Symfony 6 App\Entity\Question object not found by the #ParamConverter annotation - symfony

I try to make answers for question.
Here is my AnswerController:
#[Route('/{slug}/{name}/answer/{question}', name: 'answer_question')]
public function answer(Question $q, QuestionRepository $questionRepository, string $question, Request $request, EntityManagerInterface $entityManager, string $slug, string $name, AnswerRepository $answerRepository): Response
{
$questions = $questionRepository->findOneBySlug($question);
$answers = $answerRepository->findAnswers($question);
$form = $this->createForm(AnswerType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$answer = new Answer();
$answer->setContent($data->getContent());
$answer->setAnsweredAt(new \DateTime);
$answer->setQuestion($q);
$entityManager->persist($answer);
$entityManager->flush();
return $this->redirectToRoute('show_question', [
'slug' => $slug,
'name' => $name,
'question' => $question,
]);
}
return $this->render('answer/index.html.twig', [
'questions' => $questions,
'answers' => $answers,
'answer' => $form->createView(),
]);
}
I have problem with
App\Entity\Question object not found by the #ParamConverter annotation
EDIT:
Still I have a little problem with wildcards,
for example when i put address "/audi-a3/8v/answer/question" it's ok, but when i put "/audi-a4/8v/answer/question" ( there isn't audi-a4 with model 8v but this address gives me correct page for "8V" model. It doesn't match ).
Can someone explain me how to do it right?

I did some changes in AnswerController and now it's working.
Set ParamConverter manually.
#[Route('/{car}/{name}/answer/{slug}', name: 'answer_question')]
#[ParamConverter('question', class: Question::class, options: ['mapping' => ['slug' => 'slug']])]
public function answer(Question $question, QuestionRepository $questionRepository, Request $request, EntityManagerInterface $entityManager, string $slug, string $name, string $car, AnswerRepository $answerRepository): Response
{
$questions = $questionRepository->findOneBySlug($slug);
$answers = $answerRepository->findAnswers($slug);
$form = $this->createForm(AnswerType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$answer = new Answer();
$answer->setContent($data->getContent());
$answer->setAnsweredAt(new \DateTime);
$answer->setQuestion($question);
$entityManager->persist($answer);
$entityManager->flush();
return $this->redirectToRoute('show_question', [
'slug' => $slug,
'name' => $name,
'car' => $car,
]);
}
return $this->render('answer/index.html.twig', [
'questions' => $questions,
'answers' => $answers,
'answer' => $form->createView(),
]);
}

Related

Retrieve posts created by a specific Symfony user

