symfony2 validation of child entity prevents editing of parent entity - forms

I have run into this problem with a couple of my entities now so I thought to try and get a hang of what really goes on, and I turn to my best source here (will add a bounty to this question as soon as it is eligible).
My user is part of a user group. I have a validator for the userGroup entity to make sure no two userGroups have the same name.
The problem is that when I go to editing a user, and try to select that userGroup for the user, symfony2 is behaving as if I were trying to create another userGroup with that same name, when in reality all I am doing is I am trying to select that userGroup for the user.
A user entity
<?php
// src/BizTV/UserBundle/Entity/User.php
namespace BizTV\UserBundle\Entity;
use BizTV\UserBundle\Validator\Constraints as BizTVAssert;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use BizTV\BackendBundle\Entity\company as company;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser implements AdvancedUserInterface
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
//TODO: Add constraint on $name * #BizTVAssert\NameExists (and finish coding this constraint)
/**
* #var object BizTV\BackendBundle\Entity\company
*
* #ORM\ManyToOne(targetEntity="BizTV\BackendBundle\Entity\company")
* #ORM\JoinColumn(name="company", referencedColumnName="id", nullable=false)
*/
protected $company;
/**
* #var object BizTV\UserBundle\Entity\UserGroup
* #ORM\ManyToOne(targetEntity="BizTV\UserBundle\Entity\UserGroup")
* #ORM\JoinColumn(name="userGroup", referencedColumnName="id", nullable=true)
*/
protected $userGroup;
/**
* #ORM\ManyToMany(targetEntity="BizTV\ContainerManagementBundle\Entity\Container", inversedBy="users")
* #ORM\JoinTable(name="access")
*/
private $access;
/**
* #var object BizTV\ContainerManagementBundle\Entity\Container
*
* This only applies to the BizTV server user accounts or "screen display accounts". Others will have null here.
*
* #ORM\ManyToOne(targetEntity="BizTV\ContainerManagementBundle\Entity\Container")
* #ORM\JoinColumn(name="screen", referencedColumnName="id", nullable=true)
*/
protected $screen;
/**
* #ORM\Column(type="boolean", nullable=true)
*/
protected $isServer;
public function __construct()
{
parent::__construct();
$this->access = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set company
*
* #param BizTV\BackendBundle\Entity\company $company
*/
public function setCompany(\BizTV\BackendBundle\Entity\company $company)
{
$this->company = $company;
}
/**
* Get company
*
* #return BizTV\BackendBundle\Entity\company
*/
public function getCompany()
{
return $this->company;
}
/**
* Add access
*
* #param BizTV\ContainerManagementBundle\Entity\Container $access
*/
public function addContainer(\BizTV\ContainerManagementBundle\Entity\Container $access)
{
$this->access[] = $access;
}
/**
* Get access
*
* #return Doctrine\Common\Collections\Collection
*/
public function getAccess()
{
return $this->access;
}
/**
* Set screen
*
* #param BizTV\ContainerManagementBundle\Entity\Container $screen
*/
public function setScreen(\BizTV\ContainerManagementBundle\Entity\Container $screen)
{
$this->screen = $screen;
}
/**
* Get screen
*
* #return BizTV\ContainerManagementBundle\Entity\Container
*/
public function getScreen()
{
return $this->screen;
}
/**
* Set isServer
*
* #param boolean $isServer
*/
public function setIsServer($isServer)
{
$this->isServer = $isServer;
}
/**
* Get isServer
*
* #return boolean
*/
public function getIsServer()
{
return $this->isServer;
}
/**
* Set userGroup
*
* #param BizTV\UserBundle\Entity\UserGroup $userGroup
*/
public function setUserGroup(\BizTV\UserBundle\Entity\UserGroup $userGroup = null)
{
$this->userGroup = $userGroup;
}
/**
* Get userGroup
*
* #return BizTV\UserBundle\Entity\UserGroup
*/
public function getUserGroup()
{
return $this->userGroup;
}
}
The UserGroup entity that the User is linked to:
<?php
namespace BizTV\UserBundle\Entity;
use BizTV\UserBundle\Validator\Constraints as BizTVAssert;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* BizTV\UserBundle\Entity\UserGroup
*
* #ORM\Table()
* #ORM\Entity
*/
class UserGroup
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $name
* #BizTVAssert\NameExists
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotBlank(message = "Du måste ange ett gruppnamn")
*/
private $name;
/**
* #var object BizTV\BackendBundle\Entity\company
*
* #ORM\ManyToOne(targetEntity="BizTV\BackendBundle\Entity\company")
* #ORM\JoinColumn(name="company", referencedColumnName="id", nullable=false)
*/
protected $company;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set company
*
* #param BizTV\BackendBundle\Entity\company $company
*/
public function setCompany(\BizTV\BackendBundle\Entity\company $company)
{
$this->company = $company;
}
/**
* Get company
*
* #return BizTV\BackendBundle\Entity\company
*/
public function getCompany()
{
return $this->company;
}
}
The NameExistsValidator
<?php
namespace BizTV\UserBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use Doctrine\ORM\EntityManager as EntityManager;
class NameExistsValidator extends ConstraintValidator
{
private $container;
private $em;
public function __construct(Container $container, EntityManager $em) {
$this->container = $container;
$this->em = $em;
}
public function isValid($value, Constraint $constraint)
{
$em = $this->em;
$container = $this->container;
$company = $this->container->get('security.context')->getToken()->getUser()->getCompany();
//Fetch entities with same name
$repository = $em->getRepository('BizTVUserBundle:UserGroup');
//$repository = $this->getDoctrine()->getRepository('BizTVContainerManagementBundle:Container');
$query = $repository->createQueryBuilder('c')
->where('c.company = :company')
->setParameter('company', $company)
->orderBy('c.name', 'ASC')
->getQuery();
$groups = $query->getResult();
foreach ($groups as $g) {
if ($g->getName() == $value) {
$this->setMessage('Namnet '.$value.' är upptaget, vänligen välj ett annat', array('%string%' => $value));
return false;
}
}
return true;
}
}
User edit form
<?php
namespace BizTV\UserBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\CallbackValidator;
use Symfony\Component\Form\FormValidatorInterface;
use Symfony\Component\Form\FormError;
use Doctrine\ORM\EntityRepository;
class editUserType extends AbstractType
{
function __construct($company)
{
$this->company = $company;
}
public function buildForm(FormBuilder $builder, array $options)
{
$company = $this->company;
$builder
->add('locked', 'checkbox', array('label' => 'Kontot är låst, användaren kan inte logga in '))
->add('username', 'text', array('label' => 'Användarnamn '))
;
$builder
->add('userGroup', 'entity', array(
'label' => 'Användargrupp',
'empty_value' => 'Ingen grupptillhörighet',
'property' => 'name',
'class' => 'BizTV\UserBundle\Entity\UserGroup',
'query_builder' => function(\Doctrine\ORM\EntityRepository $er) use ($company) {
$qb = $er->createQueryBuilder('a');
$qb->where('a.company = :company');
$qb->setParameters( array('company' => $company) );
$qb->orderBy('a.name', 'ASC');
return $qb;
}
));
$builder
->add('email', 'email', array('label' => 'Epost '))
->add('plainPassword', 'repeated', array('type' => 'password', 'first_name' => 'Nytt lösenord ', 'second_name' => 'Upprepa lösenord ',));
$builder
->add('roles', 'choice', array(
'label' => 'Roller',
'expanded' => true,
'multiple' => true,
'choices' => array(
'ROLE_CONTENT' => 'Innehåll (Användaren kan lägga till, redigera och ta bort innehåll där du nedan beviljar åtkomst)',
'ROLE_LAYOUT' => 'Skärmlayout (Användaren kan skapa ny skärmlayout, redigera befintlig eller ta bort gällande skärmlayout där du nedan beviljar åtkomst)',
'ROLE_VIDEO' => 'Videouppladdning (Användaren har rätt att ladda upp videofiler till företagets mediabibliotek)',
'ROLE_ADMIN' => 'Administratör (Användaren är administratör med fulla rättigheter till allt precis som det konto du nu är inloggad på, var mycket restriktiv med att tilldela denna behörighet).',
),
))
;
$builder
->add('access', 'entity', array(
'label' => 'Behörigheter',
'multiple' => true, // Multiple selection allowed
'expanded' => true, // Render as checkboxes
'property' => 'select_label',
'class' => 'BizTV\ContainerManagementBundle\Entity\Container',
'query_builder' => function(\Doctrine\ORM\EntityRepository $er) use ($company) {
$qb = $er->createQueryBuilder('a');
$qb->innerJoin('a.containerType', 'ct');
$qb->where('a.containerType IN (:containers)', 'a.company = :company');
$qb->setParameters( array('containers' => array(1,2,3,4), 'company' => $company) );
$qb->orderBy('ct.id', 'ASC');
return $qb;
}
));
$builder-> addValidator(new CallbackValidator(function(FormInterface $form){
$email = $form->get('email')->getData();
if (empty( $email )) {
$form['email']->addError(new FormError("Du måste ange en epostadress för användaren"));
}
}));
$builder-> addValidator(new CallbackValidator(function(FormInterface $form){
$username = $form->get('username')->getData();
if (strpos($username,'#') !== false) {
$form['username']->addError(new FormError("Användarnamnet får inte innehålla tecknet #"));
}
}));
$builder-> addValidator(new CallbackValidator(function(FormInterface $form){
$username = $form->get('username')->getData();
if (empty($username)) {
$form['username']->addError(new FormError("Du måste ange ett namn för användaren"));
}
}));
//TODO check if username exists
}
public function getName()
{
return 'biztv_userbundle_newusertype';
}
}

