Laminas / Zf3 - getting parameters from Fieldset but it return null values - zend-framework3

I was following the instructions of #crash and I get the value of my parameter passed in my fieldset. But sometimes it returns a null value. Here are my complete code
My RapportEffetForm :
<?php
/**
* #module Commun
* #subpackage Form\Admin
* #author Samuel NANGUI <nanguisamuel#gmail.com>
* #copyright Copyright (c) 2021 Nslabs
*/
namespace Commun\Form\Modules\Application;
use Commun\Form\Modules\Application\Fieldset\RapportEffetFieldset;
use Commun\Form\CommunForm;
class RapportEffetForm extends CommunForm
{
private $parameters;
public function __construct($params)
{
$this->parameters=$params;
parent::__construct('RapportEffetForm',$this->parameters,[]);
}
public function init() {
$myFieldset = $this->getFormFactory()->getFormElementManager()->get(RapportEffetFieldset::class, ['params' => $this->parameters]);
$this->setName('RapportEffetForm');
$this->setAttribute('class', 'form-saisie');
//$this->addFieldset(RapportEffetFieldset::class,['use_as_base_fieldset' => true]);
$this->addFieldsetWithParameters($myFieldset,['use_as_base_fieldset' => true]);
$this->addSubmitButton('next', 'Poursuivre', 'next', 'btn btn-vert w-100');
$this->addSubmitButton('previous', 'Retour', 'previous', 'btn btn-rouge w-100');
}
}
My RapportEffetFormFactory :
<?php
/**
* #module Commun
* #subpackage Form
* #author Samuel NANGUI <nanguisamuel#gmail.com>
* #copyright Copyright (c) 2020 Nslabs
*/
namespace Commun\Factory\Form;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Commun\Form\Modules\Application\RapportEffetForm;
class RapportEffetFormFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$params = $options['id'] ?? [];
unset($options['id']);
return new RapportEffetForm($params);
}
}
My RapportEffetFieldset :
<?php
/**
* #module Commun
* #subpackage Form\Admin
* #author Samuel NANGUI <nanguisamuel#gmail.com>
* #copyright Copyright (c) 2020 Nslabs
*/
namespace Commun\Form\Modules\Application\Fieldset;
use Commun\Model\Entity\Supervision;
use Laminas\InputFilter\InputFilterProviderInterface;
use Laminas\Hydrator\ReflectionHydrator;
use Commun\Form\Modules\Application\Fieldset\EffetRapportFieldset;
use Commun\Form\CommunFormFieldset;
class RapportEffetFieldset extends CommunFormFieldset implements InputFilterProviderInterface
{
private $mapper;
private $params;
public function __construct($mappers=[],$params=[], $options = [])
{
$this->mapper = $mappers;
$this->params = $params;
parent::__construct($this->mapper,'RapportEffetForm',$options);
$this->setHydrator(new ReflectionHydrator());
$this->setObject(new Supervision());
$this->setLabel('RapportEffetFieldset');
}
public function init() {
parent::init();
$myFieldset = $this->getFormFactory()->getFormElementManager()->get(EffetRapportFieldset::class, ['params' => $this->params]);
$this->addCollection('effets','', get_class(new $myFieldset()),1,[],'__index__',FALSE,FALSE);
$optionsNotation = $this->mapper['notations']->getOptions('idRefNotation','libelle','Sélectionner',null,['ordre']);
$this->addSelect('notationEffetPresent', 'Notation du présent rapport',$optionsNotation,['class' => 'form-control'],'champ-requis');
$this->addSelect('notationEffetPrecedent', 'Notation du rapport précédent',$optionsNotation,['class' => 'form-control champ-affiche', 'placeholder' => 'Choisir']);
$this->addTextarea('JustifNotationEffet', 'Justification', NULL, ['class' => 'form-control','rows' => 5]);
}
/**
* #return array
*/
public function getInputFilterSpecification()
{
return [
];
}
}
My RapportEffetFieldsetFactory :
<?php
/**
* #module Commun
* #subpackage Form
* #author Samuel NANGUI <nanguisamuel#gmail.com>
* #copyright Copyright (c) 2020 Nslabs
*/
namespace Commun\Factory\Form\Fieldset;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Commun\Form\Modules\Application\Fieldset\RapportEffetFieldset;
class RapportEffetFieldsetFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$params = $options['params'] ?? [];
unset($options['params']);
$mappers = ['notations' => $container->get('TREFNOTATION')];
return new RapportEffetFieldset($mappers,$params,$options);
}
}
My EffetRapportFieldset :
<?php
/**
* #module Commun
* #subpackage Form\Admin
* #author Samuel NANGUI <nanguisamuel#gmail.com>
* #copyright Copyright (c) 2020 Nslabs
*/
namespace Commun\Form\Modules\Application\Fieldset;
use Commun\Model\Entity\EffetProjet;
use Laminas\InputFilter\InputFilterProviderInterface;
use Laminas\Hydrator\ReflectionHydrator;
use Laminas\Filter\StripTags;
use Laminas\Filter\StringTrim;
use Commun\Form\CommunFormFieldset;
class EffetRapportFieldset extends CommunFormFieldset implements InputFilterProviderInterface
{
private $mapper;
private $inputFilter;
private $params;
public function __construct($mappers=[],$params=[], $options = [])
{
$this->mapper = $mappers;
$this->params = $params;
parent::__construct($this->mapper,'EffetRapportForm',$options);
$this->setHydrator(new ReflectionHydrator());
$this->setObject(new EffetProjet());
}
public function init() {
parent::init();
var_dump($this->params);
//die;
$idProjet = $this->params['id']; // I retrieve my param here like this. But I get this warning <<Notice: Undefined index: id in EffetRapportFieldset.php on line 45>>
$optionsEffetCadreLogique = $this->mapper['effetProjet']->getOptions('idEffetProjet','libelleEffet','Sélectionner',['idProjet' => $idProjet],['libelleEffet']);
$this->addSelect('idEffetProjet', 'Intitule de l\'effet',$optionsEffetCadreLogique,['class' => 'form-control champ-affiche'],'champ-requis');
$this->addText('valeurReference','Valeur de référence (a)',NULL,['class' => 'form-control champ_decimal champ-affiche'],'champ-requis');
$this->addText('valeurRecente','Valeur la plus récente (b)',NULL,['class' => 'form-control champ_decimal'],'champ-requis');
$this->addText('valeurCible','Cible finale (c)',NULL,['class' => 'form-control champ_decimal champ-calcule'],'champ-requis');
$this->addText('progresRealisation','Progrès vers la réalisation de la cible (% de réalisation) (d=b/c)',NULL,['class' => 'form-control champ_decimal champ-affiche'],'champ-requis');
$this->addTextarea('evaluation', 'Évaluation', NULL, ['class' => 'form-control','rows' => 3]);
}
/**
* #return array
*/
public function getInputFilterSpecification()
{
return [
];
}
}
My EffetRapportFieldsetFactory :
<?php
/**
* #module Commun
* #subpackage Form
* #author Samuel NANGUI <nanguisamuel#gmail.com>
* #copyright Copyright (c) 2020 Nslabs
*/
namespace Commun\Factory\Form\Fieldset;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Commun\Form\Modules\Application\Fieldset\EffetRapportFieldset;
class EffetRapportFieldsetFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$params = $options['params'] ?? [];
unset($options['params']);
$mappers = ['effetProjet' => $container->get('TEFFETPROJET')];
return new EffetRapportFieldset($mappers,$params,$options);
}
}
My CommunForm class here :
<?php
/**
* #module Commun
* #subpackage Form
* #author Samuel NANGUI <nanguisamuel#gmail.com>
* #copyright Copyright (c) 2020 Nslabs
*/
namespace Commun\Form;
use Laminas\Form\Form;
use Laminas\Hydrator\ClassMethodsHydrator;
use Laminas\InputFilter\InputFilter;
use Laminas\Form\Element\Select;
use Laminas\Form\Element\Hidden;
class CommunForm extends Form
{
protected $mapper;
public $params;
public function __construct($formName=null,$params=[],$mapper=[]) {
parent::__construct($formName);
$this->mapper = $mapper;
$this->params = $params;
$this->setHydrator(new ClassMethodsHydrator(false));
$this->setInputFilter(new InputFilter());
$this->setAttribute('class', 'form-horizontal');
//$this->setOption('params', $params);
}
public function populateSelect(\Laminas\Form\Element\Select $selectName,$optionValues=[]){
$selectName->setValueOptions($optionValues);
}
public function addFieldset($fieldset,$options=[]){
$this->add([
'type' => $fieldset,
'options' => $options,
]);
}
public function addFieldsetWithParameters($fieldset,$options=[]){
$this->add([
'type' => get_class(new $fieldset()),
'options' => $options,
]);
}
public function addSubmitButton($name,$label,$id='',$className=''){
$this->add([
'name' => $name,
'type' => 'submit',
'attributes' => [
'value' => $label,
'id' => $id,
'class' => $className,
]
]);
}
public function addSelect($name,$label){
$this->add([
'name' => $name,
'type' => Select::class,
'options' => [
'label' => $label,
'value_options' => [
'0' => 'French',
'1' => 'English',
'2' => 'Japanese',
'3' => 'Chinese',
],
],
]);
}
public function addFile($name,$label,$id='',$attributes=[],$labelClass=''){
$this->add([
'name' => $name,
'type' => 'file',
'options' => [
'label' => $label,
'id' => $id,
'label_attributes' => [
'class' => $labelClass
],
],
'attributes' => $attributes,
]);
}
public function addHiddenElement($name,$attributes=[]){
$this->add([
'name' => $name,
'type' => Hidden::class,
'attributes' => $attributes,
]);
}
public function addText($name,$label,$id='',$attributes=[],$labelClass=''){
$this->add([
'name' => $name,
'type' => 'text',
'options' => [
'label' => $label,
'id' => $id,
'label_attributes' => [
'class' => $labelClass
],
],
'attributes' => $attributes,
]);
}
}
and my CommunFieldset :
<?php
/**
* #module Commun
* #subpackage Form
* #author Samuel NANGUI <nanguisamuel#gmail.com>
* #copyright Copyright (c) 2021 Nslabs
*/
namespace Commun\Form;
use Laminas\Form\Element\Select;
use Laminas\Form\Fieldset;
use Laminas\Form\Element\Checkbox;
use Laminas\Form\Element\MultiCheckbox;
use Laminas\Form\Element\Button;
use Laminas\Form\Element\Hidden;
class CommunFormFieldset extends Fieldset
{
/**
* Shortcut for adding an input type text element
* #param string $name name of the item
* #param string $label label of the item
* #param string $id unique HTML id of the item
* #param array $attributes array of attributes to apply to the item
*/
//public $additionnalParams;
private $mapper;
public function __construct($mapper=[],$name=null,$options = []) {
//$this->additionnalParams = $options;
$this->mapper = $mapper;
parent::__construct($name, $options);
}
public function init(){
parent::init();
}
/**
* Shortcut for adding an input type text element
* #param string $name name of the item
* #param string $label label of the item
* #param string $id unique HTML id of the item
* #param array $attributes array of attributes to apply to the item
* #param string $labelClass label class(espacially for required item)
*/
public function addHiddenElement($name,$attributes=[]){
$this->add([
'name' => $name,
'type' => Hidden::class,
'attributes' => $attributes,
]);
}
public function addText($name,$label,$id='',$attributes=[],$labelClass=''){
$this->add([
'name' => $name,
'type' => 'text',
'options' => [
'label' => $label,
'id' => $id,
'label_attributes' => [
'class' => $labelClass
],
],
'attributes' => $attributes,
]);
}
/**
* Shortcut for adding an input type text element
* #param string $name name of the item
* #param string $label label of the item
* #param string $id unique HTML id of the item
* #param array $attributes array of attributes to apply to the item
* #param string $labelClass label class(espacially for required item)
*/
public function addFile($name,$label,$id='',$attributes=[],$labelClass=''){
$this->add([
'name' => $name,
'type' => 'file',
'options' => [
'label' => $label,
'id' => $id,
'label_attributes' => [
'class' => $labelClass
],
],
'attributes' => $attributes,
]);
}
public function addTextarea($name,$label,$id='',$attributes=[],$labelClass=''){
$this->add([
'name' => $name,
'type' => 'textarea',
'options' => [
'label' => $label,
'id' => $id,
'label_attributes' => [
'class' => $labelClass
],
],
'attributes' => $attributes,
]);
}
/**
* Shortcut for adding a select list type element
* #param string $name name of the select item
* #param string $label label of the select item
* #param array $valueOptions array values to populate the Select with
* #param array $attributes array of attributes to apply to the Select item
* #param string $labelClass label class(espacially for required item)
*/
public function addSelect($name,$label,$valueOptions=[],$attributes=[],$labelClass=''){
$this->add([
'name' => $name,
'type' => Select::class,
'options' => [
'label' => $label,
'value_options' => $valueOptions,
'label_attributes' => [
'class' => $labelClass
],
],
'attributes' => $attributes,
]);
}
public function addSelectFromTable($name,$label,$type,$attributes=[],$labelClass=''){
$this->add([
'name' => $name,
'type' => get_class($type) ,
'options' => [
'label' => $label,
'label_attributes' => [
'class' => $labelClass
],
],
//'label_attributes' => ['class' => $labelClass],
'attributes' => $attributes,
]);
}
/**
* Shortcut for adding a select list type element
* #param string $name name of the select item
* #param string $label label of the select item
* #param string $id id of the select item
* #param string $checkedValue value of checked item.
* #param string $unCheckedValue value of unchecked item.
* #param array $attributes attribute array.
* #param string $labelClass label class(espacially for required item)
*/
public function addCheckbox($name,$label,$id='',$checkedValue='',$unCheckedValue='',$attributes=[],$labelClass=''){
$this->setLabelAttributes(['class' => $labelClass]);
$this->add([
'name' => $name,
'type' => Checkbox::class,
'options' => [
'label' => $label,
'id' => $id,
'use_hidden_element' => true,
'checked_value' => $checkedValue,
'unchecked_value' => $unCheckedValue,
'label_attributes' => [
'class' => $labelClass
],
],
'attributes' => $attributes,
]);
}
public function addMultiCheckbox($name,$label,$id='',$valueOptions=[],$attributes=[],$labelClass=''){
$this->add([
'name' => $name,
'type' => MultiCheckbox::class,
'options' => [
'label' => $label,
'id' => $id,
'value_options' => $valueOptions,
'label_attributes' => [
'class' => $labelClass
],
],
'attributes' => $attributes,
]);
}
public function addButton($name,$label,$attributes=[]){
$this->add([
'name' => $name,
'type' => Button::class,
'options' => [
'label' => $label,
],
'attributes' => $attributes,
]);
}
/**
* Shortcut for adding a collection list type element
* #param string $name name of the select item
* #param string $label label of the select item
* #param string $targetElement name of the target fieldset
* #param boolean $isObject indicate if the variable is an instance of a class or just a string
* #param int $count number of visible row
* #param boolean $shouldCreateTemplate indicate if the html markup must be created
* #param boolean $allowAdd indicate if new item can to addeds
*/
private function getStringFromElement($element){
if(gettype($element)==='object'){
return get_class($element);
}elseif(gettype($element)==='string'){
return $element;
}else{
throw new \Exception('This type cannot be used with collection element');
}
}
public function addCollection($name,$label, $targetElement,$count=2,$attributes=[],$templatePlaceholder='__index__',$shouldCreateTemplate=true,$allowAdd=true){
$this->add([
'type' => \Laminas\Form\Element\Collection::class,
'name' => $name,
'options' => [
'label' => $label,
'count' => $count,
'should_create_template' => $shouldCreateTemplate,
'template_placeholder' => $templatePlaceholder,
'allow_add' => $allowAdd,
'target_element' => [
'type' => $this->getStringFromElement($targetElement),
],
],
'attributes' => $attributes,
]);
}
}
When I do a var_dump in my init() function in EffetRapportFielset, I get this
And in the same page I get also this :
I need to say that when I do echo on $this->parameters on my RapportEffetForm I get my correct parameter value.
I do not know why for the first time, the value is good, and the (2nd time ??) is null. Do not know also why this value is shown more than once.
Here are all my infos. Hope it helps you to also help me finding a solution.
Best regards !

