How to populate a dropdown in Symfony 3 - php

I am a newbie in symfony and i have decided to explore symfony 3. I have two models: products and category and I want to populate a dropdown in a new product form with all the categories. How can i do this pls?
Below is what have done so far:
<?php
Product Model:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Persisters\Entity;
use Doctrine\ORM\Mapping\Column;
/**
* #ORM\Entity
* #ORM\Table(name="product")
*/
class Product
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
/**
* #ORM\Column( type ="string", length=100)
*/
private $name;
/**
* #ORM\Column(type="decimal", scale=2)
*/
private $price;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Product
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set price
*
* #param string $price
*
* #return Product
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* #return string
*/
public function getPrice()
{
return $this->price;
}
/**
* Set description
*
* #param string $description
*
* #return Product
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set category
*
* #param \AppBundle\Entity\Category $category
*
* #return Product
*/
public function setCategory(\AppBundle\Entity\Category $category = null)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return \AppBundle\Entity\Category
*/
public function getCategory()
{
return $this->category;
}
}
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* #ORM\Table(name="category")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
*/
class Category
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Product", mappedBy="category")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $products;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
public function __construct()
{
$this->products= new ArrayCollection();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add product
*
* #param \AppBundle\Entity\Product $product
*
* #return Category
*/
public function addProduct(\AppBundle\Entity\Product $product)
{
$this->products[] = $product;
return $this;
}
/**
* Remove product
*
* #param \AppBundle\Entity\Product $product
*/
public function removeProduct(\AppBundle\Entity\Product $product)
{
$this->products->removeElement($product);
}
/**
* Get products
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProducts()
{
return $this->products;
}
}
<
?php
DefaultController:
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use AppBundle\Entity\Category;
use AppBundle\Entity\Product;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
class DefaultController extends Controller
{
/**
* #Route("/product_new")
*/
public function newAction(Request $request)
{
$category = new Category();
$product = new Product();
$form = $this->createFormBuilder($product)
->add('name', TextType::class)
->add('price', NumberType::class)
->add('description', TextareaType::class)
->add('category', EntityType::class, array(
'class' => 'AppBundle:Category',
'choices' => $category->getProducts(),
))
->add('save', SubmitType::class, array('label'=>'Create New Product'))
->getForm();
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid())
{
// $category->setName( $request->request->get('category'));
//$product->setCategory( new Category('Cat1'));
$product = $form->getData();
$entityManager = $this->getDoctrine()->getManager();
//$entityManager->persist($category);
$entityManager->persist($product);
$entityManager->flush();
return $this->render('product/product_status.html.twig',
['msg' =>'Saved new product with id ' . $product->getId()]);
}else
{
return $this->render('product/product_new.html.twig', ['form'=> $form->createView(),]);
}
}
/**
* #Route("/new_product", name="new_product")
*/
public function createAction(Request $request)
{
$product = new Product();
$product->setName("Keyboard");
$product->setPrice(19.9);
$product->setDescription("Ergonomic and stylish!");
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($product);
$entityManager->flush();
return $this->render('product/product_status.html.twig',
['msg' =>'Saved new product with id ' . $product->getId()]);
}
/**
* #Route("/show_product/{productId}")
*/
public function showAction($productId)
{
$product = $this->getDoctrine()->getRepository('AppBundle:Product')->find($productId);
if(!$product)
{
$this->createNotFoundException("No Product was found with Id". $productId);
}
return $this->render('product/product_search.html.twig', ['product' => $product]);
}
/**
* #Route("/product_list", name ="productlist")
*/
public function listAction()
{
$products = $this->getDoctrine()->getRepository('AppBundle:Product')->findAll();
if(!$products)
{
$this->createNotFoundException("No Product was found ");
}
return $this->render('product/product_list.html.twig', ['products' => $products]);
}
/**
* #Route("/update_product/{productId}", name ="updateproduct")
*/
public function updateAction($productId)
{
$entityManager = $this->getDoctrine()->getManager();
$product = $this->getDoctrine()->getRepository('AppBundle:Product')->find($productId);
if($product)
{
$product->setName("Project");
$product->setDescription("Sony Projector with LCD light");
$entityManager->flush();
return $this->redirectToRoute('productlist');
}
}
/**
* #Route("/delete_product/{productId}", name ="deleteproduct")
*/
public function deleteAction($productId)
{
$entityManager = $this->getDoctrine()->getManager();
$product = $this->getDoctrine()->getRepository('AppBundle:Product')->find($productId);
if($product)
{
$entityManager->remove($product);
$entityManager->flush();
return $this->redirectToRoute('productlist');
}
}
}