Your NameExistsValidator does this:
Fail if I find any user-group with the name I'm checking.
But I think you want it to do this:
Fail if I find another user-group with the name I'm checking.
In other words: the validator needs the complete UserGroup entity (or at least its id and name) to check for a user-group with the same name but different id.
Symfony 2 already has a UniqueEntity validator, why don't you use it?
Using annotations this would look something like this:
/**
* #ORM\Entity
* #AssertUniqueEntity(fields={"name"}, message="This name already exists")
*/
class UserGroup
{

One possible and simplest solution is to define Validation Groups. For example, when you create a group, you can use the validation group named 'create' or 'groups' and when you create a user does not specify a group. Then validator will not apply to user creation process.
Validation Groups can be assigned dynamically in the form class. An example of this you can see in the documentation.

Related

symfony 3 form entity returning converting error

My form is returning the following error:
An exception occurred while executing 'UPDATE user_info SET
country_of_residence = ?, want_children = ?, salary = ? WHERE id = ?'
with params [{}, "a", "0", 22]:
Catchable Fatal Error: Object of class AppBundle\Entity\Country could
not be converted to string
My UserInfoType:
<?php
// src/AppBundle/Form/UserInfoType.php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
class UserInfoType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('first_name', TextType::class, array('label' => 'Prénom'))
->add('surname', TextType::class, array('label' => 'Nom'))
->add('nationality', TextType::class, array('label' => 'Nationalité'))
->add('country_of_residence', EntityType::class, array(
'class' => 'AppBundle:Country',
'choice_label' => 'name',
))
->add('maritial_status', TextType::class, array('label' => 'Votre statut maritial'))
->add('ethnique_origin', TextType::class, array('label' => 'Origine ethinique'))
->add('spoken_language', TextType::class, array('label' => 'Langues parlés'))
->add('children', TextType::class, array('label' => 'Possèdez vous des enfants'))
->add('want_children', TextType::class, array('label' => 'Désirez vous des enfants'))
->add('astrological_sign', TextType::class, array('label' => 'Votre signe astrologique'))
->add('education', TextType::class, array('label' => 'Votre niveau d\'étude'))
->add('profession', TextType::class, array('label' => 'Votre profession'))
->add('salary', TextType::class, array('label' => 'Votre salaire'))
->add('save', SubmitType::class, array('label' => 'Suivant'))
;
}
My country entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Country
*
* #ORM\Table(name="country")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CountryRepository")
*/
class Country
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="code", type="string", length=255)
*/
private $code;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="language", type="string", length=255)
*/
private $language;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set code
*
* #param string $code
*
* #return Country
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* #return string
*/
public function getCode()
{
return $this->code;
}
/**
* Set name
*
* #param string $name
*
* #return Country
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set language
*
* #param string $language
*
* #return Country
*/
public function setLanguage($language)
{
$this->language = $language;
return $this;
}
/**
* Get language
*
* #return string
*/
public function getLanguage()
{
return $this->language;
}
}
My profil controller:
/**
* #Route("/survey/{slug}", name = "survey_render" )
*/
public function renderSurvey($slug, Request $request)
{
$user = $this->getUser();
$em = $this->getDoctrine()->getManager();
$user_info = $em->getRepository('ProfileBundle:UserInfo')->findOneBy(array('userId' => $user->getId()));
if (!$user_info) {
$user_info = new UserInfo();
$user_info->setuserId($user->getId());
}
$user_pref = $em->getRepository('ProfileBundle:UserPreference')->findOneBy(array('userId' => $user->getId()));
if (!$user_pref) {
$user_pref = new UserPreference();
$user_pref->setuserId($user->getId());
}
//$user_info = new UserInfo();
switch ($slug) {
case 'vos_infos':
$form = $this->createForm(UserInfoType::class, $user_info );
break;
case 'votre_apparance':
$form = $this->createForm(UserAppearanceType::class, $user_info);
break;
case 'votre_style_vie':
$form = $this->createForm(UserLifeStyleType::class, $user_info);
break;
case 'ses_infos':
$form = $this->createForm(UserPrefInfoType::class, $user_pref);
break;
case 'son_apparence':
$form = $this->createForm(UserPrefAppearanceType::class, $user_pref);
break;
case 'son_style_vie':
$form = $this->createForm(UserPrefLifeStyleType::class, $user_pref);
break;
case 'votre_quiz':
$form = $this->createForm(UserLifeStyleType::class, $user_pref);
break;
default;
echo 'Lien incorrect';
break;
}
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$form_data = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($form_data);
$em->flush();
It seems that its trying to pass the whole entity to the form and not just the choice results.
Does anyone have an idea of what im doing wrong here?
Thx
Ok i found the error I had in UserInfo.
I did not prepend #ORM and did not have the correct path to the Country entity ( it is not in the same namespace)
Before:
/**
* One Product has One Shipping.
* #OneToOne(targetEntity="Country")
* #JoinColumn(name="countryOfResidence", referencedColumnName="id")
*/
private $countryOfResidence;
After:
/**
* One Product has One Shipping.
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Country")
* #ORM\JoinColumn(name="countryOfResidence", referencedColumnName="id")
*/
private $countryOfResidence;
Thanks for pointing me in the right direction.
If user_info is an entity do you have set the field country_of_residence as a onetoone relation on country entity ?
I got the same type of error. In my case it was an erroneous annotation in the 'owning' entity.
Befor (causes error):
/**
* #ORM\OneToOne(targetEntity="RfpMatchBundle\Entity\Address", cascade={"persist"})
* #ORM\Column(nullable=true, unique=false)
*/
private $address;
After(fixed):
/**
* #ORM\OneToOne(targetEntity="RfpMatchBundle\Entity\Address", cascade={"persist"})
*/
private $address;`

How to get an email from a imbricated form into swiftmailer?

I want to insert an email from an imbricated form into swiftmailer.
The email is the "sendTo" section of the swifmailer.
As I tried it doesn't work. The form is sent but no email is recieved.
How can I have it? Do you have an idea?
So the controller, the action to send the form and then the email is :
/**
* Creates a new Reservations entity.
*
*/
public function createAction(Request $request)
{
$entity = new Reservations();
$emailPool = new Pool();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
// Get the sender's email adress
$sender = $entity->getEmail();
// Get the recipients' emails adresses (pool address)
$emailPool = $this->$pool->getEmailPool(); // mal codé >> trouver la bonne méthode
// Send email
$message = \Swift_Message::newInstance()
->setSubject('Demande de véhicule')
->setFrom($sender)
->setTo($emailPool) // email à entrer Vehicule.Esplanade#eurelien.fr
// Indicate "High" priority
->setPriority(2)
->setBody(
$this->renderView(
// View in app/Resources/views/emails/demandereservation.html.twig
'emails/demandereservation.html.twig', array(
'reservations' => $entity)),
'text/html'
);
$this->get('mailer')->send($message);
$this->get('session')->getFlashBag()->Add('notice', 'Votre réservation a bien été envoyée');
return $this->redirect($this->generateUrl('reservations_show', array('id' => $entity->getId())));
}
return $this->render('CDCarsBundle:Reservations:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
The form (with the imbricated form (pool)) is :
<?php
namespace CD\CarsBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use CD\CarsBundle\Entity\Reservations;
use CD\CarsBundle\Entity\Vehicules;
use Application\Sonata\UserBundle\Entity\User;
class ReservationsType extends AbstractType
{
// Form for the entity "Reservations" which is used to build the car's booking form
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nomAgent', null, array(
'label' => 'Nom de l\'agent',
//'attr' => array(
//'readonly' => true,
//'disabled' => true
//)
))
->add('prenomAgent', null, array(
'label' => 'Prénom de l\'agent',
//'attr' => array(
//'readonly' => true,
//'disabled' => true
//)
))
->add('dga', null, array(
'label' => 'D.G.A',
//'attr' => array(
//'readonly' => true,
//'disabled' => true
//)
))
->add('direction', null, array(
'label' => 'Direction',
//'attr' => array(
//'readonly' => true,
//'disabled' => true
//)
))
->add('email', null, array(
'label' => 'Email',
//'attr' => array(
//'readonly' => true,
//'disabled' => true
//)
))
->add('telephone', null, array(
'label' => 'Téléphone',
//'attr' => array(
//'readonly' => true,
//'disabled' => true
//)
))
// ajouter le pool
->add('pool', new PoolType())
->add('heureDebut', null, array(
'label' => 'Date et heure de début',
'format' => 'dd-MM-yyyy H:i',
'years' => range(\date("Y") - 0, \date("Y") + 2),
)
)
->add('heureFin', null, array(
'label' => 'Date et heure de fin',
'format' => 'dd-MM-yyyy H:i',
'years' => range(\date("Y") - 0, \date("Y") + 2),
)
)
// ajouter type véhicule
->add('besoin', 'choice', array(
'label' => 'Type',
'choices' => array(
'V.L' => 'V.L',
'V.L.E' => 'V.L.E',
'V.U' => 'V.U',
'velo' => 'Vélo')
)
)
// ajouter nombre personnes
->add('nombrePersonne', 'choice', array(
'label' => 'Nombre de personne',
'choices' => array(
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5 +')
)
)
// ajouter demande de remisage -> si coché dévoiler champs pour le remisage (dématérialisation) => à faire dans la vue
->add('remisage', null, array('required' => false))
->add('adresseRemisage', null, array('label' => 'Adresse'))
->add('dateDebutRemisage', null, array(
'label' => 'Du',
'format' => 'dd-MM-yyyy H:i',
'years' => range(\date("Y") - 0, \date("Y") + 2),
)
)
->add('dateFinRemisage', null, array(
'label' => 'au',
'format' => 'dd-MM-yyyy H:i',
'years' => range(\date("Y") - 0, \date("Y") + 2),
)
)
->add('emailDirecteur', null, array(
'label' => 'Email du directeur',
'attr' => array(
'placeholder' => 'email#email.fr',
))
)
->add('destination', null, array('label' => 'Destination'))
->add('motifRdv', null, array('required' => false))
->add('motifFormation', null, array('required' => false))
->add('motifReunion', null, array('required' => false))
->add('motifCollecte', null, array('required' => false))
->add('motifInstallation', null, array('required' => false))
->add('motifProgrammation', null, array('required' => false))
->add('motifDepannage', null, array('required' => false))
->add('motifVad', null, array('required' => false))
->add('motifAutre', null, array('label' => 'Autre motif'))
->add('conducteur', null, array('required' => false))
// ajouter mandataire -> si coché dévoiler champs pour le mandataire (email...) => à faire dans la vue
->add('mandataire', null, array('required' => false))
->add('nomMandataire', null, array('label' => 'Votre nom'))
->add('prenomMandataire', null, array('label' => 'Votre prénom'))
->add('emailMandataire', null, array('label' => 'Votre émail'))
->add('honneur', null, array('required' => true))
;
}
The Pool form is :
<?php
namespace CD\CarsBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use CD\CarsBundle\Entity\Pool;
use CD\CarsBundle\Entity\Vehicules;
class PoolType extends AbstractType
{
// Form for the entity "pool"
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
/*->add('nom', null, array(
'label' => 'Nom',
))*/
->add('emailPool', null, array(
'label' => 'Email du pool duquel vous dépendez',
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'CD\CarsBundle\Entity\Pool'
));
}
/**
* #return string
*/
public function getName()
{
return 'cd_carsbundle_pool';
}
}
The pool entity is :
<?php
namespace CD\CarsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Pool
*/
class Pool
{
// Code for the entity "Pool"
public function __toString()
{
return (string) $this->getEmailPool();
}
//YML GENERATED CODE
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $nom;
/**
* #var string
*/
private $emailPool;
/**
* #var \Doctrine\Common\Collections\Collection
*/
private $vehicules;
/**
* #var \Doctrine\Common\Collections\Collection
*/
private $user;
/**
* #var \Doctrine\Common\Collections\Collection
*/
private $reservations;
/**
* Constructor
*/
public function __construct()
{
$this->vehicules = new \Doctrine\Common\Collections\ArrayCollection();
$this->user = new \Doctrine\Common\Collections\ArrayCollection();
$this->reservations = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set nom
*
* #param string $nom
* #return Pool
*/
public function setNom($nom)
{
$this->nom = $nom;
return $this;
}
/**
* Get nom
*
* #return string
*/
public function getNom()
{
return $this->nom;
}
/**
* Set emailPool
*
* #param string $emailPool
* #return Pool
*/
public function setEmailPool($emailPool)
{
$this->emailPool = $emailPool;
return $this;
}
/**
* Get emailPool
*
* #return string
*/
public function getEmailPool()
{
return $this->emailPool;
}
/**
* Add vehicules
*
* #param \CD\CarsBundle\Entity\Vehicules $vehicules
* #return Pool
*/
public function addVehicule(\CD\CarsBundle\Entity\Vehicules $vehicules)
{
$this->vehicules[] = $vehicules;
return $this;
}
/**
* Remove vehicules
*
* #param \CD\CarsBundle\Entity\Vehicules $vehicules
*/
public function removeVehicule(\CD\CarsBundle\Entity\Vehicules $vehicules)
{
$this->vehicules->removeElement($vehicules);
}
/**
* Get vehicules
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getVehicules()
{
return $this->vehicules;
}
/**
* Add user
*
* #param \Application\Sonata\UserBundle\Entity\User $user
* #return Pool
*/
public function addUser(\Application\Sonata\UserBundle\Entity\User $user)
{
$this->user[] = $user;
return $this;
}
/**
* Remove user
*
* #param \Application\Sonata\UserBundle\Entity\User $user
*/
public function removeUser(\Application\Sonata\UserBundle\Entity\User $user)
{
$this->user->removeElement($user);
}
/**
* Get user
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getUser()
{
return $this->user;
}
/**
* Add reservations
*
* #param \CD\CarsBundle\Entity\Reservations $reservations
* #return Pool
*/
public function addReservation(\CD\CarsBundle\Entity\Reservations $reservations)
{
$this->reservations[] = $reservations;
return $this;
}
/**
* Remove reservations
*
* #param \CD\CarsBundle\Entity\Reservations $reservations
*/
public function removeReservation(\CD\CarsBundle\Entity\Reservations $reservations)
{
$this->reservations->removeElement($reservations);
}
/**
* Get reservations
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getReservations()
{
return $this->reservations;
}
}
The reservations entity is :
<?php
namespace CD\CarsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints as Asserts;
/**
* Reservations
*/
class Reservations
{
// Code for the entity "Reservations"
public function __toString()
{
return (string) $this->getId();
return (string) $this->getHeureDebut();
}
// YML GENERATED CODE
/**
* #var integer
*/
private $id;
/**
* #var \DateTime
*/
private $heureDebut;
/**
* #var \DateTime
*/
private $heureFin;
/**
* #var string
*/
private $nomAgent;
/**
* #var string
*/
private $prenomAgent;
/**
* #var string
*/
private $dga;
/**
* #var string
*/
private $direction;
/**
* #var string
*/
private $email;
/**
* #var string
*/
private $telephone;
/**
* #var string
*/
private $destination;
/**
* #var boolean
*/
private $reserve;
/**
* #var boolean
*/
private $annulation;
/**
* #var boolean
*/
private $remisage;
/**
* #var string
*/
private $adresseRemisage;
/**
* #var \DateTime
*/
private $dateDebutRemisage;
/**
* #var \DateTime
*/
private $dateFinRemisage;
/**
* #var string
*/
private $emailDirecteur;
/**
* #var boolean
*/
private $conducteur;
/**
* #var boolean
*/
private $mandataire;
/**
* #var boolean
*/
private $motifRdv;
/**
* #var boolean
*/
private $motifFormation;
/**
* #var boolean
*/
private $motifReunion;
/**
* #var boolean
*/
private $motifCollecte;
/**
* #var boolean
*/
private $motifInstallation;
/**
* #var boolean
*/
private $motifProgrammation;
/**
* #var boolean
*/
private $motifDepannage;
/**
* #var boolean
*/
private $motifVad;
/**
* #var string
*/
private $motifAutre;
/**
* #var string
*/
private $commentaires;
/**
* #var integer
*/
private $nombrePersonne;
/**
* #var string
*/
private $besoin;
/**
* #var string
*/
private $nomMandataire;
/**
* #var string
*/
private $prenomMandataire;
/**
* #var string
*/
private $emailMandataire;
/**
* #var boolean
*/
private $honneur;
/**
* #var boolean
*/
private $traite;
/**
* #var \CD\CarsBundle\Entity\Vehicules
*/
private $vehicules;
/**
* #var \Application\Sonata\UserBundle\Entity\User
*/
private $user;
/**
* #var \CD\CarsBundle\Entity\Pool
*/
private $pool;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set heureDebut
*
* #param \DateTime $heureDebut
* #return Reservations
*/
public function setHeureDebut($heureDebut)
{
$this->heureDebut = $heureDebut;
return $this;
}
/**
* Get heureDebut
*
* #return \DateTime
*/
public function getHeureDebut()
{
return $this->heureDebut;
}
/**
* Set heureFin
*
* #param \DateTime $heureFin
* #return Reservations
*/
public function setHeureFin($heureFin)
{
$this->heureFin = $heureFin;
return $this;
}
/**
* Get heureFin
*
* #return \DateTime
*/
public function getHeureFin()
{
return $this->heureFin;
}
/**
* Set nomAgent
*
* #param string $nomAgent
* #return Reservations
*/
public function setNomAgent($nomAgent)
{
$this->nomAgent = $nomAgent;
return $this;
}
/**
* Get nomAgent
*
* #return string
*/
public function getNomAgent()
{
return $this->nomAgent;
}
/**
* Set prenomAgent
*
* #param string $prenomAgent
* #return Reservations
*/
public function setPrenomAgent($prenomAgent)
{
$this->prenomAgent = $prenomAgent;
return $this;
}
/**
* Get prenomAgent
*
* #return string
*/
public function getPrenomAgent()
{
return $this->prenomAgent;
}
/**
* Set dga
*
* #param string $dga
* #return Reservations
*/
public function setDga($dga)
{
$this->dga = $dga;
return $this;
}
/**
* Get dga
*
* #return string
*/
public function getDga()
{
return $this->dga;
}
/**
* Set direction
*
* #param string $direction
* #return Reservations
*/
public function setDirection($direction)
{
$this->direction = $direction;
return $this;
}
/**
* Get direction
*
* #return string
*/
public function getDirection()
{
return $this->direction;
}
/**
* Set email
*
* #param string $email
* #return Reservations
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set telephone
*
* #param string $telephone
* #return Reservations
*/
public function setTelephone($telephone)
{
$this->telephone = $telephone;
return $this;
}
/**
* Get telephone
*
* #return string
*/
public function getTelephone()
{
return $this->telephone;
}
/**
* Set destination
*
* #param string $destination
* #return Reservations
*/
public function setDestination($destination)
{
$this->destination = $destination;
return $this;
}
/**
* Get destination
*
* #return string
*/
public function getDestination()
{
return $this->destination;
}
/**
* Set reserve
*
* #param boolean $reserve
* #return Reservations
*/
public function setReserve($reserve)
{
$this->reserve = $reserve;
return $this;
}
/**
* Get reserve
*
* #return boolean
*/
public function getReserve()
{
return $this->reserve;
}
/**
* Set annulation
*
* #param boolean $annulation
* #return Reservations
*/
public function setAnnulation($annulation)
{
$this->annulation = $annulation;
return $this;
}
/**
* Get annulation
*
* #return boolean
*/
public function getAnnulation()
{
return $this->annulation;
}
/**
* Set remisage
*
* #param boolean $remisage
* #return Reservations
*/
public function setRemisage($remisage)
{
$this->remisage = $remisage;
return $this;
}
/**
* Get remisage
*
* #return boolean
*/
public function getRemisage()
{
return $this->remisage;
}
/**
* Set adresseRemisage
*
* #param string $adresseRemisage
* #return Reservations
*/
public function setAdresseRemisage($adresseRemisage)
{
$this->adresseRemisage = $adresseRemisage;
return $this;
}
/**
* Get adresseRemisage
*
* #return string
*/
public function getAdresseRemisage()
{
return $this->adresseRemisage;
}
/**
* Set dateDebutRemisage
*
* #param \DateTime $dateDebutRemisage
* #return Reservations
*/
public function setDateDebutRemisage($dateDebutRemisage)
{
$this->dateDebutRemisage = $dateDebutRemisage;
return $this;
}
/**
* Get dateDebutRemisage
*
* #return \DateTime
*/
public function getDateDebutRemisage()
{
return $this->dateDebutRemisage;
}
/**
* Set dateFinRemisage
*
* #param \DateTime $dateFinRemisage
* #return Reservations
*/
public function setDateFinRemisage($dateFinRemisage)
{
$this->dateFinRemisage = $dateFinRemisage;
return $this;
}
/**
* Get dateFinRemisage
*
* #return \DateTime
*/
public function getDateFinRemisage()
{
return $this->dateFinRemisage;
}
/**
* Set emailDirecteur
*
* #param string $emailDirecteur
* #return Reservations
*/
public function setEmailDirecteur($emailDirecteur)
{
$this->emailDirecteur = $emailDirecteur;
return $this;
}
/**
* Get emailDirecteur
*
* #return string
*/
public function getEmailDirecteur()
{
return $this->emailDirecteur;
}
/**
* Set vehicules
*
* #param \CD\CarsBundle\Entity\Vehicules $vehicules
* #return Reservations
*/
public function setVehicules(\CD\CarsBundle\Entity\Vehicules $vehicules = null)
{
$this->vehicules = $vehicules;
return $this;
}
/**
* Get vehicules
*
* #return \CD\CarsBundle\Entity\Vehicules
*/
public function getVehicules()
{
return $this->vehicules;
}
/**
* Set user
*
* #param \Application\Sonata\UserBundle\Entity\User $user
* #return Reservations
*/
public function setUser(\Application\Sonata\UserBundle\Entity\User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \Application\Sonata\UserBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Set pool
*
* #param \CD\CarsBundle\Entity\Pool $pool
* #return Reservations
*/
public function setPool(\CD\CarsBundle\Entity\Pool $pool = null)
{
$this->pool = $pool;
return $this;
}
/**
* Get pool
*
* #return \CD\CarsBundle\Entity\Pool
*/
public function getPool()
{
return $this->pool;
}
}
Thank you. Have a nice day.
I have figured it out.
In the controller, at the swiftmailer section, the line to the get the recipient's email is :
// Get the recipients' emails adresses (pool address)
$recipients = $entity->getPool()->getEmailPool();
Like this it works.
Thank you to all the people who read this post and if you have an other answer, feel free to post it.
Have a nice day!

Symfony2 Collection Form type - Not saving new records

I have implemented the 'collection' form type in my app, and it works great, including removing related records that are removed from the submitted data, however in order to save any newly added link record I have to manually loop through the links entities & set the owner as the entity being edited. I'm sure it should do this automatically, so what have I missed?
You'll see a...
/*****************************************************************
* This is the bit I've had to add to persist the new entries!!! *
*****************************************************************
... where I've had to manually link the entities in the AppController file.
The files
App Entity
<?php
namespace ...\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;
/**
* App
*
* #ORM\Table()
* #ORM\Entity()
*/
class App
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
// ...
/**
* #var AppAppStoreData[]|ArrayCollection
*
* We use orphan removal here to remove the link data when deleting an app
* #ORM\OneToMany(targetEntity="AppAppStoreData", mappedBy="app", cascade={"all"}, orphanRemoval=TRUE)
*/
private $appAppStoreData;
// ...
/**
* #return ArrayCollection|AppAppStoreData[]
*/
public function getAppAppStoreData()
{
return $this->appAppStoreData;
}
/**
* #param ArrayCollection|AppAppStoreData[] $appAppStoreData
*
* #return $this
*/
public function setAppAppStoreData( $appAppStoreData )
{
$this->appAppStoreData = $appAppStoreData;
return $this;
}
}
AppStore Entity
<?php
namespace ...\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* AppStore
*
* #ORM\Table()
* #ORM\Entity()
*/
class AppStore
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
// ...
/**
* #var AppAppStoreData[]|ArrayCollection
*
* We use orphan removal here to remove the link data when deleting an app
* #ORM\OneToMany(targetEntity="AppAppStoreData", mappedBy="appStore", cascade={"all"}, orphanRemoval=TRUE)
*/
private $appAppStoreData;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
// ...
/**
* #return AppAppStoreData[]|ArrayCollection
*/
public function getAppAppStoreData()
{
return $this->appAppStoreData;
}
/**
* #param AppAppStoreData[]|ArrayCollection $appAppStoreData
*
* #return $this
*/
public function setAppAppStoreData( $appAppStoreData )
{
$this->appAppStoreData = $appAppStoreData;
return $this;
}
}
AppAppStoreData Entity
<?php
namespace ...\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* AppAppStoreData
*
* #ORM\Table()
* #ORM\Entity()
*/
class AppAppStoreData
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var App
*
* #ORM\ManyToOne(targetEntity="App", inversedBy="appAppStoreData")
* #ORM\JoinColumn(name="app_id", referencedColumnName="id")
*/
private $app;
/**
* #var AppStore
*
* #ORM\ManyToOne(targetEntity="AppStore", inversedBy="appAppStoreData")
* #ORM\JoinColumn(name="app_store_id", referencedColumnName="id")
*/
private $appStore;
/**
* #var string
*
* #ORM\Column(name="app_store_uri", type="string", length=1083)
*/
private $appUri;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set app
*
* #param App $app
*
* #return AppAppStoreData
*/
public function setApp(App $app)
{
$this->app = $app;
return $this;
}
/**
* Get app
*
* #return App
*/
public function getApp()
{
return $this->app;
}
/**
* Set appStore
*
* #param AppStore $appStore
*
* #return AppAppStoreData
*/
public function setAppStore(AppStore $appStore)
{
$this->appStore = $appStore;
return $this;
}
/**
* Get appStore
*
* #return AppStore
*/
public function getAppStore()
{
return $this->appStore;
}
/**
* Set appStoreLink
*
* #param string $appUri
*
* #return AppAppStoreData
*/
public function setAppUri( $appUri)
{
$this->appUri = $appUri;
return $this;
}
/**
* Get appStoreLink
*
* #return string
*/
public function getAppUri()
{
return $this->appUri;
}
}
AppType Form
<?php
namespace ...\Form\Type;
use ...\Entity\App;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class AppType extends AbstractType
{
/**
* Builds the App admin edit form
*
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm( FormBuilderInterface $builder, array $options )
{
$builder
// ...
->add( 'appAppStoreData', 'collection', [
'type' => new ,
'label' => 'App Store Links',
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'widget_add_btn' => array( 'label' => "Add App Store Details" ),
'widget_remove_btn' => array( 'label' => "Remove App Store Details" ),
'show_legend' => false, // dont show another legend of subform
'options' => array( // options for collection fields
'label_render' => false,
'widget_addon_prepend' => array(
'text' => '#',
),
'horizontal_input_wrapper_class' => "col-lg-8",
),
] );
}
/**
* Sets the Entity data class
*
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions( OptionsResolverInterface $resolver )
{
$resolver->setDefaults(
array(
'data_class' => '...\Entity\App',
)
);
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'app';
}
}
AppAppStoreDataFieldsType
<?php
namespace ...\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class AppAppStoreDataFieldsType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm( FormBuilderInterface $builder, array $options )
{
$builder
->add( 'appStore', 'entity', [
'class' => '...Bundle:AppStore',
'property' => 'name',
'label' => 'App Store'
] )
->add( 'appUri', 'url', [
'label' => 'App URI'
] );
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions( OptionsResolverInterface $resolver )
{
$resolver->setDefaults( array(
'data_class' => '...\Entity\AppAppStoreData'
) );
}
/**
* #return string
*/
public function getName()
{
return 'app_store_data_fields';
}
}
App Controller
<?php
namespace ...\Controller;
use ...\Entity\UploadableInterface;
use ...\Exception\RecordNotFoundException;
use ...\Exception\RedirectException;
use ...\Entity\App;
use ...\Entity\AppRepository;
use ...\Entity\ClientRepository;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class AppController extends ClientAssetController
{
/**
* #param Request $request
* #param null $id
*
* #return Response
*/
public function editAction( Request $request, $id = null )
{
$app = #$this->getAppRepository()->find( $id );
// ...
$form = $this->createForm( 'app', $app )
->add( 'save', 'submit', [ 'label' => 'Save' ] );
$form->handleRequest( $request );
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist( $app );
/*****************************************************************
* This is the bit I've had to add to persist the new entries!!! *
*****************************************************************
/
foreach ($app->getAppAppStoreData() as $appAppStoreDatum) {
$appAppStoreDatum->setApp( $app );
}
$em->flush();
// ... Redirect
}
// ... Render
}
// ...
}
initialize the collection of appAppStoreData:
...
public function __construct()
{
$this->appAppStoreData = new ArrayCollection();
}

ZF2 and Doctrine2: One form -> Two entities

I would like to make one form in which I could have elements to populate two entities.
How can I do that? One of the objects is mapped to the other one.
For example I have something like this:
Table user:
id | login | password
Table user_email:
id | user_id | email
There can be more than one row user_email mapped to user - user can have more than one email.
But - when I'm adding first occurrence of the user I have to get his first email.
I know everything how to map entities but I have problem with populating objects from ZF2 form.
Can anyone suggest how should I do this? I've tried to make two fieldsets but I cannot bind object to fieldset. If this is the solution how bind objects to form which have two filedsets? Every fieldset have mapped doctrine2 hydrator but when I'm trying to bind one of the entity to form (not fieldset which i cannot do) I have error message:
Zend\Stdlib\Hydrator\ArraySerializable::extract expects the provided object to implement getArrayCopy()
Before my example I have to explan what i want to achieve. I have a table cameras - which contain link and some other information about streaming cameras. Second table: cameras_desc contain descriptions to those cameras in different languages. In my CMS i want to add two rows: one in cameras and second in cmaeras_desc in one form. cameras_desc will have first translation in polish language (which would be default language for CMS). As u can see cameras and cameras_desc are mapped with some other entites (cameras with checkpoints and cameras_desc with languages). but thats not a point. What i want to achieve is to populate two rows in two tables by one form. lang in cameras_desc is set by PHP code, but checkpoint is set by user in form by select element. everything works in code below but it isnt made honestly.
This is my code:
First entity:
namespace Granica\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Cameras
*
* #ORM\Table(name="cameras", indexes={#ORM\Index(name="IDX_6B5F276AF27C615F", columns={"checkpoint_id"})})
* #ORM\Entity
*/
class Cameras
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="link", type="text", nullable=false)
*/
private $link;
/**
* #var string
*
* #ORM\Column(name="direction", type="string", length=4, nullable=false)
*/
private $direction;
/**
* #var \Granica\Entity\Checkpoints
*
* #ORM\ManyToOne(targetEntity="Granica\Entity\Checkpoints")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="checkpoint_id", referencedColumnName="id")
* })
*/
private $checkpoint;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set link
*
* #param string $link
* #return Cameras
*/
public function setLink($link)
{
$this->link = $link;
return $this;
}
/**
* Get link
*
* #return string
*/
public function getLink()
{
return $this->link;
}
/**
* Set direction
*
* #param string $direction
* #return Cameras
*/
public function setDirection($direction)
{
$this->direction = $direction;
return $this;
}
/**
* Get direction
*
* #return string
*/
public function getDirection()
{
return $this->direction;
}
/**
* Set checkpoint
*
* #param \Granica\Entity\Checkpoints $checkpoint
* #return Cameras
*/
public function setCheckpoint(\Granica\Entity\Checkpoints $checkpoint = null)
{
$this->checkpoint = $checkpoint;
return $this;
}
/**
* Get checkpoint
*
* #return \Granica\Entity\Checkpoints
*/
public function getCheckpoint()
{
return $this->checkpoint;
}
}
Second entity:
<?php
namespace Granica\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* CamerasDesc
*
* #ORM\Table(name="camera_desc", indexes={#ORM\Index(name="lang", columns={"lang"}), #ORM\Index(name="camera_id", columns={"camera_id"})})
* #ORM\Entity
*/
class CameraDesc
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="description", type="text", nullable=false)
*/
private $description;
/**
* #var \Granica\Entity\Languages
*
* #ORM\ManyToOne(targetEntity="Granica\Entity\Languages")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="lang", referencedColumnName="id")
* })
*/
private $lang;
/**
* #var \Granica\Entity\Cameras
*
* #ORM\ManyToOne(targetEntity="Granica\Entity\Cameras")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="camera_id", referencedColumnName="id")
* })
*/
private $camera;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set description
*
* #param string $description
* #return CamerasDesc
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set lang
*
* #param \Granica\Entity\Languages $lang
* #return CamerasDesc
*/
public function setLang(\Granica\Entity\Languages $lang = null)
{
$this->lang = $lang;
return $this;
}
/**
* Get lang
*
* #return \Granica\Entity\Languages
*/
public function getLang()
{
return $this->lang;
}
/**
* Set camera
*
* #param \Granica\Entity\Cameras $camera
* #return CamerasDesc
*/
public function setCamera(\Granica\Entity\Cameras $camera = null)
{
$this->camera = $camera;
return $this;
}
/**
* Get camera
*
* #return \Granica\Entity\Cameras
*/
public function getCamera()
{
return $this->camera;
}
}
Fieldset ( for camera_desc ):
namespace Granica\Form;
use Zend\Form\Fieldset;
use DoctrineModule\Persistence\ObjectManagerAwareInterface;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use DoctrineORMModule\Stdlib\Hydrator\DoctrineEntity;
use Granica\Entity\Languages;
class CameraDescFieldset extends Fieldset implements ObjectManagerAwareInterface
{
protected $objectManager;
public function __construct(ObjectManager $objectManager)
{
parent::__construct('camera_desc');
$this->setObjectManager($objectManager);
$this->setHydrator(new DoctrineHydrator($this->getObjectManager(),'Granica\Entity\CameraDesc'));
$this->add(array(
'name' => 'description',
'attributes' => array(
'type' => 'text',
'placeholder' => 'Opis',
'required' => 'true',
),
'options' => array(
'label' => 'Opis kamery',
),
));
}
// implementacja interfajsu objectmanager
public function setObjectManager(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;
return $this;
}
public function getObjectManager()
{
return $this->objectManager;
}
}
Form (for camera):
use Zend\Form\Form;
use DoctrineModule\Persistence\ObjectManagerAwareInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Granica\Form\CameraDescFieldset;
class AddCameraForm extends Form implements ObjectManagerAwareInterface
{
protected $objectManager;
public function __construct(ObjectManager $objectManager)
{
parent::__construct('checkpoint');
$this->setObjectManager($objectManager);
// tworzenie formularza
$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'checkpoint',
'type' => 'DoctrineModule\Form\Element\ObjectSelect',
'options' => array(
'label' => 'Punkt graniczny',
'object_manager' => $this->getObjectManager(),
'target_class' => 'Granica\Entity\Checkpoints',
'property' => 'name',
'empty_option' => '--- wybierz przejście ---'
),
));
$this->add(array(
'name' => 'link',
'attributes' => array(
'type' => 'text',
'placeholder' => 'Link',
'required' => 'true',
),
'options' => array(
'label' => 'Adres URL kamery',
),
));
$this->add(array(
'type' => 'Zend\Form\Element\Select',
'name' => 'direction',
'attributes' => array(
'required' => 'true',
),
'options' => array(
'label' => 'Kierunek',
'empty_option' => '--- wybierz kierunek ---',
'value_options' => array(
'from' => 'FROM: Wyjazd z Polski',
'to' => 'TO: Wjazd do Polski',
),
)
));
$this->add(new CameraDescFieldset($this->getObjectManager()));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Zapisz',
'id' => 'submitbutton',
),
));
}
// implementacja interfajsu objectmanager
public function setObjectManager(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;
return $this;
}
public function getObjectManager()
{
return $this->objectManager;
}
}
And the add controller:
public function addAction()
{
$camera = new Cameras();
$cameraDesc = new CameraDesc();
$lang = $this->getEntityManager()->getRepository('Granica\Entity\Languages')->find('pl');
$form = new AddCameraForm($this->getEntityManager());
$cameraDescFieldset = new CameraDescFieldset($this->getEntityManager());
$form->setHydrator(new DoctrineHydrator($this->getEntityManager(),'Granica\Entity\Cameras'));
$form->bind($camera);
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$data = $form->getData();
$cameraDesc->setLang($lang);
$cameraDesc->setDescription($request->getPost()['camera_desc']['description']);
$this->getEntityManager()->persist($camera);
$cameraDesc->setCamera($camera);
$this->getEntityManager()->persist($cameraDesc);
$this->getEntityManager()->flush();
return $this->redirect()->toRoute('cameras');
}
}
return new ViewModel(array('form' => $form));
}
As you can see I've managed to overcome my problem - I've populate camera_desc with data which I get from post. This work but isn't the best solution - for example filters didn't work on cameraDesc descrition.

Symfony 2 Exception: Call to a member function on a non object when using Form Events

I'm trying to create a form which dinamically load all "sites" related to a "project", It seems like this would be of use, so I tried it:
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class EngineeringType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('project','entity',array(
'class' => 'tBundle:Project',
'label' => 'Project'
;
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function(FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
$sites = $data->getProject()->getSites();
$form->add('site', 'entity', array('choices' => $sites));
}
);
}
My problem comes when I try to access the form, I get:
FatalErrorException: Error: Call to a member function getSites() on a non-object in ... tBundle\Form\EngineeringType.php line 41
Here are my entities:
namespace tBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Engineering
*
* #ORM\Table(name="engineerings")
* #ORM\Entity
*/
class Engineering
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="tBundle\Entity\Project")
* #ORM\JoinColumn(name="project_id", referencedColumnName="id",nullable=false)
*/
private $project;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set project
*
* #param string $project
* #return Engineering
*/
public function setProject(\tBundle\Entity\Project $project)
{
$this->project = $project;
return $this;
}
/**
* Get project
*
* #return string
*/
public function getProject()
{
return $this->project;
}
Project:
namespace tBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Project
*
* #ORM\Table(name="projects")
* #ORM\Entity
*/
class Project
{
/**
* #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)
*/
private $name;
/**
* #ORM\ManyToMany(targetEntity="tBundle\Entity\Site")
* #ORM\JoinTable(name="project_sites",
* joinColumns={#ORM\JoinColumn(name="site_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="project_id", referencedColumnName="id")}
* )
*/
private $sites;
public function __construct()
{
$this->sites = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Project
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Get Sites
*
* #return array
*/
public function getSites()
{
return $this->sites;
}
/* Returns Project's Name */
public function __toString()
{
return $this->name;
}
What am I doing wrong?
EDIT
Controller:
/**
* Creates a form to create a Engineering entity.
*
* #param Engineering $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Engineering $entity)
{
$form = $this->createForm(new EngineeringType(), $entity, array(
'action' => $this->generateUrl('engineering_create'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
/**
* Creates a form to edit a Engineering entity.
*
* #param Engineering $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createEditForm(Engineering $entity)
{
$form = $this->createForm(new EngineeringType(), $entity, array(
'action' => $this->generateUrl('engineering_update', array('id' => $entity->getId())),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Update'));
return $form;
}
The PRE_SET_DATA event is actually fired twice. The first time will not have any data. There used to be a blurb in the manual explaining why but I could not find it again.
So just:
function(FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
if ($data)
{
$sites = $data->getProject()->getSites();
$form->add('site', 'entity', array('choices' => $sites));
}
}
=======================================================
Updated answer to show how to handle non-existent $project:
if ($data)
{
$project = $data->getProject();
$sites = $project ? $project->getSites() : array();
$form->add('site', 'entity', array('choices' => $sites));
}
There is an easy solution, why don't you use the "property" property on the form builder?
$builder
->add('project','entity',array(
'class' => 'tBundle:Project',
'label' => 'Project',
'property' => 'sites');
Or even you can use a query builder if this is not enough:
$builder->add('users', 'entity', array(
'class' => 'AcmeHelloBundle:User',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.username', 'ASC');
},
));
You can find here more description, if this is not enough:
Symfony documentation
EDIT:
So your problem that with the first solution, that it's going to be an array, so use my second option, and in the query builder, specify what will reflect your needs.
Or use it like the class is not Project but Sites.