Budujemy formularz dla naszej relacji. Kontynuacja lekcji poprzednich. Do dzieła.

Ok, utwórzmy formularz komendą:

symfony console make:form

Nazwa CommentType, klasa Comment. Teraz przechodzimy i usuwamy pole post:

class CommentType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('content');
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Comment::class,
        ]);
    }
}

Post będziemy dodawać poprzez route i auto-wiring (to jest wnioskować po tym, dodawać metodą entity setPost i zapisywać entity managerem).

Ok, tworzymy comment.html.twig:

{% extends 'base.html.twig' %}

{% block title %}Post - Add Comment{% endblock %}



{% block body %}
   <h1>{{ post.title }}</h1>
   <p>{{post.content}} </p>

  {{ form_start(form) }}
  <div>{{ form_errors(form)}}</div>

  <div>
    {{ form_label(form.content, 'Please enter the comment') }}
    {{ form_widget(form.content) }}
    {{ form_errors(form.content) }}
  </div>

  <div>
    <button type="submit">Add comment!</button>
  </div>
  {{ form_end(form) }}
{% endblock %}

Jak widać, będziemy musieli przekazać post oraz form. Dobra, zabieramy się za metodę w micro post controller:

#[Route('/micro_post/{post}/comment', name: 'app_micro_post_comment')]
    public function addComment(MicroPost $post, Request $request, EntityManagerInterface $entityManager): Response
    {
        $form = $this->createForm(CommentType::class, new Comment());
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $comment = $form->getData();
            $comment->setPost($post);
            $entityManager->persist($comment);
            $entityManager->flush();

            
            $this->addFlash('success', 'Your comment have been updated.');

            return $this->redirectToRoute(
                'app_micro_post_show',
                ['post' => $post->getId()]
            );
            
        }

     return $this->render(
            'micro_post/comment.html.twig',
            [
                'form' => $form,
                'post' => $post
            ]
        );
    }

Wyjaśnienie:

  • Stosujemy znany nam auto-wiring (route model binding mówiąc językiem Laravela) aby zamienić nazwę id z route na entity pod nazwą $post
  • Request będzie potrzebny do przeprocesowania formularza
  • EntityManager jest potrzebny bo zapisujemy do bazy danych
  • Kontroler ma dziedziczoną metodę createForm
  • Tworzymy formularz w oparciu o klasę CommentType oraz nowy obiekt Comment (Entity) bo ma to być formularz dodawania nowego obiektu
  • Robimy handleReqest, to nie Laravel, więc często tutaj mamy taki odpowiednik Route::match(’post”get’) a w zasadzie to Route::any jakby się czepiać szczegółów
  • W bloku if mamy co jeśli form został wysłany i przeszedł walidację
  • Tworzymy komentarz, ustawiamy post, entity manager robi persist i flush
  • Robimy flash message dziedziczoną metodą kontrolera addFlash
  • Zwracamy redirect z parametrem post, bo app_micro_post_show używa auto-wiring z taką nazwą właśnie
  • Post posiada metodę getId, którą bierzemy ID, bo takie wartości przyjmuje parametr post (auto wiring)
  • Jeżeli jesteśmy w „get” a nie „post” (poza blokiem if) to trzeba renderować template przekazując utworzony formularz oraz post, który mamy dzięki auto-wiring

Wiem, że jak to się czyta, to wygląda strasznie, w dodatku sama logika też może na pierwszy rzut oka być lekko nieintuicyjna, ale jeżeli solidnie przerobiliśmy poprzednie ćwiczenia, to wszystko powinno być dla nas jasne i oczywiste a moje gadanie powyżej to coś, co przelecimy okiem i zastanowimy się po co w ogóle takie oczywistości tak tłumaczyć.

Jeżeli nie – albo musimy przerobić materiał raz jeszcze, albo zacząć od łatwiejszego frameworka (Laravel, własny framework) bo Symfony jest jakie jest, niektórzy mogą uznać, że trudne.