You can use query_builder option like below. You can adapt it to your application. Full example is here: Full webform style CRUD example with an embedded associated entity in symfony
....
private $country;
public function __construct()
{
$this->country = [
....
'class' => 'FootballFrontendBundle:Country',
'query_builder' => function (EntityRepository $repo)
{
return $repo->createQueryBuilder('c')->orderBy('c.name', 'ASC');
}
];
}
public function buildForm(FormBuilderInterface $builder, array $options = [])
{
$builder
....
->add('country', 'entity', $this->country);
}
....

Related

Neither the property "parent" build form Symfony 2 Self-Referenced mapping

I have an Entity containing Self-Referenced mapping. I would like to add new categories and subcategories to the systems but I do not know how to build the add form correctly. Gets are generated and setters are generated in Entity. I'm getting an error:
Neither the property "parent" nor one of the methods
"addParent()"/"removeParent()", "setParent()", "parent()", "__set()"
or "__call()" exist and have public access in class
"Adevo\ClassifiedsBundle\Entity\ClassifiedsCategory".
namespace XXX\ClassifiedsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="XXX\ClassifiedsBundle\Repository\ClassifiedsCategoryRepository")
* #ORM\Table(name="classifieds_categories")
*/
class ClassifiedsCategory extends ClassifiedsAbstractTaxonomy {
/**
* #ORM\OneToMany(
* targetEntity = "Classifieds",
* mappedBy = "category"
* )
*/
protected $classifieds;
/**
* #ORM\ManyToMany(targetEntity="ClassifiedsCategory", mappedBy="parent")
*/
private $children;
/**
*
* #ORM\ManyToMany(targetEntity="ClassifiedsCategory", inversedBy="children")
* #ORM\JoinTable(name="subCategory",
* joinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="parent_id", referencedColumnName="id")}
* )
*/
private $parent;
/**
* Constructor
*/
public function __construct() {
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
$this->parent = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add classified
*
* #param \XXX\ClassifiedsBundle\Entity\Classifieds $classified
*
* #return ClassifiedsCategory
*/
public function addClassified(\XXX\ClassifiedsBundle\Entity\Classifieds $classified) {
$this->classifieds[] = $classified;
return $this;
}
/**
* Remove classified
*
* #param \XXX\ClassifiedsBundle\Entity\Classifieds $classified
*/
public function removeClassified(\XXX\ClassifiedsBundle\Entity\Classifieds $classified) {
$this->classifieds->removeElement($classified);
}
/**
* Get classifieds
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getClassifieds() {
return $this->classifieds;
}
/**
* Add child
*
* #param \XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $child
*
* #return ClassifiedsCategory
*/
public function addChild(\XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $child) {
$this->children[] = $child;
return $this;
}
/**
* Remove child
*
* #param \XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $child
*/
public function removeChild(\XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $child) {
$this->children->removeElement($child);
}
/**
* Get children
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getChildren() {
return $this->children;
}
/**
* Add parent
*
* #param \XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $parent
*
* #return ClassifiedsCategory
*/
public function addParent(\XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $parent) {
$this->parent[] = $parent;
return $this;
}
/**
* Remove parent
*
* #param \XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $parent
*/
public function removeParent(\XXX\ClassifiedsBundle\Entity\ClassifiedsCategory $parent) {
$this->parent->removeElement($parent);
}
/**
* Get parent
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getParent() {
return $this->parent;
}
}
<pre>
namespace XXX\ClassifiedsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
* #ORM\HasLifecycleCallbacks
*/
abstract class ClassifiedsAbstractTaxonomy {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=120, unique=true)
*/
private $name;
/**
* #ORM\Column(type="string", length=120, unique=true)
*/
private $slug;
protected $classifieds;
/**
* Constructor
*/
public function __construct()
{
$this->classifieds = new \Doctrine\Common\Collections\ArrayCollection();
// $this->children = new \Doctrine\Common\Collections\ArrayCollection();
// $this->parent = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add classifieds
*
* #param \XXX\ClassifiedsBundle\Entity\Classifieds $classifieds
* #return ClassifiedsCategory
*/
public function addClassifieds(\XXX\ClassifiedsBundle\Entity\Classifieds $classifieds)
{
$this->classifieds[] = $classifieds;
return $this;
}
/**
* Remove classifieds
*
* #param \XXX\ClassifiedsBundle\Entity\Classifieds $classifieds
*/
public function removeClassifieds(\XXX\ClassifiedsBundle\Entity\Classifieds $classifieds)
{
$this->classifieds->removeElement($classifieds);
}
/**
* Get classifieds
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCompanies()
{
return $this->classifieds;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return AbstractTaxonomy
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set slug
*
* #param string $slug
* #return AbstractTaxonomy
*/
public function setSlug($slug)
{
$this->slug = \XXX\ClassifiedsBundle\Libs\Utils::sluggify($slug);
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function preSave(){
if(null === $this->slug){
$this->setSlug($this->getName());
}
}
}
namespace XXX\AdminBundle\Form\Type;
use XXX\AdminBundle\Form\Type\ClassifiedsTaxonomyType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ClassifiedsCategoryType extends ClassifiedsTaxonomyType {
public function getName() {
return 'taxonomy';
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('name', 'text', array(
'label' => 'Tytuł'
))
->add('slug', 'text', array(
'label' => 'Alias'
))
->add('parent', 'entity', array(
'class' => 'XXX\ClassifiedsBundle\Entity\ClassifiedsCategory',
'property' => 'name',
'empty_value' => 'Choose a parent category',
'required' => false,
))
->add('save', 'submit', array(
'label' => 'Zapisz'
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'XXX\ClassifiedsBundle\Entity\ClassifiedsCategory'
));
}
}
Your FormType ClassifiedsCategoryType is expecting an instance of ClassifiedsCategory and this need the attribute parent so far so good. But when you handle the request from your form to the controller, the formbuilder component tries to set the entered value to the attribute via the set method on the entity. This set method (setParent) is missing in your entity class.
So you have to implement it like this:
public function setParent($parent)
{
$this->parent = $parent;
return $this;
}

Symfony3 Trying to add record in join table

A User has many Games.
A Game can Belong to many Users.
I have a form with a list of games, I want the list of Games to be added to the current logged User.
When I submit the form nothing happens, I want at least 1 record to be added to users_games:
Update:
Added User entity
FormType addGameToUserType:
namespace AppBundle\Form;
use AppBundle\Entity\Game;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
class addGameToUserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('game', EntityType::class, [
'class' => 'AppBundle:Game',
'choice_label' => function ($game) {
return $game->getName();
},
'multiple' => true,
'expanded' => false,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
}
public function getBlockPrefix()
{
return 'app_bundleadd_game_to_user';
}
}
UserController addGameAction:
/**
* Adds game(s) to current user.
*
* #Route("user/game/add", name="game_add")
* #Method({"GET", "POST"})
*/
public function addGameAction(Request $request)
{
/** #var $form */
$form = $this->createForm('AppBundle\Form\addGameToUserType');
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
echo $form->get('game')->getData();
$em = $this->getDoctrine()->getManager();
/** #var $game */
$game = new Game();
$game->getId();
/** #var User $userObject */
$userObject = $this->getUser();
$user = $em->getRepository('AppBundle:User')
->find(['id' => $userObject->getId()]);
$game->addGameUser($user);
$em->persist($user);
$em->flush();
}
return $this->render('user/addGame.html.twig', array(
'form' => $form->createView()
));
}
Game entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Game
*
* #ORM\Table(name="game")
* #ORM\Entity(repositoryClass="AppBundle\Repository\GameRepository")
*/
class Game
{
/**
* #ORM\OneToMany(targetEntity="PlayLog", mappedBy="game")
* #ORM\OrderBy({"date" = "DESC"})
*
*/
private $playlogs;
private $users;
/**
* #return ArrayCollection
*/
public function getUsers()
{
return $this->users;
}
/**
* #param ArrayCollection $users
*/
public function setUsers($users)
{
$this->users = $users;
}
// private $categories;
public function __construct()
{
$this->playlogs = new ArrayCollection();
$this->users = new ArrayCollection();
}
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #Assert\NotBlank()
* #Assert\Length(
* min = "3",
* max = "100"
* )
* #ORM\Column(name="name", type="string", length=255, unique=true)
*/
private $name;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Game
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* #return mixed
*/
public function getPlaylogs()
{
return $this->playlogs;
}
/**
* #param mixed $playlogs
*/
public function setPlaylogs($playlogs)
{
$this->playlogs = $playlogs;
}
public function addPlayLog(PlayLog $playlog)
{
$this->playlog->add($playlog);
$playlog->setPlayLogs($this);
}
public function addGameUser(User $user){
$this->users[] = $user;
}
}
User entity:
namespace AppBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\ManyToMany(targetEntity="Game")
*
* #ORM\JoinTable(name="users_games",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="game_id", referencedColumnName="id")}
* )
*/
private $games;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\PlayLog", mappedBy="user")
*
*/
private $playlogs;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}
public function __construct()
{
$this->games = new ArrayCollection();
}
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #return mixed
*/
public function getGames()
{
return $this->games;
}
/**
* #param mixed $games
*/
public function setGames($games)
{
$this->games = $games;
}
public function addGame(Game $game)
{
// $this->games->add($game);
$this->games[] = $game;
return $this;
}
public function removeGame(Game $game)
{
$this->games->removeElement($game);
}
/**
* #return mixed
*/
public function getPlaylogs()
{
return $this->playlogs;
}
/**
* #param mixed $playlogs
*/
public function setPlaylogs($playlogs)
{
$this->playlogs = $playlogs;
}
public function addPlayLog(PlayLog $playlog)
{
$this->playlog->add($playlog);
$playlog->setPlayLogs($this);
}
}

