I'm creating a little QA app. I've got Entity Answer which is related to User and Question. I am trying to make a creating form for Answer. I am able to show the list of all the answers, but when it comes to creating a new, there is a problem.
the error
Here is my AnswerEntity code:
namespace App\Entity;
use App\Repository\AnswerRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=AnswerRepository::class)
* #ORM\Table(name="answers")
*/
class Answer
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=200)
*/
private $answer_text;
/**
* #ORM\ManyToOne(targetEntity=Question::class, inversedBy="answer")
* #ORM\JoinColumn(nullable=false)
*/
private $question;
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;
}
}
and the code for AnswerForm
/**
* Answer type.
*/
namespace App\Form;
use App\Entity\Answer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* 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 \Symfony\Component\Form\FormBuilderInterface $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],
]
);
}
/**
* Configures the options for this type.
*
* #param \Symfony\Component\OptionsResolver\OptionsResolver $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 also Answer Controller
/**
* Answer Controller
*/
namespace App\Controller;
use App\Entity\Answer;
use App\Entity\Question;
use App\Form\AnswerType;
use App\Repository\AnswerRepository;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Flex\PackageFilter;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class AnswerController.
*
* #Route("/answer")
*/
class AnswerController extends AbstractController
{
private $answerRepository;
private $answer;
private $paginator;
/**
* AnswerController constructor
*
* #param \App\Repository\AnswerRepository $answerRepository Answer Repository
* #param \Knp\Component\Pager\PaginatorInterface $paginator
*/
public function __construct(AnswerRepository $answerRepository, PaginatorInterface $paginator)
{
$this->answerRepository = $answerRepository;
$this->paginator = $paginator;
}
/**
* Index action.
*
* #param \Symfony\Component\HttpFoundation\Request $request HTTP request
* #return \Symfony\Component\HttpFoundation\Response 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 \Symfony\Component\HttpFoundation\Request $request HTTP request
*
* #param \App\Repository\AnswerRepository $answerRepository Answer repository
* #param \App\Entity\Answer $answer Answer Entity
*
* #return \Symfony\Component\HttpFoundation\Response HTTP response
*
* #throws \Doctrine\ORM\ORMException
* #throws \Doctrine\ORM\OptimisticLockException
*
* #Route(
* "/create",
* methods={"GET", "POST"},
* name="answer_create",
* )
*/
public function create(Request $request, AnswerRepository $answerRepository, Answer $answer): Response
{
$answer = new Answer();
$form = $this->createForm(AnswerType::class, $answer);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$answerRepository->save($answer);
$this->addFlash('success', 'answer_created_successfully');
return $this->redirectToRoute('question_index');
}
return $this->render(
'answer/create.html.twig',
['form' => $form->createView()]
);
}
}
And also, the questions is.., how to route answer/create to make it the answer to the question? I mean, I've localhost/question/{questionid} and I want to create the question here.
Thanks for your help!
Your error is a ParamConverter error. In your controller you ask symfony to give you an Answer $answer but it cannot provide it because there's no way to do it. you don't need this param in your controller's method.
Also I doubt your AnswerType will work since your property is named answer_text and your field is named AnserText. They must match.
Related
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 App\Controller;
use App\Entity\Answer;
use App\Entity\Question;
use App\Form\AnswerType;
use App\Repository\AnswerRepository;
use App\Repository\QuestionRepository;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Flex\PackageFilter;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class AnswerController.
*
* #Route("/answer")
*/
class AnswerController extends AbstractController
{
private $answerRepository;
private $answer;
private $paginator;
/**
* AnswerController constructor
*
* #param \App\Repository\AnswerRepository $answerRepository Answer Repository
* #param \Knp\Component\Pager\PaginatorInterface $paginator
*/
public function __construct(AnswerRepository $answerRepository, PaginatorInterface $paginator)
{
$this->answerRepository = $answerRepository;
$this->paginator = $paginator;
}
/**
* Index action.
*
* #param \Symfony\Component\HttpFoundation\Request $request HTTP request
* #return \Symfony\Component\HttpFoundation\Response 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 \Symfony\Component\HttpFoundation\Request $request HTTP request
*
* #param \App\Repository\AnswerRepository $answerRepository Answer repository
*
* #return \Symfony\Component\HttpFoundation\Response HTTP response
*
* #throws \Doctrine\ORM\ORMException
* #throws \Doctrine\ORM\OptimisticLockException
*
* #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 App\Form;
use App\Entity\Answer;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* 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 \Symfony\Component\Form\FormBuilderInterface $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 \Symfony\Component\OptionsResolver\OptionsResolver $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 App\Entity;
use App\Repository\AnswerRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=AnswerRepository::class)
* #ORM\Table(name="answers")
*/
class Answer
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=200)
*/
private $answer_text;
/**
* #ORM\ManyToOne(targetEntity=Question::class, inversedBy="answer")
* #ORM\JoinColumn(nullable=false)
*/
private $question;
/**
* #ORM\Column(type="string", length=64)
*/
private $email;
/**
* #ORM\Column(type="string", length=64)
*/
private $Nick;
/**
* #ORM\Column(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>
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);
// ....
The answer is in the error image you posted, there is no $this->getQuestion() in a controller unless you create that function.
You can get the question entity by any identifier with Doctrine
$question = this->getDoctrine()->getRepository(Question::class)->find($question_id);
and then you can set the question relation in your $answer object
$answer->setQuestion($question);
I'm trying to make an easy listAction to retrieve data from Doctrine but I got this error:
Attempted to load class "ProductRepository" from namespace "AppBundle\Entity".
Did you forget a "use" statement for another namespace?
This come out when i call the route ex.com/list that must
to list the data coming from product table
Controller: (src/AppBundle/Controller)
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\MessageSelector;
use AppBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;
new Translator('it', new MessageSelector(), __DIR__.'/../cache');
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
* #param Request $request
* #return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction(Request $request)
{
$request->getLocale();
$request->setLocale('it');
return $this->render('default/index.html.twig', [
'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..'),
]);
}
/**
*
* #Route("list", name="list")
* #return Response
*
*/
public function listAction()
{
return $product = $this->getDoctrine()
->getRepository('AppBundle\Entity\Product')
->findAll();
/* if (!$product) {
throw $this->createNotFoundException(
'Nessun prodotto trovato'
);
}*/
}
/**
* #Route("create",name="create")
* #return Response
*/
public function createAction()
{
$product = new Product();
$product->setName('Pippo Pluto');
$product->setPrice('19.99');
$product->setDescription('Lorem ipsum dolor');
$product->setSeller('1');
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->render('default/index.html.twig');
}
/**
* #param $id
* #Route("show/{id}",name="show/{id}")
* #return Response
*/
public function showAction($id)
{
$product = new Product();
$product = $this->getDoctrine()
->getRepository('AppBundle:Product')
->find($id);
if (!$product) {
throw $this->createNotFoundException(
'Nessun prodotto trovato per l\'id '.$id
);
}
}
}
Entity: (src/AppBundle/Entity)
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Product
*
* #ORM\Table(name="product")
* #ORM\Entity(repositoryClass="AppBundle\Entity\ProductRepository")
*/
class Product
{
/**
* #var int
*
* #ORM\Column(name="`id`", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="`name`", type="string")
*/
private $name;
/**
* #var float
*
* #ORM\Column(name="`price`", type="float")
*/
private $price;
/**
* #var string
*
* #ORM\Column(name="`description`", type="string")
*/
private $description;
/**
* #var int
*
* #ORM\Column(name="`seller`", type="integer")
*/
private $seller;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Product
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Set price
*
* #param float $price
*
* #return Product
*/
public function setPrice($price) {
$this->price = $price;
return $this;
}
/**
* Set description
*
* #param string $description
*
* #return Product
*/
public function setDescription($description) {
$this->description = $description;
return $this;
}
/**
* Set seller
*
* #param int $seller
*
* #return Product
*/
public function setSeller($seller) {
$this->seller = $seller;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Get price
*
* #return float
*/
public function getPrice()
{
return $this->price;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Get seller
*
* #return int
*/
public function getSeller()
{
return $this->seller;
}
}
I can't understand what I'm missing to use. thanks.
That error "Attempted to load class "ProductRepository" from namespace "AppBundle\Entity" is generated because you, by mistake I guess, renamed the repositoryClass in your AppBundle/Entity/Product class.
So instead of * #ORM\Entity(repositoryClass="AppBundle\Entity\ProductRepository") you should have * #ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository"), which means that the repository classes are meant to be located into Repository directory and not Entity.
And a controller action method must always return a response, or a redirect, etc.
And, even though your way works too, you would always want to call the findAll() method on a repository object, and not an entity one. So, again,
in your listAction instead of ->getRepository('AppBundle\Entity\Product')->findAll() needs to be ->getRepository('AppBundle:Product')->findAll()
I might be wrong, but i think that is becouse You dont render anything. Try this code: $product = $this->getDoctrine() ->getRepository('AppBundle\Entity\Product') ->findAll(); return $this->render('default/index.html.twig',['product' => $product]);
I tried to find an answer for my question but it was unsuccessful. I'm using Symfony (Ive been using it 2 months) and I have a problem when I want to make many to many relationship.
I have homes and I have services. One home can have a lot of services and one service can have a lot of homes. Everything is ok and I understand the way many to many works with the doctrine, i persisted all values before flush in my controller, but i always get this message:
An exception occurred while executing 'INSERT INTO homess_services (home_id, service_id) VALUES (?, ?)' with params [25, 7]:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '25' for key 'home_id'
My codes are (home entity):
<?php
namespace Filip\SymfonyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Filip\SymfonyBundle\FilipSymfonyBundle;
/**
* Home
*
* #ORM\Table(name="homes")
* #ORM\Entity
*
*
*/
class Home
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Service", inversedBy="homes")
* #ORM\JoinTable(name="homess_services")
*/
protected $services;
public function __construct() {
$this->photos = new ArrayCollection();
$this->services = new ArrayCollection();
}
/**
* Renders a publication as a string
*
* #return string
*/
public function __toString (){
return $this->getName();
}
/**
* Add services
*
* #param \Filip\SymfonyBundle\Entity\Service $services
* #return Home
*/
public function addService(\Filip\SymfonyBundle\Entity\Service $services)
{
$this->services[] = $services;
return $this;
}
/**
* Remove services
*
* #param \Filip\SymfonyBundle\Entity\Service $services
*/
public function removeService(\Filip\SymfonyBundle\Entity\Service $services)
{
$this->services->removeElement($services);
}
/**
* Get services
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getServices()
{
return $this->services;
}
Service entity:
<?php
namespace Filip\SymfonyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Filip\SymfonyBundle\FilipSymfonyBundle;
/**
* Service
*
* #ORM\Table("services")
* #ORM\Entity
*/
class Service
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Home", mappedBy="services")
*/
protected $homes;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM
\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="category", type="string", length=45)
*/
private $category;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=45)
*/
private $name;
/**
* Renders a service as a string
*
* #return string
*/
/**
* Get id
*
6
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set category
*
* #param string $category
* #return Service
*/
public function setCategory($category)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return string
*/
public function getCategory()
{
return $this->category;
}
/**
* Set name
*
* #param string $name
* #return Service
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
public function __construct()
{
$this->homes = new ArrayCollection();
}
/**
* Add homes
*
* #param \Filip\SymfonyBundle\Entity\Home $homes
* #return Service
*/
public function addHome(\Filip\SymfonyBundle\Entity\Home $homes)
{
$this->homes[] = $homes;
return $this;
}
/**
* Remove homes
*
* #param \Filip\SymfonyBundle\Entity\Home $homes
*/
public function removeHome(\Filip\SymfonyBundle\Entity\Home $homes)
{
$this->homes->removeElement($homes);
}
/**
* Get homes
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getHomes()
{
return $this->homes;
}
}
Form(HomeType):
<?php
namespace Filip\SymfonyBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class HomeType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('city')
->add('region')
->add('phone')
->add('address')
->add('email')
->add('website')
->add('content')
->add('youtubeApi')
->add('premium')
->add('services' , 'entity' , array(
'class' => 'FilipSymfonyBundle:Service' ,
'property' => 'name' ,
'expanded' => true ,
'multiple' => true ,
));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Filip\SymfonyBundle\Entity\Home'
));
}
/**
* #return string
*/
public function getName()
{
return 'filip_symfonybundle_home';
}
}
Home controller:
/**
* Creates a new Home entity.
*
* #Route("/", name="home_create")
* #Method("POST")
* #Template("FilipSymfonyBundle:Home:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Home();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$services = $entity->getServices();
foreach($services as $service) {
$entity->addService($service);
$em->persist($service);
}
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('home_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
/**
* Creates a form to create a Home entity.
*
* #param Home $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Home $entity)
{
$form = $this->createForm(new HomeType(), $entity, array(
'action' => $this->generateUrl('home_create'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
in the if($form->isValid()) part you don't need to call the addService() method in the foreach loop as Symfony will do this for you on the handleRequest() call.
If the Home entity is at the owning side of the ManyToMany relation you don't need to persist every Service object too. So you can try to remove the whole foreach loop too.
I have read through various solutions for this issue but none seem to work. I really want to know what is at the heart of this issue. I am going to list exactly what I did since it is relatively simple and I can't understand what I am missing.
So I have created a simple database with a table person and I am trying to generate CRUD with bootstrap which I get working fine. My issue is when I try to get jquery plugin to work with autocomplete. Next thing I add a repository to handle my query and that's when I get the Symfony2 Undefined method 'findLikeFullnameArray' message. I am trying to use just annotations so if there is something wrong in my process please let me know.
Here are my commands:
Create Bundle
app/console generate:bundle --bundle-name=CompanyNameofBundle --format=annotation
Bundle namespace: Company/nameofBundle
Do you want to generate the whole directory structure: yes
Do you confirm generation: return
Confirm automatic update of your Kernel: yes
Confirm automatic update of the Routing: yes
Create entities with crud
app/console generate:bundle --bundle-name=CompanyNameofBundle --format=annotation
Bundle namespace: Company/nameofBundle
Do you want to generate the whole directory structure: yes
Do you confirm generation: return
Confirm automatic update of your Kernel: yes
Confirm automatic update of the Routing: yes
app/console doctrine:mapping:import --force CompanyNameofBundle xml
app/console doctrine:generate:entities CompanyNameofBundle
app/console generate:doctrine:crud –entity=CompanyNameofBundle:Entityname --format=annotation --with-write –no-interaction
I then create my SearchController:
namespace Company\NameofBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Company\NameofBundle\Form\JqueryType;
use Company\NameofBundle\Form\SearchType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Company\NameofBundle\Entity\Person;
/**
* Search controller.
*
* #Route("/search")
*/
class SearchController extends Controller
{
/**
* #Route("/", name="search")
* #Template()
*/
public function indexAction()
{
$form = $this->createForm(new SearchType(), null, [
'action' => '',
'method' => 'POST'
]);
return array(
'form' => $form->createView(),
);
}
/**
* #Route("/person_search", name="person_search")
* #Template()
*
* #param Request $request
*
* #return array
*/
public function searchPersonAction(Request $request)
{
$q = $request->get('term');
$em = $this->getDoctrine()->getManager();
$results = $em->getRepository('CompanyNameofBundle:Person')->findLikeFullname($q);
return array('results' => $results);
}
/**
* #Route("/person_get", name="person_get")
*
* #param $id
*
* #return Response
*/
public function getPersonAction($id)
{
$em = $this->getDoctrine()->getManager();
$book = $em->getRepository('CompanyNameofBundle:Person')->find($id);
return new Response($book->getFullname());
}
/**
* #Route("/jquery", name="jquery")
* #Template()
*/
public function jqueryAction()
{
$form = $this->createForm(new JqueryType(), null, [
'action' => '',
'method' => 'POST'
]);
return array(
'form' => $form->createView(),
);
}
/**
* #Route("/jquery_search/{phrase}", name="jquery_search")
*
* #param string $phrase
*
* #return JsonResponse
*/
public function searchJqueryAction($phrase)
{
$em = $this->getDoctrine()->getManager();
$results = $em->getRepository('CompanyNameofBundle:Person')->findLikeFullnameArray($phrase);
return new JsonResponse($results);
}
}
Person Entity:
<?php
namespace Company\NameofBundle\Person;
use Doctrine\ORM\Mapping as ORM;
/**
* Person
* #ORM\Table()
* #ORM\Entity(repositoryClass="Company\NameofBundle\Entity\Repository\PersonRepository")
*/
class Person
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="fullname", type="string", length=255)
*/
private $fullname;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=255)
*/
private $email;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set fullname
*
* #param string $fullname
* #return Person
*/
public function setFullname($fullname)
{
$this->fullname = $fullname;
return $this;
}
/**
* Get fullname
*
* #return string
*/
public function getFullname()
{
return $this->fullname;
}
/**
* Set email
*
* #param string $email
* #return Person
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
}
Lastly PersonRepository
<?php
namespace Company\NameofBundle\Entity\Repository;
use Doctrine\ORM\EntityRepository;
class PersonRepository extends EntityRepository
{
public function findLikeFullnameArray($fullname)
{
return $this->createQueryBuilder('person_repository')
->where('person_repository.fullname LIKE :name')
->setParameter('name', '%' . $fullname . '%')
->getQuery()
->getArrayResult();
}
}
In just in case here is my app/config/routing.yml
company_nameofbundle:
resource: "#CompanyNameofBundle/Controller/"
type: annotation
prefix: /
Thanks in advance!
In a first time, you should have a look on the documentation to have a repository like this :
http://symfony.com/doc/current/book/doctrine.html
// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="AppBundle\Entity\ProductRepository")
*/
class Product
{
//...
}
In a second time, you have to check in case of xml format you have put
<entity name="Acme\StoreBundle\Entity\Product" repository-class="Acme\StoreBundle\Entity\ProductRepository">
You cannot have a mix of annotation, xml or yml format to shape an entity in Symfony 2, remove all the unnecessary files.
I'm trying to learn Symfony, and I found it don't access the doctrine from the entity.
I created an Entity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Facility
*
* #ORM\Table()
* #ORM\Entity
* #ORM\Entity(repositoryClass="AppBundle\Entity\FacilityRepository")
*/
class Facility
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="label", type="string", length=200)
*/
private $label;
/**
* #ORM\OneToOne(targetEntity="Facility")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
private $parent;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set label
*
* #param string $label
* #return Facility
*/
public function setLabel($label)
{
$this->label = $label;
return $this;
}
/**
* Get label
*
* #return string
*/
public function getLabel()
{
return $this->label;
}
/**
* Set parent
*
* #param \AppBundle\Entity\Facility $parent
* #return Facility
*/
public function setParent(\AppBundle\Entity\Facility $parent = null)
{
$this->parent = $parent;
return $this;
}
/**
* Get parent
*
* #return \AppBundle\Entity\Facility
*/
public function getParent()
{
return $this->parent;
}
public function __toString()
{
return $this->label;
}
}
and for FacilityType.php
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class FacilityType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('parent')
->add('label')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Facility'
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_facility';
}
}
How can I get just the parents in the $builder->add('parent') (dropdown select) and not all the data.
Thanks in advance.
You don't need to access repository from an entity class. Entities should be plain php objects. If you want to limit options in your dropdown use query_builder property.
$builder->add('parent', 'entity', array(
'class' => 'AppBundle:Facility',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('f')
->where('/* ... */');
},
));
It depends on your case. If your filter criteria is fixed, then #b.b3rn4rd's answer is best. If the criteria depends on the current facility then you probably want to use a form event listener. Symfony forms have a fairly powerful architecture, where a single form type is created and then cloned for each instance. The buildForm() method is only called once for each form even if the field type is repeated multiple times on the page. In some cases the field is only rendered once, and that is fine but the safest way is to use a form listener. Rather than adding a generic parent field to the form builder, you are adding a specific field to the form instance.
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('label');
$builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
/** #var Facility $facility */
$facility = $event->getData();
$form->add(
'parent',
'entity',
array(
'class' => 'AppBundle:Facility',
'query_builder' => function (FacilityRepository $repository) use ($facility) {
return $repository->createQueryBuilder('f')->findParents($facility);
},
)
);
});
}