My intelligent guess is, that the problem is your CommunForm::addFieldsetWithParameters() method. You're loosing the parameters, since you'r creating the fieldset a second time, without the parameters getting passed again.
Just use Laminas\Form\Form::add() to add the fieldset:
$myFieldset = $this->getFormFactory()
->getFormElementManager()
->get(RapportEffetFieldset::class, ['params' => $this->parameters]);
$this->add($myFieldset);
And you do the same thing within the collection. Just pass the object to the collection there as "target_element":
$myFieldset = $this->getFormFactory()
->getFormElementManager()
->get(EffetRapportFieldset::class, ['params' => $this->params]);
$this->add([
'type' => \Laminas\Form\Element\Collection::class,
'name' => 'effets',
'options' => [
'label' => '',
'count' => 1,
'should_create_template' => false,
'template_placeholder' => '__index__',
'allow_add' => false,
'target_element' => $myFieldset,
],
'attributes' => []
]);

Related

Symfony2 Cannot instantiate interface Doctrine\Common\Collections\Collection

Symfony version 2.8
I have a problem when I try to add new Collection(); in construct function of User Entity.
public function __construct()
{
$this->sectors = new Collection();
parent::__construct();
}
Sector has many to many relationship
/**
* #ORM\ManyToMany(targetEntity="UserBundle\Entity\Sectors", fetch="EAGER")
* #ORM\JoinTable(
* joinColumns={#ORM\JoinColumn(onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(onDelete="CASCADE")}
* )
*/
public $sectors;
and getter/setter methods are
/**
* Add sector
*
* #param UserBundle\Entity\Sectors $sector
*
* #return User
*/
public function addSector(UserBundle\Entity\Sectors $sector)
{
$this->sectors[] = $sector;
return $this;
}
/**
* Remove sector
*
* #param UserBundle\Entity\Sectors $sector
*/
public function removeSector(UserBundle\Entity\Sectors $sector)
{
$this->sectors->removeElement($sector);
}
/**
* Get sectors
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSectors()
{
return $this->sectors;
}
When in a FormType I do:
$builder
->add('sectors', EntityType::class, array(
'class' => 'UserBundle\Entity\Sectors',
'placeholder' => 'Select Sector ...',
'label' => 'Sector',
'required' => false,
'attr' => ['placeholder' => 'Select Sector ...', 'data-jcf' => '{"wrapNative": false, "wrapNativeOnMobile": false, "useCustomScroll": true, "multipleCompactStyle": true}'],
'multiple' => true,
'expanded' => false,
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.name', 'ASC');
},
));
$formModify = function (FormInterface $form, \Doctrine\Common\Collections\ArrayCollection $sector, $factory) {
$output = [];
foreach($sector as $sec) {
$output[] = $sec->id;
}
$formOption = array(
'class' => 'UserBundle\Entity\UserAccreditation',
'multiple' => true,
'auto_initialize' => false,
'required' => false,
'expanded' => true,
'choice_attr' => function ($output) {
return ['class' => 'attr_checkbox'];
},
'query_builder' => function(EntityRepository $ertt) use ($output) {
$qb = $ertt->createQueryBuilder('g');
$qb->select(array('g'));
$qb->where('g.sector IN (:sector_id)');
$qb->setParameters( array('sector_id' => $output) );
$qb->orderBy('g.name', 'ASC');
return $qb;
},
);
$form->add($factory->createNamed('accreditationdata', EntityType::class, null, $formOption));
};
$builder->addEventListener(FormEvents::PRE_SET_DATA,function (FormEvent $event) use ($formModify,$factory) {
$data = $event->getData();
$form = $event->getForm();
if ($data != null) {
//print_r(get_object_vars($data->getSectors()));
$formModify($event->getForm(), $data->getSectors(),$factory);
}
}
);
$factory = $builder->getFormFactory();
$builder->get('sectors')->addEventListener(FormEvents::POST_SUBMIT,function (FormEvent $event) use ($formModify,$factory) {
$sector = $event->getForm()->getData();
//print_r($sector);
$formModify($event->getForm()->getParent(), $sector,$factory);
}
);
I get following error:
Fatal error: Cannot instantiate interface Doctrine\Common\Collections\Collection
Earlier I am using ArrayCollection instead of Collection, I have to do this because I am getting error
Type error: Argument 2 passed to UserBundle\Form\Type\ProfileAboutMeFormType::UserBundle\Form\Type{closure}() must be an instance of Doctrine\Common\Collections\ArrayCollection, instance of Doctrine\ORM\PersistentCollection given,
and by searching on google I found this solution on github link
https://github.com/doctrine/orm/issues/5946
but still I am facing the problem. can anyone tell me What goes wrong here ?

Symfony: Creating a new user results in overwriting of properties

When someone creates a new user on our application, some of his own properties get overwritten by the new users properties. I have no clue yet, where to look for the mistake, since in the controller or entities, nothing was changed.
Here are some information: the user entity (we are using the FOS User Bundle)
class User extends BaseUser{
/**
* #Solr\Id
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #Solr\Field(type="string")
* #Assert\NotBlank()
* #var string
* #ORM\Column(type="string", length=32, nullable=false)
*/
protected $firstName;
/**
* #Solr\Field(type="string")
* #Assert\NotBlank()
* #var string
* #ORM\Column(type="string", length=32, nullable=false)
*/
protected $lastName;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Agency", inversedBy="useragencies", cascade={"persist"})
* #ORM\JoinTable(name="user_user_agencies",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="iata8", referencedColumnName="iata8")})
* #var \AppBundle\Entity\Agency
**/
private $agencies;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Product", inversedBy="users", cascade={"persist"})
* #ORM\JoinTable(name="user_user_products",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="product_id", referencedColumnName="id")})
* #var \AppBundle\Entity\Product
**/
private $products;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Market", inversedBy="users", cascade={"persist"})
* #ORM\JoinTable(name="user_user_markets",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="market_id", referencedColumnName="id")})
* #var \AppBundle\Entity\Market
* #Solr\Field(type="string", getter="getId")
**/
private $markets;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Airline", inversedBy="users", cascade={"persist"})
* #ORM\JoinTable(name="user_user_airlines",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="airline_id", referencedColumnName="id")})
* #var \AppBundle\Entity\Airline
* #Solr\Field(type="string", getter="getId")
**/
private $airlines;
...
The properties that get overwritten are products and airlines. There is no prePersist() or preUpdate() function for this entity!
The create controller
class CreateController extends Controller
{
/**
* #Security("has_role('ROLE_USER_INVITER')")
* #Route("/user/create/{employer}", defaults={"employer": 1}
* , requirements={"employer": "\d+"}, name="userBundle_create")
*/
public function createAction($employer, Request $request)
{
$currentUser=$this->container->get('security.token_storage')->getToken()->getUser();
// get employer Object
$em = $this->getDoctrine ()->getManager ();
$repository = $this->getDoctrine()
->getRepository('UserBundle:Employer');
$employerObj = $repository->findOneByIdInContext($employer, $currentUser);
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->createUser();
$url = $this->get('router')->generate('userBundle_create', array(
'employer' => $employerObj->getId()
));
// generate form and handle
$form = $this->createForm(CreateType::class, $user
, array('employer' => $employerObj,
'action' => $url,)
);
$form->handleRequest($request);
if ($form->isValid()) {
$tokenGenerator = $this->container->get('fos_user.util.token_generator');
$user->setConfirmationToken($tokenGenerator->generateToken());
$user->setUsername($user->getEmail());
$user->setEnabled(false);
$user->setApprover($currentUser);
$user->setInviter($currentUser);
$user->addRole($user->getMainRole()->getName());
$userManager->updateUser($user);
if(count($user->getAgencies()) > 0){
$userId = rtrim($user->getId(),"_user");
$query = $em->createQuery("SELECT DISTINCT (a.market) FROM UserBundle\Entity\User u JOIN u.agencies a WHERE u.id = $userId");
$marketIds = $query->getResult();
$em = $this->getDoctrine ()->getManager ();
$repository = $this->getDoctrine()
->getRepository('AppBundle:Market');
$markets = $repository->findOneById($marketIds[0]);
$user->addMarket($markets);
$userManager->updateUser($user);
}
$this->addFlash(
'success',
'The user was created and an activation email was sent!'
);
return $this->redirectToRoute('userBundle_list');
}
return $this->render('UserBundle:User:create.html.twig', array(
'form' => $form->createView(),
'user'=>$user,
));
}
}
Here are more classes that may be useful for helping to point me in the right direction.
CreateType
class CreateType extends AbstractType
{
private $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class,
'employer' => null
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$employer = $options['employer'];
$builder
->add('firstName', 'text', array('label' => 'label.firstname',
'translation_domain' => 'User',))
->add('lastName', 'text', array('label' => 'label.lastname',
'translation_domain' => 'User',))
;
$user = $this->tokenStorage->getToken()->getUser();
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($user, $employer){
$form = $event->getForm();
// show iata selection if empoyer is any agency
$employerArr = array(10, 11);
if (in_array($employer->getId(), $employerArr)) {
// only show iata based on user's employer
if($user->hasRoles(array('ROLE_AGENCY_TC_ONLY',
'ROLE_AGENCY_WAIVER_REQUEST_ONLY',
'ROLE_AGENCY_CORE_TEAM',
'ROLE_AGENCY',
'ROLE_AGENCY_MANAGEMENT',
'ROLE_AGENCY_SIGNEE','ROLE_CORPORATION_TRAVEL_MANAGER' ))){
$form
->add('agencies', EntityType::class, array(
'class' => 'AppBundle:Agency',
'query_builder' => function (EntityRepository $er) use ($user) {
return $er->createQueryBuilder('a')
->addOrderBy('a.id', 'ASC')
->andWhere('a.id IN (:ids)')
->setParameter('ids',$user->getAgencies());
},
'choice_label' => 'agencyName',
// 'data' => $user->getAgencies(),
'label' => 'label.iata',
'empty_value' => "label.select.agency",
'property' => 'id',
'expanded' => false, 'multiple' => true,
'required' => true,
'translation_domain' => 'User',
'choice_translation_domain' => 'User'));
} else {
// only show iata based on user's context
$form
->add('agencies', EntityType::class, array(
'class' => 'AppBundle:Agency',
'query_builder' => function (EntityRepository $er) use ($user) {
return $er->createQueryBuilder('a')
->addOrderBy('a.id', 'ASC')
->andWhere('a.market IN (:markets)')
->setParameter('markets',$user->getMarkets());
},
'choice_label' => 'agencyName',
'label' => 'label.iata',
'empty_value' => "label.select.agency",
'property' => 'id',
'expanded' => false, 'multiple' => true,
'required' => true,
'translation_domain' => 'User',
'choice_translation_domain' => 'User'));
}
// show market only if not agency user
} else {
// only show specific markets based on user's context
$form->add('markets', 'entity', array(
'class' => 'AppBundle:Market', 'property' => 'id',
'query_builder' => function (EntityRepository $er) use ($user) {
$markets = $user->getMarkets();
return $er->createQueryBuilder('m')
->addOrderBy('m.id', 'ASC')
->andWhere('m.id IN (?1)')
->setParameter(1,$markets);
},
// 'choice_value' => 'id',
'choice_label' => 'id', 'label' => 'label.markets',
'translation_domain' => 'User',
'expanded' => false, 'multiple' => true,));
}
// only show specific roles based on user's employer
$form->add('mainRole', 'entity', array(
'class' => 'UserBundle:Role',
'query_builder' => function (EntityRepository $er) use ($employer){
$roles = $employer->getRoles();
return $er->createQueryBuilder('r')
->orderBy('r.sort', 'ASC')
->andWhere('r.id IN (?1)')
->setParameter(1,$roles);
},
'choice_label' => 'translationKey',
'choices_as_values' => true, 'label' => 'label.role',
'expanded' => true, 'multiple' => false,
'translation_domain' => 'User',
'choice_translation_domain' => 'Role',));
// only show specific airlines based on user's context
$form->add('airlines', 'entity', array(
'class' => 'AppBundle:Airline', 'property' => 'id',
'query_builder' => function (EntityRepository $er) use ($user) {
$airlines = $user->getAirlines();
return $er->createQueryBuilder('a')
->addOrderBy('a.id', 'ASC')
->andWhere('a.id IN (?1)')
->setParameter(1,$airlines);
},
'choice_value' => 'id',
'data' => $user->getAirlines(),
'choice_label' => 'id', 'label' => 'label.airlines',
'translation_domain' => 'User',
'expanded' => false, 'multiple' => true,));
// only show specific products based on user's context
$form->add('products', 'entity', array(
'class' => 'AppBundle:Product', 'property' => 'id',
'query_builder' => function (EntityRepository $er) use ($user) {
$products = $user->getProducts();
return $er->createQueryBuilder('p')
->addOrderBy('p.id', 'ASC')
->andWhere('p.id IN (?1)')
->setParameter(1,$products);
},
'choice_value' => 'id',
'data' => $user->getProducts(),
'choice_label' => 'translationKey', 'label' => 'label.products',
'translation_domain' => 'User',
'expanded' => false, 'multiple' => true,
'choice_translation_domain' => 'AppBundle',));
});
}
public function getParent()
{
return 'FOS\UserBundle\Form\Type\RegistrationFormType';
}
public function getBlockPrefix()
{
return 'userBundle_create';
}
}
Your issue is caused by these to lines:
'data' => $user->getAirlines(),
and
'data' => $user->getProducts(),
To change the new user s airlines & products collection, symfony form uses the loggedin users airlines & products collection reference.
Clone the collection when setting it as default, to remove the reference to the logged in user.
'data' => clone $user->getAirlines(),
and
'data' => clone $user->getProducts(),
Hope it helps.
Wrong assumption: Your error is in CreateType class. You use the loggedin user s properties to populate agencies, airlines and products fields of your form:
$user = $this->tokenStorage->getToken()->getUser();
...
'query_builder' => function (EntityRepository $er) use ($user) {
You should instead use the user you edit. Add in your buildForm function:
$userEdited = $builder->getData();
and then change:
'query_builder' => function (EntityRepository $er) use ($userEdited) {
in all places.
Do not forget to change also:
$user->getMarkets()
to
$userEdited->getMarkets()
in your callbacks, same for ailines & products.

many to many save data

I have two entity that have manytomany relation
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Esame
*
* #ORM\Table(name="esame", indexes={#ORM\Index(name="id_tipologia_esame", columns={"id_tipologia_esame"}), #ORM\Index(name="id_analisi", columns={"id_analisi"})})
* #ORM\Entity(repositoryClass="AppBundle\Repository\EsameRepository")
*/
class Esame
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \AppBundle\Entity\Nome_esame
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Nome_esame")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id_tipologia_esame", referencedColumnName="id")
* })
*/
private $idTipologiaEsame;
/**
* #var \AppBundle\Entity\Analisi
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Analisi")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id_analisi", referencedColumnName="id")
* })
*/
private $idAnalisi;
/**
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\TipologiaCampione", inversedBy="esami")
*/
private $campioni;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set idAnalisi
*
* #param \AppBundle\Entity\Analisi $idAnalisi
*
* #return Esame
*/
public function setIdAnalisi($idAnalisi)
{
$this->idAnalisi = $idAnalisi;
return $this;
}
/**
* Get idAnalisi
*
* #return int
*/
public function getIdAnalisi()
{
return $this->idAnalisi;
}
/**
* Constructor
*/
public function __construct()
{
$this->campioni = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add campioni
*
* #param \AppBundle\Entity\TipologiaCampione $campioni
*
* #return Esame
*/
public function addCampioni(\AppBundle\Entity\TipologiaCampione $campioni)
{
$this->campioni[] = $campioni;
return $this;
}
/**
* Remove campioni
*
* #param \AppBundle\Entity\TipologiaCampione $campioni
*/
public function removeCampioni(\AppBundle\Entity\TipologiaCampione $campioni)
{
$this->campioni->removeElement($campioni);
}
/**
* Get campioni
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCampioni()
{
return $this->campioni;
}
/**
* Set idTipologiaEsame
*
* #param \AppBundle\Entity\Nome_esame $idTipologiaEsame
*
* #return Esame
*/
public function setIdTipologiaEsame(\AppBundle\Entity\Nome_esame $idTipologiaEsame = null)
{
$this->idTipologiaEsame = $idTipologiaEsame;
return $this;
}
/**
* Get idTipologiaEsame
*
* #return \AppBundle\Entity\Nome_esame
*/
public function getIdTipologiaEsame()
{
return $this->idTipologiaEsame;
}
}
and Entity 2
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* TipologiaCampione
*
* #ORM\Table(name="tipologia_campione")
* #ORM\Entity(repositoryClass="AppBundle\Repository\TipologiaCampioneRepository")
*/
class TipologiaCampione
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="tipologia", type="string", length=255, nullable=true)
*/
private $tipologia;
/**
* #var string
*
* #ORM\Column(name="matricola", type="string", length=255, nullable=true)
*/
private $matricola;
/**
* #var string
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Esame",mappedBy="campioni")
*/
private $esami;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set tipologia
*
* #param string $tipologia
*
* #return TipologiaCampione
*/
public function setTipologia($tipologia)
{
$this->tipologia = $tipologia;
return $this;
}
/**
* Get tipologia
*
* #return string
*/
public function getTipologia()
{
return $this->tipologia;
}
/**
* Set matricola
*
* #param string $matricola
*
* #return TipologiaCampione
*/
public function setMatricola($matricola)
{
$this->matricola = $matricola;
return $this;
}
/**
* Get matricola
*
* #return string
*/
public function getMatricola()
{
return $this->matricola;
}
/**
* Constructor
*/
public function __construct()
{
$this->esami = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add esami
*
* #param \AppBundle\Entity\Esame $esami
*
* #return TipologiaCampione
*/
public function addEsami(\AppBundle\Entity\Esame $esami)
{
$this->esami[] = $esami;
return $this;
}
/**
* Remove esami
*
* #param \AppBundle\Entity\Esame $esami
*/
public function removeEsami(\AppBundle\Entity\Esame $esami)
{
$this->esami->removeElement($esami);
}
/**
* Get esami
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEsami()
{
return $this->esami;
}
}
now i must save data and in my controller i write this:
for($i=0;$i<$form->get('numero_campioni')->getData();$i++) {
$campione=new TipologiaCampione();
$campione->setMatricola($form['matricola_'.$i]->getData());
$campione->setTipologia($form['tipologia_'.$i]->getData());
foreach($form['esame_'.$i]->getData() as $value){
$tipo_esame = $this->getDoctrine()
->getRepository('AppBundle:nome_esame')
->find($value->getId());
$esame=new Esame();
$esame->setIdAnalisi($analisi);
$esame->setIdTipologiaEsame($tipo_esame);
$em->persist($esame);
$em->flush();
$campione->addEsami($esame); -> this don't work
}
$em->persist($campione);
$em->flush();
}
I expect that $campione->addEsami($esame); creates a new record in my table esame_tipologia_campione for each $campione but it doesn't work ..
My form Type:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Validator\Constraints\DateTime;
use AppBundle\Entity\anagrafica;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use AppBundle\Form\anagraficaType;
use Symfony\Component\Form\Extension\Core\Type\CurrencyType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use AppBundle\Form\EsameType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class AnalisiType extends AbstractType {
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$province = array(
'AG' => 'Agrigento',
'AL' => 'Alessandria',
'AN' => 'Ancona',
);
$builder->add('ruminanti', ChoiceType::class, array(
'label' => false,
'mapped' => false,
'placeholder' => 'Tipologia di modulo',
'choices' => array('Ruminanti' => 'Ruminanti', 'Suini' => 'Suini'),
'required' => true,
'data' => ($options['data']->getTipoModulo() != NULL ? $options['data']->getTipoModulo() : ''),
'attr' => array(
'placeholder' => 'Provincia',
)))
->add('idLaboratorio', EntityType::class, array(
'label' => false,
'placeholder' => 'Laboratorio a cui inviare i dati',
'class' => 'AppBundle:Laboratorio',
'choice_label' => 'nome',
// 'data'=>5
))
// Dati proprietario
->add('privato', ChoiceType::class, array(
'label' => false,
'choices' => array('Privato' => 'Privato', 'Azienda' => 'Azienda'),
'data' => 'Privato',
'expanded' => true,
'multiple' => false,
'mapped' => false,
))
->add('Nome_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getNome() : ''),
'attr' => array(
'placeholder' => 'Nome',
'novalidate' => 'novalidate'
)))
->add('Cognome_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getCognome() : ''),
'attr' => array(
'placeholder' => 'Cognome',
'novalidate' => 'novalidate'
)))
->add('Ragione_sociale_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'required' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getRagioneSociale() : ''),
'attr' => array(
'placeholder' => 'Ragione Sociale',
'novalidate' => 'novalidate'
)))
->add('Via_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getvia() : ''),
'attr' => array(
'placeholder' => 'Via'
)))
->add('Comune_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getComune() : ''),
'attr' => array(
'placeholder' => 'Comune'
)))
->add('Provincia_proprietario', ChoiceType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getProvincia() : ''),
'choices' => $province,
'placeholder' => 'Provincia'
))
->add('Telefono_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->gettel() : NULL),
'attr' => array(
'placeholder' => 'Telefono'
)))
->add('email_proprietario', EmailType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getemail() : ''),
'attr' => array(
'placeholder' => 'E-mail'
)
))
->add('Cod_allev_proprietario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdProprietario() != NULL ? $options['data']->getIdProprietario()->getCodiceAllievo() : ''),
'attr' => array(
'placeholder' => 'Codice Allevamento'
)))
// Dati Veterinario
->add('Nome_veterinario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdProprietario()->getNome() : ''),
'attr' => array(
'placeholder' => 'Nome'
)))
->add('Cognome_veterinario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdProprietario()->getCognome() : ''),
'attr' => array(
'placeholder' => 'Cognome'
)))
->add('Via_veterinario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdVeterinario()->getvia() : ''),
'attr' => array(
'placeholder' => 'Via'
)))
->add('Comune_veterinario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdVeterinario()->getComune() : ''),
'attr' => array(
'placeholder' => 'Comune'
)))
->add('Provincia_veterinario', ChoiceType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdVeterinario()->getProvincia() : ''),
'choices' => $province,
'attr' => array(
'placeholder' => 'Provincia'
)))
->add('Telefono_veterinario', TextType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdVeterinario()->getTel() : NULL),
'attr' => array(
'placeholder' => 'Telefono'
)))
->add('email_veterinario', EmailType::class, array(
'label' => false,
'mapped' => false,
'data' => ($options['data']->getIdVeterinario() != NULL ? $options['data']->getIdVeterinario()->getEmail() : ''),
'attr' => array(
'placeholder' => 'E-mail'
)
))
->add('trattamenti', TextareaType::class, array(
'label' => false,
'attr' => array(
'placeholder' => 'Trattamenti(inserire ANAMNESI; SINTOMATOLOGIA; TRATTAMENTI)'
)
))
->add('vacinazione', TextareaType::class, array(
'label' => false,
'attr' => array(
'placeholder' => 'Vacinazioni(obbligatorio)'
)
))
->add('numero_campioni', NumberType::class, array(
'label' => false,
'attr' => array(
'placeholder' => 'Numero Totale di campioni'
)
));
//->add('save', SubmitType::class, array('label' => 'Create Task'));
$builder->add('idTipologiaEsame', EntityType::class, array(
'label' => false,
'mapped' => false,
'class' => 'AppBundle:Nome_esame',
'choice_label' => 'nome',
'group_by' => 'idCategoriaEsame.tipo',
))
->add('Aggiungi', ButtonType::class, array(
'attr' => array(
'class' => 'btn-primary col-md-2 conferma_esame'),
))
->add('Rimuovi', ButtonType::class, array(
'attr' => array(
'class' => 'btn-primary col-md-2 conferma_esame'),
));
// for($i=0;$i<$options['data']->getNumeroCampioni();$i++){
for ($i = 0; $i < 60; $i++) {
$builder->add('checkbox_' . $i, CheckboxType::class, array(
'label' => false,
'required' => false,
'mapped' => false,
'attr' => array(
'class' => 'check_box_table',
// 'class'=>'col-md-1 col-xs-3 allineare_sinistra',
)
))
->add('matricola_' . $i, TextType::class, array(
'label' => false,
'mapped' => false,
'required' => false,
'attr' => array(
'placeholder' => 'Matricola (FACOLTATIVA)',
// 'class'=>'col-md-2 col-xs-9 allineare_sinistra',
)))
->add('tipologia_' . $i, TextType::class, array(
'label' => false,
'mapped' => false,
'required' => false,
'attr' => array(
'placeholder' => 'Tipologia (FACOLTATIVA)',
// 'class'=>'col-md-2 col-md-offset-0 col-xs-9 col-xs-offset-3 allineare_sinistra',
)))
->add('esame_' . $i, EntityType::class, array(
'label' => false,
'mapped' => false,
'class' => 'AppBundle:Nome_esame',
'required'=>true,
'multiple'=>true,
'choice_label' => 'nome',
// 'disabled' => 'disabled',
'attr' => array(
'placeholder' => 'Esami',
'class' => 'max_width esame_row select_esame',
// 'class'=>'col-md-12 col-md-offset-0 col-xs-9 col-xs-offset-3 ',
)
))
->add('Stampa', ButtonType::class, array(
'disabled' => 'disabled',
'attr' => array(
'class' => 'btn-primary text-center',
)
))
->add('saveAndAdd', SubmitType::class, array('label' => 'Save and Add'))
;
}
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Analisi'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix() {
return 'appbundle_analisi';
}
}
$esame entity and $campione entity are correctly saved.
Can anybody say to me what I'm doing wrong??
You need to create a Join Table
After that you need to choose which entity is the owner of the association (just after the manytomany chapter in the doc).
For exampre, if you may want to add "campioni" via the "esami" entity you should code a setter like this:
public function addCampioni(\AppBundle\Entity\TipologiaCampione($campioni) {
$campioni->addEsami($this);
$this->campioni[] = $campioni;
return $this;
}
Ciao!

Controller - No access in class - Entity

I got this error message, but I don't really understand why.
Neither the property "categories" nor one of the methods "addCategory()"/"removeCategory()", "setCategories()", "categories()", "__set()" or "__call()" exist and have public access in class "Checkout\Bundle\ItemBundle\Entity\Item".
The thing is, in my entity "Item" I really have all of this stuff:
/**
* #ORM\ManyToMany(targetEntity="Checkout\Bundle\ItemBundle\Entity\Category", mappedBy="items")
**/
private $categories;
and
/**
* Add categories
*
* #param Category $categories
* #return Item
*/
public function addCategory(Category $categories)
{
$this->categories[] = $categories;
return $this;
}
/**
* Remove categories
*
* #param Category $categories
*/
public function removeCategory(Category $categories)
{
$this->categories->removeElement($categories);
}
/**
* Get categories
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCategories()
{
return $this->categories;
}
Okay, okay - and what is in my Controller?
/**
* Creates a new Item entity.
*
* #Route("/create", name="item_create")
* #param Request $request
* #return \Symfony\Component\HttpFoundation\Response
*/
public function createAction(Request $request)
{
$entity = new Item();
$currentUser = $this->getUser();
$form = $this->createFormBuilder($entity)
->add('name', null, array(
'label' => 'Item Name',
'required' => true,
))
->add('categories', 'entity', array(
'label' => 'Select a Category',
'required' => false,
'class' => 'CheckoutItemBundle:Category',
'property' => 'name',
'query_builder' => function (EntityRepository $er) use ($currentUser) {
return $er->createQueryBuilder('c')
->where('c.user = :user')
->setParameter('user', $currentUser);
},
))
->add('submit', 'submit', array('label' => 'Speichern'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
}
return $this->render(
'CheckoutItemBundle:Item:create.html.twig',
array(
'entity' => 'entity',
'form' => $form->createView()
)
);
}
So, the big question is, why he say that he didn't find it, when it is obviously there. Any idea? Thank you in advance!
->add('categories', 'entity', array(
'label' => 'Select a Category',
'required' => false,
'class' => 'CheckoutItemBundle:Category',
'property' => 'name',
'multiple' => true,
'query_builder' => function (EntityRepository $er) use ($currentUser) {
return $er->createQueryBuilder('c')
->where('c.user = :user')
->setParameter('user', $currentUser);
},
))
You have a Many-To-Many relation, but your form expects a Many-To-One. To fix this behavior need to set multiple to true.

Symfony2 simple many-to-many issue

I have a simple question,
I have two tables in relation many to many, Post and Category,
in an intact form PostType a collection of form CategoryType, but here the problems begin ..
I followed the instructions on the cookbook collection form to persist the data, I just do not get the desired result ..
Here's the code:
class Post
{
/**
*
* #ORM\ManyToMany(targetEntity="Categories", inversedBy="posts", cascade={"persist", "remove"})
* #ORM\JoinTable(name="AnCat",
* joinColumns={
* #ORM\JoinColumn(name="post_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="categories_id", referencedColumnName="id")
* }
* )
**/
protected $categories;
public function __construct()
{
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addCategory($categories)
{
foreach ($categories as $category) {
$category->addPosts($this);
}
$this->categories[] = $categories;
}
class Categories
{
/**
*
* #ORM\ManyToMany(targetEntity="Post", mappedBy="categories")
*/
protected $posts;
public function __construct()
{
$this->posts = new ArrayCollection();
}
/**
*
* #param Post $post
* #return Categories
*/
public function addPosts(Post $posts)
{
// I tried it but I get the same result!
/*if (!$this->posts->contains($posts)) {
$this->posts->add($posts);
}*/
$posts->addCategory($this);
$this->posts[] = $posts;
}
class PostType extends AbstractType
{
->add('Categories', 'collection', array('type' => new CategoriesType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'prototype_name' => '__categ__',
'by_reference' => false
))
class CategoriesType extends AbstractType
{
->add('category', 'entity', array(
'attr' => array('class' => 'cat'),
'class' => 'MyBusinessBundle:Categories',
'property' => 'category',
'label' => 'Categories'
))
The problem is that inserts a new field Category, instead of creating a simple relationship Post-Category.
I don't understand where I'm wrong ..
In your postType, change collection type into entity Type
class PostType extends AbstractType
{
$builder->add('Categories', 'entity',
array( 'label' => 'Categories',
'required' => false,
'expanded' => true,
'class' => 'xxx\xxxBundle\Entity\Categories',
'property' => 'title',
'multiple' => true,
));
In your post creation form you will have checkboxes with categories. If you want a multi select field, change expanded by false

Resources