Symfony 3 form pre-populate collection field type

Is it possible to populate collection with some default items
Say you have collection of prices, but each price can be of different type. And what I want is that collection always has some predefined (generated somehow) items?
Main entity
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\JoinTable;
use Doctrine\ORM\Mapping\ManyToMany;
/**
* Class Stamp
* #package AppBundle\Entity
*
*
* #ORM\Entity(repositoryClass="AppBundle\Repository\StampRepository")
* #ORM\Table(name="stamp")
* #ORM\HasLifecycleCallbacks()
*/
class Stamp
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=512, nullable=true)
*/
private $title;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Price", cascade={"persist", "remove"})
* #ORM\JoinTable(name="stamps_prices",
* joinColumns={#ORM\JoinColumn(name="stamp_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="price_id", referencedColumnName="id", onDelete="CASCADE")}
* )
*/
private $prices;
/**
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\Column(type="datetime")
*/
private $updatedAt;
public function __construct()
{
$this->prices = new ArrayCollection();
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getTitle()
{
return $this->title;
}
/**
* #param mixed $title
*
* #return Stamp
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* #return mixed
*/
public function getPrices()
{
return $this->prices;
}
public function addPrice(Price $price)
{
$this->prices->add($price);
}
/**
* #param mixed $prices
*
* #return Stamp
*/
public function setPrices(ArrayCollection $prices)
{
$this->prices = $prices;
return $this;
}
/**
* #return mixed
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* #param mixed $createdAt
*
* #return Stamp
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* #return mixed
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* #param mixed $updatedAt
*
* #return Stamp
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function updateTimestamps()
{
$this->setUpdatedAt(new \DateTime('now'));
if (null == $this->getCreatedAt()) {
$this->setCreatedAt(new \DateTime());
}
}
}
Main entity form
<?php
namespace AppBundle\Form;
use AppBundle\Entity\Stamp;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AdminStampForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', null, [
'label' => false,
'attr' => [
'id' => 'stamp-title',
'class' => 'form-control input-md',
'placeholder' => 'Enter title',
'autocomplete' => 'off'
]
])
->add('prices', CollectionType::class, [
'label' => false,
'entry_type' => AdminStampPriceForm::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Stamp::class,
]);
}
public function getName()
{
return 'app_bundle_admin_stamp_form';
}
}
Price entity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Class Price
* #package AppBundle\Entity
*
* #ORM\Entity(repositoryClass="AppBundle\Repository\PriceRepository")
* #ORM\Table(name="price")
*/
class Price
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\PriceType")
* #ORM\JoinColumn(name="type_id", nullable=false, referencedColumnName="id")
*/
private $type;
/**
* #ORM\Column(type="string")
*/
private $value;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $city;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $issueDate;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getType()
{
return $this->type;
}
/**
* #param mixed $type
* #return Price
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* #return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* #param mixed $value
*
* #return Price
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* #return mixed
*/
public function getCity()
{
return $this->city;
}
/**
* #param mixed $city
*
* #return Price
*/
public function setCity($city)
{
$this->city = $city;
return $this;
}
/**
* #return mixed
*/
public function getIssueDate()
{
return $this->issueDate;
}
/**
* #param mixed $issueDate
*
* #return Price
*/
public function setIssueDate($issueDate)
{
$this->issueDate = $issueDate;
return $this;
}
}
PriceType Entity
<?php
namespace AppBundle\Entity;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Doctrine\ORM\Mapping as ORM;
/**
* Class PriceType
* #package AppBundle\Entity
*
* #ORM\Entity(repositoryClass="AppBundle\Repository\PriceTypeRepository")
* #ORM\Table(name="price_type")
* #ORM\HasLifecycleCallbacks()
*/
class PriceType
{
const SECTION_UNUSED = 1;
const SECTION_USED = 2;
const SECTION_FDC = 3;
const SECTION_CUSTOM = 4;
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="integer")
*/
private $section;
/**
* #ORM\Column(type="string")
*/
private $name;
/**
* #ORM\Column(type="boolean")
*/
private $hasCityName = false;
/**
* #ORM\Column(type="boolean")
*/
private $hasIssueDate = false;
/**
* #ORM\Column(type="boolean")
*/
private $isPredefined = false;
/**
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\Column(type="datetime")
*/
private $updatedAt;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getSection()
{
return $this->section;
}
/**
* #param mixed $section
*
* #return PriceType
*/
public function setSection($section)
{
$this->section = $section;
return $this;
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param mixed $name
*
* #return PriceType
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* #return mixed
*/
public function getHasCityName()
{
return $this->hasCityName;
}
/**
* #param mixed $hasCityName
*
* #return PriceType
*/
public function setHasCityName($hasCityName)
{
$this->hasCityName = $hasCityName;
return $this;
}
/**
* #return mixed
*/
public function getHasIssueDate()
{
return $this->hasIssueDate;
}
/**
* #param mixed $hasIssueDate
*
* #return PriceType
*/
public function setHasIssueDate($hasIssueDate)
{
$this->hasIssueDate = $hasIssueDate;
return $this;
}
/**
* #return mixed
*/
public function getIsPredefined()
{
return $this->isPredefined;
}
/**
* #param mixed $isPredefined
*
* #return PriceType
*/
public function setIsPredefined($isPredefined)
{
$this->isPredefined = $isPredefined;
return $this;
}
/**
* #return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* #param \DateTime $createdAt
*
* #return PriceType
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* #return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* #param \DateTime $updatedAt
*
* #return PriceType
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* #ORM\PrePersist
* #ORM\PreUpdate
*/
public function updateTimestamps()
{
$this->setUpdatedAt(new \DateTime('now'));
if (null == $this->getCreatedAt()) {
$this->setCreatedAt(new \DateTime());
}
}
}
PriceType repository
<?php
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
/**
* Class PriceTypeRepository
* #package AppBundle\Entity
*/
class PriceTypeRepository extends EntityRepository
{
public function getPredefinedPriceTypes($section)
{
return $this
->createQueryBuilder('pt')
->andWhere('pt.section = :section')
->setParameter('section', $section)
->andWhere('pt.isPredefined = :isPredefined')
->setParameter('isPredefined', true)
->getQuery()
->getResult()
;
}
}
Priec form
<?php
namespace AppBundle\Form;
use AppBundle\Entity\Price;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AdminStampPriceForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('value', null, [
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Price::class,
]);
}
public function getBlockPrefix()
{
return 'app_bundle_admin_stamp_price_form';
}
}
Main entity controller newAction
/**
* #Route("/new", name="admin_stamps_new")
* #Template(engine="haml")
*/
public function newAction(Request $request)
{
$stamp = new Stamp();
$priceTypeRepo = $this->getDoctrine()->getManager()->getRepository('AppBundle:PriceType');
$priceTypes = $priceTypeRepo->getPredefinedPriceTypes(PriceType::SECTION_UNUSED);
/** #var PriceType $priceType */
foreach ($priceTypes as $priceType) {
$price = new Price();
$price->setType($priceType->getId());
$stamp->addPrice($price);
}
$form = $this->createForm(AdminStampForm::class, $stamp);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** #var Stamp $stamp */
$stamp = $form->getData();
$user = $this->getUser();
$stamp->setUser($user);
$stamp->setCountry($user->getAdminConfig()->getCountry());
$em = $this->getDoctrine()->getManager();
$em->persist($stamp);
$em->flush();
$this->addFlash('success', 'Successfully added a new stamp!');
return $this->redirectToRoute('admin_stamps_list');
}
return [
'form' => $form->createView(),
];
}
So I tried to populate Stamp entity itself. But what I actually need is to have 4 separate field sets of prices (each field set for a price type). And (and) to have some predefined $priceType->isPredefined() prices to be there. I'm not sure if you understand correctly what I'm trying to say. So I will answer all upcoming questions.

Cannot get related entity field to save in Symfony Admin Form

I'm working my way through Symfony trying to learn how it all fits together and I'm working on the admin section.
Right now I'm putting together an admin form for a Show Entity which will reference a section entity (so this show belongs in that section, etc). Every other field in the form saves EXCEPT for the related entity choice field.
This is the ShowAdmin class
<?php
namespace AppBundle\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Nelmio\ApiDocBundle\Tests\Fixtures\Form\EntityType;
class ShowAdmin extends AbstractAdmin {
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper->add('title', 'text')
->add('shortname', 'text')
->add('section_id', EntityType::class, array(
'class' => 'AppBundle:SectionEntity',
'choice_label' => 'section_title',
))
->add('logo', 'text')
->add('description', 'textarea')
->add('status', 'integer');
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper->add('title');
$datagridMapper->add('shortname');
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->addIdentifier('title');
$listMapper->add('shortname', 'text');
}
}
This is the ShowEntity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="shows")
*/
class ShowEntity {
function __construct() {
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=100)
*/
private $title;
/**
* #ORM\Column(type="string", length=100)
*/
private $shortname;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\SectionEntity")
*/
private $section;
/**
* #ORM\Column(type="string", length=255)
*/
private $logo;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
* #ORM\Column(type="integer")
*/
private $status;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* #param string $title
*
* #return ShowEntity
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set sectionId
*
* #param integer $sectionId
*
* #return ShowEntity
*/
public function setSectionId($sectionId)
{
$this->section_id = $sectionId;
return $this;
}
/**
* Get sectionId
*
* #return integer
*/
public function getSectionId()
{
return $this->section_id;
}
/**
* Set logo
*
* #param string $logo
*
* #return ShowEntity
*/
public function setLogo($logo)
{
$this->logo = $logo;
return $this;
}
/**
* Get logo
*
* #return string
*/
public function getLogo()
{
return $this->logo;
}
/**
* Set description
*
* #param string $description
*
* #return ShowEntity
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set status
*
* #param integer $status
*
* #return ShowEntity
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* Get status
*
* #return integer
*/
public function getStatus()
{
return $this->status;
}
/**
* Set shortname
*
* #param string $shortname
*
* #return ShowEntity
*/
public function setShortname($shortname)
{
$this->shortname = $shortname;
return $this;
}
/**
* Get shortname
*
* #return string
*/
public function getShortname()
{
return $this->shortname;
}
}
And this is the SectionEntity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* SectionEntity
*
* #ORM\Table(name="section_entity")
* #ORM\Entity(repositoryClass="AppBundle\Repository\SectionEntityRepository")
*/
class SectionEntity
{
protected $section_id;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="text")
*/
private $section_title;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set sectionTitle
*
* #param string $sectionTitle
*
* #return SectionEntity
*/
public function setSectionTitle($sectionTitle)
{
$this->section_title = $sectionTitle;
return $this;
}
/**
* Get sectionTitle
*
* #return string
*/
public function getSectionTitle()
{
return $this->section_title;
}
/**
* Get string
*/
public function __toString() {
return $this->section_title;
}
function __construct() {
$this->section_id = new \Doctrine\Common\Collections\ArrayCollection();
}
}
Any help would be greatly appreciated, I know it's probably something super simple that I'm just not seeing.
Thanks.
(optional) Rename ShowEntity::$section into ShowEntity::$sections to highlight sections is a collection but not a single entity.
Set ShowEntity __construct method body to:
$this->sections = new \Doctrine\Common\Collections\ArrayCollection();
At ShowAdmin::configureFormFields rename
->add('section_id', EntityType::class, array(
into
->add('section', EntityType::class, array(
You should use direct reference to the relation instead of id.
Remove SectionEntity::__construct method, it has no sense.
Remove protected $section_id; from SectionEntity.
Change public function setSectionId($sectionId) into public function setSection(Section $section).
Perhaps you also need to rename section_title into sectionTitle or simply title, not sure about that.

Select categories related to current Store entity

I have two entities Store and Category and each Store has it's own categories.
I'd like that when a Store owner's try to add a new category and category_parent, just the categories related to current Store will be displayed.
Right now, all categories are displayed in the select-option.
I'm using Tree Gedmo extension to manage Category entity and I use getChildrenQueryBuilder method to select categories.
How can I modify this method and add my specific constraint ?
$store which is the constraint is declared in the controller action down.
I'd like te set current Category option disabled when he try to add a category_parent, so category and category parent must be differnt.
I hope it's clear
CategoryType.php
<?php
namespace Project\StoreBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
class CategoryType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
//..........
//..........
->add('category', 'entity', array(
'required' => false,
'label' => 'Category parent',
'class' => 'ProjectStoreBundle:Category',
'attr' => array('class' => 'col-sm-8'),
'empty_value' => 'Select one category',
'property' => 'indentedName',
'multiple' => false,
'expanded' => false ,
'query_builder' => function (\Project\StoreBundle\Entity\CategoryRepository $r)
{
return $r->getChildrenQueryBuilder(null, null, 'root', 'asc', false);
}
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Project\StoreBundle\Entity\Category'
));
}
/**
* #return string
*/
public function getName()
{
return 'project_storebundle_category';
}
}
Entity/Category.php
<?php
namespace Project\StoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Category
* #Gedmo\Tree(type="nested")
* #ORM\Table()
* #ORM\Entity(repositoryClass="Project\StoreBundle\Entity\CategoryRepository")
* #ORM\HasLifeCycleCallbacks()
*/
class Category
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*
*#Assert\NotBlank(message="Please enter the name of categorie.")
*/
private $name;
/**
* #Gedmo\slug(fields={"name"}, unique_base="uniqueBase")
* #ORM\Column(name="slug",length=255, unique=false)
*/
private $slug ;
/**
* #ORM\Column(name="uniqueBase", type="integer")
*/
private $uniqueBase ;
/**
* #ORM\Column(name="description", type="text", nullable=true)
*/
private $description;
/**
* #ORM\Column(name="metaDescription", type="string", length=255, nullable=true)
*
* #Assert\Length(
* max=255,
* maxMessage="message"
* )
*/
private $metaDescription;
/**
* #ORM\Column(name="metaKeywords", type="string", length=255, nullable=true)
*
* #Assert\Length(
* max=255,
* maxMessage="message"
* )
*/
private $metaKeywords;
/**
* #ORM\Column(name="enabled", type="boolean", nullable=false)
*/
private $enabled;
/**
* #Gedmo\TreeLeft
* #ORM\Column(name="lft", type="integer")
*/
private $lft;
/**
* #Gedmo\TreeLevel
* #ORM\Column(name="lvl", type="integer")
*/
private $lvl;
/**
* #Gedmo\TreeRight
* #ORM\Column(name="rgt", type="integer")
*/
private $rgt;
/**
* #Gedmo\TreeRoot
* #ORM\Column(name="root", type="integer", nullable=true)
*/
private $root;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
/**
* #ORM\OneToMany(targetEntity="Category", mappedBy="parent")
* #ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
/**
*non mapped property
*/
private $indentedName;
/**
*non mapped property
*/
private $category;
/**
* #ORM\ManyToOne(targetEntity="Project\StoreBundle\Entity\Store", inversedBy="categories", cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
*/
private $store ;
/**
* Constructor
*/
public function __construct()
{
$this->children = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set slug
*
* #param string $slug
* #return Category
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Set uniqueBase
*
* #param integer $uniqueBase
* #return Category
*/
public function setUniqueBase($uniqueBase)
{
$this->uniqueBase = $uniqueBase;
return $this;
}
/**
* Get uniqueBase
*
* #return integer
*/
public function getUniqueBase()
{
return $this->uniqueBase;
}
/**
* Set description
*
* #param string $description
* #return Category
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set metaDescription
*
* #param string $metaDescription
* #return Category
*/
public function setMetaDescription($metaDescription)
{
$this->metaDescription = $metaDescription;
return $this;
}
/**
* Get metaDescription
*
* #return string
*/
public function getMetaDescription()
{
return $this->metaDescription;
}
/**
* Set metaKeywords
*
* #param string $metaKeywords
* #return Category
*/
public function setMetaKeywords($metaKeywords)
{
$this->metaKeywords = $metaKeywords;
return $this;
}
/**
* Get metaKeywords
*
* #return string
*/
public function getMetaKeywords()
{
return $this->metaKeywords;
}
/**
* Set enabled
*
* #param boolean $enabled
* #return Category
*/
public function setEnabled($enabled)
{
$this->enabled = $enabled;
return $this;
}
/**
* Get enabled
*
* #return boolean
*/
public function getEnabled()
{
return $this->enabled;
}
/**
* Set parent
*
* #param \Project\StoreBundle\Entity\Category $parent
* #return Category
*/
public function setParent(\Project\StoreBundle\Entity\Category $parent = null)
{
$this->parent = $parent;
return $this;
}
/**
* Get parent
*
* #return \Project\StoreBundle\Entity\Category
*/
public function getParent()
{
return $this->parent;
}
/**
* Set lft
*
* #param integer $lft
* #return Category
*/
public function setLft($lft)
{
$this->lft = $lft;
return $this;
}
/**
* Get lft
*
* #return integer
*/
public function getLft()
{
return $this->lft;
}
/**
* Set lvl
*
* #param integer $lvl
* #return Category
*/
public function setLvl($lvl)
{
$this->lvl = $lvl;
return $this;
}
/**
* Get lvl
*
* #return integer
*/
public function getLvl()
{
return $this->lvl;
}
/**
* Set rgt
*
* #param integer $rgt
* #return Category
*/
public function setRgt($rgt)
{
$this->rgt = $rgt;
return $this;
}
/**
* Get rgt
*
* #return integer
*/
public function getRgt()
{
return $this->rgt;
}
/**
* Set root
*
* #param integer $root
* #return Category
*/
public function setRoot($root)
{
$this->root = $root;
return $this;
}
/**
* Get root
*
* #return integer
*/
public function getRoot()
{
return $this->root;
}
/**
* Add children
*
* #param \Project\StoreBundle\Entity\Category $children
* #return Category
*/
public function addChild(\Project\StoreBundle\Entity\Category $children)
{
$this->children[] = $children;
return $this;
}
/**
* Remove children
*
* #param \Project\StoreBundle\Entity\Category $children
*/
public function removeChild(\Project\StoreBundle\Entity\Category $children)
{
$this->children->removeElement($children);
}
/**
* Get children
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getChildren()
{
return $this->children;
}
/**
* Get IndentedName
*
*/
public function getIndentedName()
{
return str_repeat("-----", $this->lvl).$this->name;
}
/**
* Get category
*
*/
public function getCategory()
{
return $this->category;
}
/**
* Set store
*
* #param \Project\StoreBundle\Entity\Store $store
* #return Category
*/
public function setStore(\Project\StoreBundle\Entity\Store $store = null)
{
$this->store = $store;
return $this;
}
/**
* Get store
*
* #return \Project\StoreBundle\Entity\Store
*/
public function getStore()
{
return $this->store;
}
}
Controller
/**
* Create a new Category entity.
*
*/
/**
* #ParamConverter("store", options={"mapping": {"store_id":"id"}})
*/
public function newAction(Store $store)
{
// keep in mind, this will call all registered security voters
if (false === $this->get('security.context')->isGranted('edit', $store)) {
throw new AccessDeniedException('Unauthorised access!');
}
$category = new Category();
$category->setStore($store);
$category->setUniqueBase($store->getId());
$form = $this->createForm(new CategoryType(), $category);
$request = $this->getRequest();
if ($request->getMethod() == 'POST')
{
$form->bind($request);
if ($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->flush();
$this->get('session')->getFlashBag()->add('message', 'Category enregistred');
return $this->redirect( $this->generateUrl('dashboard_category_index', array('store_id' => $store->getId())));
}
}
return $this->render('ProjectDashboardBundle:Category:new.html.twig',
array(
'form' => $form->createView() ,
'store' =>$store,
));
}
I managed to pass the parameter $store to the form, but I don't know how to use it as a constraint in getChildrenQueryBuilder method.
Should I create a new custom method? I prefer to use getChildrenQueryBuilder if it is possible.
Here is the new code
CategoryType.php
class CategoryType extends AbstractType
{
private $store;
public function __construct($store)
{
$this->store = $store;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$store = $this->store;
$builder
//...........
//...........
->add('parent', 'entity', array(
'required' => false,
'label' => 'Category parent',
'class' => 'ProjectStoreBundle:Category',
'attr' => array('class' => 'col-sm-8'),
'empty_value' => 'Select one category',
'property' => 'indentedName',
'multiple' => false,
'expanded' => false ,
'query_builder' => function (\Project\StoreBundle\Entity\CategoryRepository $r) use ($store)
{
return $r->getChildrenQueryBuilder(null, null, 'root', 'asc', false);
}
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Project\StoreBundle\Entity\Category'
));
}
/**
* #return string
*/
public function getName()
{
return 'project_storebundle_category';
}
}
Controller
/**
* #ParamConverter("store", options={"mapping": {"store_id":"id"}})
*/
public function newAction(Store $store)
{
// keep in mind, this will call all registered security voters
if (false === $this->get('security.context')->isGranted('edit', $store)) {
throw new AccessDeniedException('Unauthorised access!');
}
$category = new Category();
$category->setStore($store);
$category->setUniqueBase($store->getId());
$form = $this->createForm(new CategoryType($store), $category);
$request = $this->getRequest();
if ($request->getMethod() == 'POST')
{
$form->bind($request);
if ($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->flush();
$this->get('session')->getFlashBag()->add('message', 'Category enregistred');
return $this->redirect( $this->generateUrl('dashboard_category_index', array('store_id' => $store->getId())));
}
}
return $this->render('ProjectDashboardBundle:Category:new.html.twig',
array(
'form' => $form->createView() ,
'store' =>$store,
));
}
You're not saying which Symfony2 version you're using, but generically speaking, you just need to find a way to pass the current store to your form builder and use it in the method that filters the possible categories.
Take a look at this one, or this one, basically you just need to inject the $store into your form builder, and then you (almost) have it :-)

Categories