I have a $ type boolean property, I need to differentiate my two types of posts I am trying to retrieve posts of type = true, (which are recipes) of a specific user for the user profile page.
/**
* #Route("/profil/{id}", name="profil", methods={"GET","POST"})
*
*/
public function index(User $user): Response
{
$em = $this->getDoctrine()->getManager();
$publications = $em->getRepository('App:Publication')->findBy(
array('users' => $user->getId()),
array('created_at' => 'Desc')
);
****// list the publication of recipes
$recette = $em->getRepository('App:Publication')->findBy(['type'=>true],['created_at' => 'desc']);****
// recuperar las 3 ultimas recetas para el sidebar rigth
$lastRecettes = $this->getDoctrine()->getRepository(Publication::class)->lastXRecette(4);
// lister les 9 dernières recettes
$recette = $this->getDoctrine()->getRepository(Publication::class)->lastPRecette(9);
return $this->render('profil/index.html.twig', [
'publications' => $publications,
'recettes' => $recette,
'user' => $user,
'lastRecettes' => $lastRecettes,
]);
}
the highlighted part allows me to retrieve all the recipes but I don't know how to add the user I tried this but it is not correct:
$recette = $em->getRepository('App:Publication')->findBy(['type'=>true], ['users' => $user->getId()],['created_at' => 'desc']);
Yes, as proposed (but maybe in a confused way) by #mustapha-ghlissi you have to include the test on your user on the first argument of the findBy method like this :
$recette = $em->getRepository('App:Publication')->findBy(['type' => true, 'users' => $user->getId()],['created_at' => 'desc']);
PublicationRepository.php
public function getRecettesUser(User $user)
{
return $this->createQueryBuilder('p')
->andWhere('p.users = :user')
->andWhere('p.type = :type')
->setParameter('user', $user)
->setParameter('type', true)
->getQuery()
->getResult();
}
create a folder src/Manager/PublicationManager.php
use App\Entity\Publication;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
class PublicationManager
{
protected $em;
public function __construct(EntityManagerInterface $entityManager)
{
$this->em = $entityManager;
}
public function getRecetteByUser(User $user)
{
return $this->em->getRepository(Publication::class)->findBy(
['type' => true, 'users' => $user->getId()],['created_at' => 'desc']
);
}
}
My Controller
/**
* #Route("/profil/{id}", name="profil", methods={"GET","POST"})
*
*/
public function index(User $user, PublicationManager $publicationManager): Response
{
$em = $this->getDoctrine()->getManager();
$publications = $em->getRepository('App:Publication')->findBy(
array('users' => $user->getId()),
array('created_at' => 'Desc')
);
// recuperer les 3 dernier recettes pour le sidebar right
$lastRecettes = $this->getDoctrine()->getRepository(Publication::class)
->lastXRecette(4);
return $this->render('profil/index.html.twig', [
'publications' => $publications,
'recettes' => $publicationManager->getRecetteByUser($user),
'lastRecettes' => $lastRecettes,
]);
}
I'm not sure if I well understood your problem
But may your code should look like this :
/**
* #Route("/profil/{id}", name="profil", methods={"GET","POST"})
*
*/
public function index(User $user): Response
{
$em = $this->getDoctrine()->getManager();
// First type
$truePublications = $em->getRepository(Publication::class)->findBy(
array('user' => $user->getId(), 'type' => true),
array('created_at' => 'DESC'),
);
// Second type
$falsePublications = $em->getRepository(Publication::class)->findBy(
array('user' => $user->getId(), 'type' => false),
array('created_at' => 'DESC'),
);
// recuperar las 3 ultimas recetas para el sidebar rigth
$lastRecettes = $this->getDoctrine()->getRepository(Publication::class)->lastXRecette(3);
// lister les 9 dernières recettes
$recette = $this->getDoctrine()->getRepository(Publication::class)->lastPRecette(9);
return $this->render('profil/index.html.twig', [
'trueTypePublications' => $truePublications,
'falseTypePublications' => $falsePublications,
'recettes' => $recette,
'user' => $user,
'lastRecettes' => $lastRecettes,
]);
}

Prevent EntityManager for one entity but not the other

so I have a controller that essentially submits an edit of a category for approval by sending an email to the admin. This was fine before I decided to add in an actions table to store action history (e.g. category: edit).
The problem that's arose is that, by using entityManager to add data to the actions table, it's automatically updating the category entity due to the Event Watcher.
I tried a google and couldn't find anything on setting entityManager to one entity only.
This is my current controller:
<?php
namespace App\Controller\Category\Edit;
use App\Entity\Action;
use App\Entity\Category;
use App\Entity\User;
use App\Form\Category\EditCategoryType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class EditController extends Controller
{
public function edit($id, Request $request, \Swift_Mailer $mailer)
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
$category = $this->getDoctrine()->getRepository(Category::class)->find($id);
$categoryGuru = $category->getGuru();
$guruName = $categoryGuru->getUsername();
$category->setGuru($categoryGuru);
$form = $this->createForm(EditCategoryType::class, $category);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$formData = $form->getData();
$name = $formData->getName();
$description = $formData->getDescription();
$newGuruId = $form['guru']->getData();
$newGuru = $this->getDoctrine()->getRepository(User::class)->find($newGuruId);
$actionId = $this->setAction();
$approveUrl = $category->getId();
$approveUrl .= '/'. $actionId;
$approveUrl .= '/'. $name;
$approveUrl .= '/'. $description;
$approveUrl .= '/'. $newGuru->getId();
$message = (new \Swift_Message('Category Edit Request - '. $category->getName()))
->setFrom('some#email.com')
->setTo('another#email.co.uk')
->setBody(
$this->renderView(
'emails/category/edit-request.html.twig',
array(
'category' => $category->getName(),
'category_new_name' => $name,
'description' => $category->getDescription(),
'category_new_description' => $description,
'guru' => $guruName,
'category_new_guru' => $newGuru->getUsername(),
'category_new_guru_id' => $newGuru->getId(),
'category_id' => $category->getId(),
'category_author' => $this->getUser()->getUsername(),
'approve_url' => $approveUrl,
'action_id' => $actionId
)
),
'text/html'
);
$mailer->send($message);
$this->addFlash('success', 'Category Edit Submitted for Review.');
return $this->redirectToRoute('category_list');
}
return $this->render(
'category/edit.html.twig',
array('form' => $form->createView(), 'category' => $category, 'guru' => $categoryGuru)
);
}
# this was originally a part of the above controller
# tried separating to see if it would work - didn't
public function setAction()
{
$action = new Action();
$entityManager = $this->getDoctrine()->getManager();
# set action data
$action->setDate(new \DateTime());
$action->setUserId($this->getUser()->getId());
$action->setDescription($this->getUser()->getUsername(). ' has edited a category');
$action->setStatus('pending');
$action->setType('Category: edit');
$entityManager->persist($action);
$entityManager->flush();
return $action->getId();
}
}
The answer I came to was, don't. Use the Repository class:
CategoryRepository.php
public function addAction($userId, $description, $status, $type)
{
$entityManager = $this->getEntityManager();
$connection = $entityManager->getConnection();
$date = date('Y-m-d H:i:s', strtotime('now'));
$connection->insert(
'action',
array(
'type' => $type,
'user_id' => $userId,
'date' => $date,
'description' => $description,
'status' => $status
)
);
return $entityManager->getConnection()->lastInsertId();
}
then call it in the controller - no longer classing entityManager issues.

Symfony and Doctrine - displaying data from database in controller method

This is my code. I want to set default value from database in the form. I want to set value in form which i create in this method.
public function updateBlogAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$data = $em->getRepository('AppBundle:Blog\Post')->find($id);
$blogs = new Post();
$form = $this->createFormBuilder($blogs)
->add('title', TextType::class, array('attr'=>array( 'class'=>'form-control','placeholder'=>'Blog title')))
->add('description', TextareaType::class, array('attr'=>array('class'=>'form-control','placeholder'=>'Blog description')))
->add('submit',SubmitType::class, array('label'=>'Add Blog', 'attr'=> array('class'=>'btn btn-primary pull-right')))
->getForm();
$form->handleRequest($request);
if( $form->isSubmitted() && $form->isValid() ){
$data->setTitle($blogs);
$em->flush();
return $this->redirectToRoute('blog');
}
return $this->render('blog/update_blog.html.twig', array(
'form' => $form->createView()
));
}
It is as easy as
$em = $this->getDoctrine()->getManager();
$blogs= $em->getRepository('AppBundle:Blog\Post')->find($id);
$form = $this->createFormBuilder($blogs)
/* ... */

symfony2 + EntityType + queryBuilder and default top value/entry

I have an entity (Category) where the user can choice a parent (always Category) for the new/edit action where the link is the vocabolaryId field.
This is my CategoryType.
class CategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$vocId = $options['data']->getVocabularyId();
$builder
->add('name')
->add('vocabularyId',HiddenType::class,[
'data' => $vocId,
])
->add('description')
->add('weight',null,[
'label' => 'Posizione'
])
;
$builder->add('parent',EntityType::class,array(
'class' => 'AppBundle:Category',
'query_builder' => function (EntityRepository $er) use ($vocId) {
return $er->createQueryBuilder('c')
->where('c.vocabularyId = ?1')
->orderBy('c.name')
->setParameter(1,$vocId);
}
));
}
To get the list of all category that have the same vocabularyId I use the "query_builder" parameter.
When I submit the form to symfony without choice a parent (or with an empty table) it replies me with : " This value is not valid." (for the parent field).
How can I set a "null" parent ? I mean a category that have no parent.
EDIT:I have added "'required' => false," like say by Stephan Vierkant, but now I have another error: "Warning: spl_object_hash() expects parameter 1 to be object, string given"
this is my controller's newAction function:
/**
* Creates a new Category entity.
*
* #Route("/new", name="admin_category_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request, $vocId)
{
$category = new Category($vocId);
$form = $this->createForm('AppBundle\Form\CategoryType', $category);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
dump($category);
exit();
$em->persist($category);
$em->flush();
return $this->redirectToRoute('admin_category_show', array('vocId' => $vocId, 'id' => $category->getId()));
}
return $this->render('category/new.html.twig', array(
'category' => $category,
'form' => $form->createView(),
'vocId' => $vocId
));
}
Set required (docs) to false:
$builder->add('parent',EntityType::class,array(
'class' => 'AppBundle:Category',
'required' => false,
'query_builder' => function (EntityRepository $er) use ($vocId) {
return $er->createQueryBuilder('c')
->where('c.vocabularyId = ?1')
->orderBy('c.name')
->setParameter(1,$vocId);
}
));
You can set a placeholder (docs) if you don't want an empty option.

On update don't update an entity replace it

I have a Branch entity that has an Address entity, one address can be link to many other types of entities, what I want to do is when I edit the Address in the Branch entity instead of editing the address with the new data I want to create a new Address entity and attach it to the Branch, what is happening right now is that its editing the address, the problem with this is that I have other entities linked to that address.
This is my form:
class MBBranchType extends AbstractType{
protected $em;
function __construct(EntityManager $em){
$this->em = $em;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('branchName')
->add('branchCode')
->add('destiny', 'entity', array(
'class' => 'ATRBundle:Destiny',
'empty_value' => '-- Seleccione --',
'mapped' => true,
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('d')
->orderBy('d.destinyDesc', 'ASC');
}))
->add('startOperation', 'text')
->add('stopOperation', 'text', array('required' => ''))
->add('authorizationL1', 'checkbox', array('required' => ''))
->add('authorizationL2', 'checkbox', array('required' => ''))
->add('authorizationL3', 'checkbox', array('required' => ''))
->add('address', new AddressType($this->em, new Address()), array('required' => ''))
->add('active', 'checkbox', array('required' => ''));
$builder->get('startOperation')->addModelTransformer(new StringToDateTransformer());
$builder->get('stopOperation')->addModelTransformer(new StringToDateTransformer());
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MB2\ATRBundle\Entity\MBBranch'
));
}
/**
* #return string
*/
public function getName()
{
return 'mb2_atr_mb_branch';
}
}
This is my Action
public function editMBBranchAction()
{
$id = $this->request->query->get('id');
$entity = $this->em->getRepository('ATRBundle:MBBranch')->find($id);
$form = $this->createForm(new MBBranchType($this->getDoctrine()->getManager()), $entity);
$form->handleRequest($this->request);
if ($form->isValid()) {
if($entity instanceof MBBranch){
$addressEntity = $this->em->getRepository('ATRBundle:Address')->findOneBy(
array('street'=>(string)$entity->getAddress()->getStreet()
, 'exteriorNum' => $entity->getAddress()->getExteriorNum();
, 'interiorNum' => $entity->getAddress()->getInteriorNum();
, 'settlment' => $entity->getAddress()->getSettlment()
)
);
if($addressEntity instanceof \MB2\ATRBundle\Entity\Address){
$entity->setAddress($addressEntity);
}else{
$otherAddress = new Address();
$otherAddress->setStreet($entity->getAddress()->getStreet());
$otherAddress->setExteriorNum($entity->getAddress()->getExteriorNum());
$otherAddress->setInteriorNum($entity->getAddress()->getInteriorNum());
$otherAddress->setSettlment($entity->getAddress()->getSettlment());
$entity->setAddress($otherAddress);
}
$this->em->flush();
}
return $this->redirect($this->generateUrl('admin', array('action' => 'list', 'entity' => $this->entity['name'])));
}
return $this->render($this->entity['templates']['edit'], array(
'form' => $form->createView(),
'entity' => $entity,
));
}
As you can see it checks if the new Address entity exist, if it does exist it sets it on the $entity->setAddress($addressEntity);, If it does not exist it created a new Address() and sets the values, This does work, it created a new Address and saves it on the table, but for some reason it also updateing the old Address entity.
I found the solution
I added a $this->em->detach($entity->getAddress()); before attaching a new Address, please see example.
public function editMBBranchAction()
{
$id = $this->request->query->get('id');
$entity = $this->em->getRepository('ATRBundle:MBBranch')->find($id);
$form = $this->createForm(new MBBranchType($this->getDoctrine()->getManager()), $entity);
$form->handleRequest($this->request);
if ($form->isValid()) {
if($entity instanceof MBBranch){
$this->em->detach($entity->getAddress());
$addressEntity = $this->em->getRepository('ATRBundle:Address')->findOneBy(
array('street'=>(string)$entity->getAddress()->getStreet()
, 'exteriorNum' => $entity->getAddress()->getExteriorNum();
, 'interiorNum' => $entity->getAddress()->getInteriorNum();
, 'settlment' => $entity->getAddress()->getSettlment()
)
);
if($addressEntity instanceof \MB2\ATRBundle\Entity\Address){
$entity->setAddress($addressEntity);
}else{
$otherAddress = new Address();
$otherAddress->setStreet($entity->getAddress()->getStreet());
$otherAddress->setExteriorNum($entity->getAddress()->getExteriorNum());
$otherAddress->setInteriorNum($entity->getAddress()->getInteriorNum());
$otherAddress->setSettlment($entity->getAddress()->getSettlment());
$entity->setAddress($otherAddress);
}
$this->em->flush();
}
return $this->redirect($this->generateUrl('admin', array('action' => 'list', 'entity' => $this->entity['name'])));
}
return $this->render($this->entity['templates']['edit'], array(
'form' => $form->createView(),
'entity' => $entity,
));
}

Resources