Skip to content
Advertisement

Unable to create new answer in Symfony

I’m making a a app in Symfony. I get Entities Answer and Question which are related. I want to enable users to add the answer to the question but I’ve got the problem with getting question_id to AnswerEntity. Here it what I came up with: Answer Controller

<?php
/**
 * Answer Controller
 */

namespace AppController;

use AppEntityAnswer;
use AppEntityQuestion;
use AppFormAnswerType;
use AppRepositoryAnswerRepository;
use AppRepositoryQuestionRepository;
use SymfonyComponentFormExtensionCoreTypeFormType;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use KnpComponentPagerPaginatorInterface;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyFlexPackageFilter;
use SymfonyComponentRoutingAnnotationRoute;

/**
 * Class AnswerController.
 *
 * @Route("/answer")
 */

class AnswerController extends AbstractController
{
    private $answerRepository;
    private $answer;
    private $paginator;

    /**
     * AnswerController constructor
     *
     * @param AppRepositoryAnswerRepository $answerRepository Answer Repository
     * @param KnpComponentPagerPaginatorInterface $paginator
     */
    public function __construct(AnswerRepository $answerRepository, PaginatorInterface $paginator)
    {
        $this->answerRepository = $answerRepository;
        $this->paginator = $paginator;
    }

    /**
     * Index action.
     *
     * @param SymfonyComponentHttpFoundationRequest $request        HTTP request
     * @return SymfonyComponentHttpFoundationResponse               HTTP response
     *
     * @Route(
     *     "/",
     *     methods={"GET"},
     *     name="answer_index",
     * )
     */
    public function index(Request $request, PaginatorInterface $paginator, AnswerRepository $answerRepository): Response
    {
        $pagination = $paginator->paginate(
            $answerRepository->queryAll(),
            $request->query->getInt('page', 1),
            AnswerRepository::PAGINATOR_ITEMS_PER_PAGE
        );

        return $this->render(
            'answer/index.html.twig',
            ['pagination' => $pagination]
        );
    }
    /**
     * Create action.
     *
     * @param SymfonyComponentHttpFoundationRequest $request HTTP request
     *
     * @param AppRepositoryAnswerRepository $answerRepository Answer repository
     *
     * @return SymfonyComponentHttpFoundationResponse HTTP response
     *
     * @throws DoctrineORMORMException
     * @throws DoctrineORMOptimisticLockException
     *
     * @Route(
     *     "/create",
     *     methods={"GET", "POST"},
     *     name="answer_create",
     * )
     */
    public function create(Request $request, AnswerRepository $answerRepository): Response
    {
        $answer = new Answer();
        $form = $this->createForm(AnswerType::class, $answer);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $answer->setQuestion($this->getQuestion());
            $answerRepository->save($answer);

            $this->addFlash('success', 'answer_created_successfully');

            return $this->redirectToRoute('answer_index');
        }

        return $this->render(
            'answer/create.html.twig',
            ['form' => $form->createView()]
        );
    }
}

AnswerForm:

<?php
/**
 * Answer type.
 */

namespace AppForm;

use AppEntityAnswer;
use SymfonyBridgeDoctrineFormTypeEntityType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormExtensionCoreTypeEmailType;
use SymfonyComponentFormExtensionCoreTypeHiddenType;
use SymfonyComponentFormExtensionCoreTypeTextType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;

/**
 * Class AnswerType.
 */
class AnswerType extends AbstractType
{
    /**
     * Builds the form.
     *
     * This method is called for each type in the hierarchy starting from the
     * top most type. Type extensions can further modify the form.
     *
     * @see FormTypeExtensionInterface::buildForm()
     *
     * @param SymfonyComponentFormFormBuilderInterface $builder The form builder
     * @param array                                        $options The options
     */
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add(
            'AnswerText',
            TextType::class,
            [
                'label' => 'label_answertext',
                'required' => true,
                'attr' => ['max_length' => 200],
            ]
        );

        $builder->add(
            'Nick',
            TextType::class,
            [
                'label' => 'label_nick',
                'required' => true,
                'attr' => ['max_length' => 64],
            ]
        );
        $builder->add(
            'Email',
            EmailType::class,
            [
                'label' => 'label_email',
                'required' => true,
                'attr' => ['max_length' => 64],
            ]
        );

        $builder->add('is_best', HiddenType::class, [
            'data' => '0',
        ]);

    }

    /**
     * Configures the options for this type.
     *
     * @param SymfonyComponentOptionsResolverOptionsResolver $resolver The resolver for the options
     */
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults(['data_class' => Answer::class]);
    }

    /**
     * Returns the prefix of the template block name for this type.
     *
     * The block prefix defaults to the underscored short class name with
     * the "Type" suffix removed (e.g. "UserProfileType" => "user_profile").
     *
     * @return string The prefix of the template block name
     */
    public function getBlockPrefix(): string
    {
        return 'answer';
    }
}

and AnswerEntity

<?php

namespace AppEntity;

use AppRepositoryAnswerRepository;
use DoctrineORMMapping as ORM;

/**
 * @ORMEntity(repositoryClass=AnswerRepository::class)
 * @ORMTable(name="answers")
 */
class Answer
{
    /**
     * @ORMId
     * @ORMGeneratedValue
     * @ORMColumn(type="integer")
     */
    private $id;

    /**
     * @ORMColumn(type="string", length=200)
     */
    private $answer_text;

    /**
     * @ORMManyToOne(targetEntity=Question::class, inversedBy="answer")
     * @ORMJoinColumn(nullable=false)
     */
    private $question;

    /**
     * @ORMColumn(type="string", length=64)
     */
    private $email;

    /**
     * @ORMColumn(type="string", length=64)
     */
    private $Nick;

    /**
     * @ORMColumn(type="integer")
     */
    private $isBest;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getAnswerText(): ?string
    {
        return $this->answer_text;
    }

    public function setAnswerText(string $answer_text): void
    {
        $this->answer_text = $answer_text;
    }

    public function getQuestion(): ?Question
    {
        return $this->question;
    }

    public function setQuestion(?Question $question): void
    {
        $this->question = $question;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;

        return $this;
    }

    public function getNick(): ?string
    {
        return $this->Nick;
    }

    public function setNick(string $Nick): self
    {
        $this->Nick = $Nick;

        return $this;
    }

    public function getIsBest(): ?int
    {
        return $this->isBest;
    }

    public function setIsBest(int $isBest): self
    {
        $this->isBest = $isBest;

        return $this;
    }
}

The error is: [enter image description here][1] [1]: https://i.stack.imgur.com/fYGpo.png

but I have a function getQuestion in AnswerEntity so why doesn’t it read that? It read the function setQuestion which is the same Entity.

Is there any chance to do it another way?

Also I’m adding part of my question template code where I get to create_answer

            <a href="{{ url('answer_create', {id: questions.id}) }}" title="{{ 'create_answer'|trans }}">
                {{ 'create_answer'|trans }}
            </a>

Advertisement

Answer

Why don’t you have the questionId in your route. I think it’s a mandatory data to know which question the users tries to answer to.

With a requestParam id in the route and a method param typed Question the ParamConverter can inject the right question in your controller method

/**
    *  ...
     * @Route(
     *     "/create/{id}",
     *     methods={"GET", "POST"},
     *     name="answer_create",
     * )
     */
    public function create(Request $request, AnswerRepository $answerRepository, Question $question): Response
    {
        $answer = new Answer();
        $answer->setQuestion($question);
        // ....

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement