This blog covers following questions:
how to
1, custom query in entitity field type
2, add custom field into entity form type
3, how to pass data to formBuilder
4, how to transform array to collection
5, how to set default choices in controller
6, how to get form data from request
questions are all related, to answer all the questions, lets setup a scenario.
we have category, product, tag and product_tags
the relationships are:
each category may have many products
each product only belongs to one category
each category may have many tags
each tag only belongs to one category
products may have many tags belonging to current category
So we have entities: Category, Product, Tag, ProductTags
When we do product crud, we want to be able to manage product tags in product form.
Then all problems popup.
1, add tags list in product form
in ProductType class
add tags field
$category = $this->category;
$builder->add('tags', 'entity', array(
'property_path' => false,
'multiple' => true,
'expanded' => true,
'class' => 'Bundle:Tag',
'query_builder' => function(Bundle\Repository\TagRepository $er) use ($category) {
return $er->createQueryBuilder('u')
->where('u.category = '. $category->getId());
}
));
pay attention to:
'property_path' => false, this means the field is not part of the product entity, without this, you'll get fatal error of no getter, no setter.
use ($category) , this is how you pass current category to the query_builder.
very well, you got the field, but where this $category from??? how do you pass data to formBuilder?
answer is
in your ProductType class, add following:
protected $category; //category object
public function __construct($category)
{
$this->category = $category;
}
in your controller:
$category = $em->getRepository('Bundle:Category')->find($id);
$entity = new Product();
$form = $this->createForm(new ProductType($category), $entity);
Now, on your new product form, you've got the tags list, next is handling the form submitted data.
$data = $request->request->get('product');
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($entity);
$em->flush();
//save product tags
if(!empty($data['tag']))
{
foreach ($data['tag'] as $value) {
$tag = $em->getRepository('Bundle:Tag')->find($value);
$obj = new ProductTags();
$obj->setProduct($entity);
$obj->setTag($tag);
$em = $this->getDoctrine()->getEntityManager();
$em->persist($obj);
$em->flush();
}
}
Almost there, when you edit the product, you need setup the default value for the tag list, here is how to do it:
this is how your transform array to collection
in your controller
use Doctrine\Common\Collections\ArrayCollection;
in your edit action
$entities = $em->getRepository('Bundle:ProductTags')->findByProduct($product_entity);
$choices = new ArrayCollection($entities);
$editForm->get('tag')->setData($choices);
making sure pass category object when you create the product form, that's all.
More than 3 requests, I'll translate this to Chinese.
超过3个请求,我就会把这篇文章翻译成中文。
1 comment:
Great post :)
It works great with a many-to-one relation ; but with a many-to-many / many-to-many relation, with a intermediate table between article and tag, it persist only article and tag in the database, not the relation between them :/
Post a Comment