Skip to content

update/delete verb routes aren't resolved #1510

@Treggats

Description

@Treggats

Tempest version

1.6.0

PHP version

8.4

Operating system

macOS

Description

This is kinda related to #856

I am creating a CRUD application, to better understand how Tempest would work in a actual application.

In line with Tempest examples / tests I created a application to manage books, authors and book chapters.
Creating, listing goes well, however when I want to edit or delete a record I run into issues. The route I want to use doesn't resolve. This route is marked with the #[Post(..)] or #{Delete) attribute.

Steps to reproduce

Example implementation
I think this all that is needed.

edit.view.php
<form action="/books/{{ $book->id }}" method="post">
    <x-csrf-token />
    <input type="hidden" name="_method" value="PUT" />
    <h1 class="text-balance text-5xl font-semibold tracking-tight text-gray-800 sm:text-7xl">
        Edit Book
    </h1>
    <p class="mt-8 text-pretty text-lg font-medium text-gray-500 sm:text-xl/8">
        <input type="text" name="title" value="{{ $originalValues['title'] ?? ($book?->title ?? '') }}" placeholder="Title" class="border placeholder:px-2 px-2" />
        <div :if="isset($errors['title'])" class="text-red-600 text-sm mt-1">
            <div :foreach="$errors['title'] as $error">
                {{ $error->message() }}
            </div>
        </div>
    </p>
    <p class="mt-8 text-pretty text-lg font-medium text-gray-500 sm:text-xl/8">
        <select name="authorId" id="authorId" class="border px-2 py-1">
            <option value="">Select Author</option>
            <option :foreach="$this->authors as $author" :value="$author->id" :selected="($originalValues['authorId'] ?? ($book?->author?->id ?? '')) == $author->id">
                {{ $author->name }}
            </option>
        </select>
        <div :if="isset($errors['authorId'])" class="text-red-600 text-sm mt-1">
            <div :foreach="$errors['authorId'] as $error">
                {{ $error->message() }}
            </div>
        </div>
    </p>
    <p class="mt-8 text-pretty text-lg font-medium text-gray-500 sm:text-xl/8">
        <input type="submit" value="Update" class="bg-blue-500 text-white px-4 py-0.5 rounded-lg" />
    </p>
</form>
BookController::edit
#[Get('/books/{bookId}/edit')]
public function edit(int $bookId): View|Redirect
{
    $book = Book::find(id: $bookId)
        ->with('author.publisher')
        ->first();

    if ($book === null) {
        return new Redirect('/');
    }

    // Get validation errors and original values from session with null safety
    $sessionErrors = $this->session->get(Session::VALIDATION_ERRORS, []);
    $sessionOriginalValues = $this->session->get(Session::ORIGINAL_VALUES, []);

    // Ensure session data is always an array
    $errors = is_array($sessionErrors) ? $sessionErrors : [];
    $originalValues = is_array($sessionOriginalValues) ? $sessionOriginalValues : [];

    return view('Views/Books/edit.view.php',
        title: 'Edit Book',
        book: $book,
        authors: Author::select()->all() ?? [],
        publishers: Publisher::select()->all() ?? [],
        errors: $errors,
        originalValues: $originalValues
    );
}
BookController::update
#[Put('/books/{bookId}')]
public function update(int $bookId, UpdateBookRequest $request): Redirect
{
    $book = Book::find(id: $bookId)->first();

    // Ensure book exists
    if ($book === null) {
        return new Redirect('/');
    }

    $author = Author::find(id: $request->authorId)->first();

    // Ensure author exists
    if ($author === null) {
        // Author not found - redirect back to edit form
        return new Redirect('/books/' . $bookId . '/edit');
    }

    $book->title = $request->title;
    $book->author = $author;
    $book->save();

    return new Redirect('/books/' . $bookId);
}

Steps:

  1. create a book record, with dependent records
  2. visit the edit route
  3. update something (without triggering a validation error)
  4. submit the form

Expectation
I expected the following things to happen upon submitting

  1. I would be redirected to the show book page/route
  2. the database record would have been updated

Result
The browser returns a 404 (outside of the Tempest application)


What I've worked out so far is that when resolving the request from the form it looks for a POST route, ignoring the method="PUT" form element.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions