I'm trying to create a ManyToMany relationship between Sonata's User and an entity called "Network" that resides in my bundle.
The idea is to be able to assign multiple Networks to each user via the User creation/edition of SonataAdmin.
Here's what I've got:
User Entity:
<?php
namespace Application\Sonata\UserBundle\Entity;
use Sonata\UserBundle\Entity\BaseUser as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
class User extends BaseUser
{
/**
* #var integer $id
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="\Acme\TestBundle\Entity\Network", mappedBy="users", cascade={"persist", "remove"})
*/
protected $networks;
public function __construct()
{
parent::__construct();
$this->networks = new ArrayCollection();
}
/**
* Get id
*
* #return integer $id
*/
public function getId()
{
return $this->id;
}
/**
* Add network
*
* #param \Acme\TestBundle\Entity\Network $network
* #return User
*/
public function addNetwork($network)
{
$this->networks[] = $network;
$network->addUser($this);
return $this;
}
/**
* Remove network
*
* #param \Acme\TestBundle\Entity\Network $network
*/
public function removeNetwork($network)
{
$this->networks->removeElement($network);
$network->removeUser($this);
}
/**
* Get networks
*
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getNetworks()
{
return $this->networks;
}
}
Network Entity:
<?php
namespace Acme\TestBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
*/
class Network
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255)
*/
protected $name;
/**
* #ORM\ManyToMany(targetEntity="\Application\Sonata\UserBundle\Entity\User", inversedBy="networks")
* #ORM\JoinTable(name="Networks_Users")
*/
protected $users;
public function __construct()
{
$this->users = new ArrayCollection();
}
public function __toString()
{
return $this->getName();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Network
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add user
*
* #param \Application\Sonata\UserBundle\Entity\User $user
* #return Network
*/
public function addUser($user)
{
$this->users[] = $user;
return $this;
}
/**
* Remove user
*
* #param \Application\Sonata\UserBundle\Entity\User $user
*/
public function removeUser($user)
{
$this->users->removeElement($user);
}
/**
* Get users
*
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getUsers()
{
return $this->users;
}
}
app\config.yml
sonata_user:
admin:
user:
class: Acme\TestBundle\Admin\UserAdmin
#...#
User Admin class:
<?php
namespace Acme\TestBundle\Admin;
use Sonata\UserBundle\Admin\Model\UserAdmin as SonataUserAdmin;
class UserAdmin extends SonataUserAdmin
{
/**
* {#inheritdoc}
*/
protected function configureFormFields(\Sonata\AdminBundle\Form\FormMapper $formMapper)
{
parent::configureFormFields($formMapper);
$formMapper
->with('Networks')
->add('networks', 'sonata_type_model', array(
'by_reference' => false,
'required' => false,
'expanded' => false,
'multiple' => true,
'label' => 'Choose the user Networks',
'class' => 'AcmeTestBundle:Network'
))
->end();
}
}
Here's the problem:
When I edit an existing User via SonataAdmin and assign certain Networks to it changes are persisted to the database but the selector appears empty, as if no Networks were ever assigned. If I try to assign Networks again, I get a database constraint violation message (as it would be expected).
I discovered that for some reason the $networks ArrayCollection is returning NULL, as if the relationship could not be established from the User side:
$usr = $this->getUser();
$selected_networks = $usr->getNetworks(); // returns NULL
If I attempt to manage Users from the Network side, everything works fine (with no additions or changes to the actual code):
<?php
namespace Acme\TestBundle\Admin;
use Sonata\AdminBundle\Form\FormMapper;
class NetworkAdmin extends Admin
{
/**
* #param \Sonata\AdminBundle\Form\FormMapper $formMapper
*
* #return void
*/
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->with('General')
->add('name')
->end()
->with('Users')
->add('users', 'sonata_type_model', array(
'by_reference' => false,
'required' => false,
'expanded' => false,
'multiple' => true,
'label' => 'Choose the network Users',
'class' => 'ApplicationSonataUserBundle:User'
))
;
}
}
I'm stumped. Any ideas?
Thank you all.
Related
I started working with SonataAdmin Bundle today, and i can't figure out OneToMany relations. My User can follow(obserwowane) offerts
Entities:
class Obserwowane {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Oferty",inversedBy="obserwowane")
* #ORM\JoinColumn(name="oferta", referencedColumnName="id_oferty", onDelete="CASCADE")
*/
protected $oferta;
/**
*
* #ORM\ManyToOne(targetEntity="User", inversedBy="obserwowane")
* #ORM\JoinColumn(name="user", referencedColumnName="id")
*/
protected $user;
}
.
class User {
/**
* #ORM\OneToMany(targetEntity="Obserwowane", mappedBy="user")
*/
public $obserwowane;
}
.
class Oferty {
/**
* #ORM\OneToMany(targetEntity="Obserwowane", mappedBy="oferta")
*/
protected $obserwowane;
}
My servies.yml -> http://pastebin.com/biNCLhNt
I would like to display followed offers in User form in SonataAdminBundle. I would like also to have it editable.
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('id', 'integer', array('label' => 'id'))
->add('username', 'text', array('label' => 'Username'))
->add('email', 'text', array('label' => 'e-mail'))
->add('password', 'text', array('label' => 'Password'))
;
}
Define obserwowane as ArrayCollection and add getter and setter methods so sonata will use them to operate with Obserwowane array of entities.
use Doctrine\Common\Collections\ArrayCollection;
class user{
// ...
public function __construct()
{
$this->obserwowane = new ArrayCollection;
}
/**
* Get obserwowane
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getObserwowane ()
{
return $this->obserwowane ;
}
public function setObserwowane (ArrayCollection $obserwowane )
{
$this->obserwowane = $obserwowane ;
return $this;
}
/**
* Add Obserwowane
*
* #param Obserwowane $obserwowane
* #return Obserwowane
*/
public function addObserwowane (Obserwowane $obserwowane )
{
$this->obserwowane[] = $obserwowane;
return $this;
}
/**
* Remove Obserwowane
*
* #param Obserwowane $obserwowane
*/
public function removeObserwowane(Obserwowane $obserwowane)
{
$this->obserwowane->removeElement($obserwowane);
}
}
Finally add obserwowane field in formMapper
$formMapper
->add('obserwowane')
Update
To add or remove user for Obserwowane entity add those functions to Obserwowaneclass
class Obserwowane{
// ..
/**
* Set User
*
* #param User $user
* #return User
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* Get User
*
* #return User
*/
public function getUser()
{
return $this->user;
}
}
And in sonata
$formMapper
->add(user)
In a Symfony2 application using the Sonata Admin bundle, I have two entities:
CorporateAttributes
CorporateAttributesApi
Related in Doctrine like so:
CorporateAttributes ←one-to-many→ CorporateAttributesApi
My Sonata Admin class for CorporateAttributes contains the following:
in AppBundle/Admin/CorporateAttributesAdmin.php
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper) {
$formMapper
->add('apis', 'sonata_type_collection',
['required' => false, 'label' => 'API Clients'],
['edit'=>'inline','inline'=>'table']
)
;
}
This adds a "Add new" button to the CorporateAttributes form where I can add and edit CorporateAttributesApi's related to the CorporateAttributes object for which the user is editing.
However, this only works for an existing CorporateAttributes object.
If I'm trying to add a new CorporateAttributes, clicking the "Add New" button gives the following error in the console:
Failed to load resource: the server responded with a status of 500 (Internal Server Error)
http://localhost/app_dev.php/admin/core/append-form-field-element?code=sonata.admin.corporateattributes&elementId=s55fc29157eeee_apis&uniqid=s55fc29157eeee
I suspect it has something to do with the fact that CorporateAttributesApi needs a CorporateAttributes id that it references, but I'm not sure how to make it play nice.
Here is the other relevant code:
in AppBundle/Admin/CorporateAttributesApiAdmin.php:
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper) {
$formMapper
->add('corporate_attributes', null, ['required' => true])
->add('group_name', 'choice', [
'choices' => ['a', 'b', 'c'],
'required' => false,
])
;
}
And the entities with doctrine2 annotations:
in AppBundle/Entity/CorporateAttributes.php:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* CorporateAttributes
*
*
* #ORM\Entity
* #ORM\Table("drupal_wiredb_corporate_attributes")
*/
class CorporateAttributes
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="CorporateAttributesApi", mappedBy="corporate_attributes", cascade={"persist"}, orphanRemoval=true))
*/
protected $apis;
public function getId() {
return $this->id;
}
/**
* Add apis
*
* #param \AppBundle\Entity\CorporateAttributesApi $apis
* #return CorporateAttributes
*/
public function addApi(\AppBundle\Entity\CorporateAttributesApi $api)
{
$this->apis[] = $api;
$api->setCorporateAttributes($this);
return $this;
}
/**
* Remove apis
*
* #param \AppBundle\Entity\CorporateAttributesApi $apis
*/
public function removeApi(\AppBundle\Entity\CorporateAttributesApi $api)
{
$this->apis->removeElement($api);
$api->setCorporateAttributes(null);
}
/**
* Get apis
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getApis()
{
return $this->apis;
}
/**
* Constructor
*/
public function __construct()
{
$this->apis = new \Doctrine\Common\Collections\ArrayCollection();
}
}
in AppBundle/Entities/CorporateAttributesApi.php:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* CorporateAttributesApi
*
*
* #ORM\Entity
* #ORM\Table("drupal_wiredb_corporate_attributes_api")
*/
class CorporateAttributesApi
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="CorporateAttributes", inversedBy="apis")
* #ORM\JoinColumn(name="attribute_id", referencedColumnName="id")
*/
protected $corporate_attributes;
/**
* #ORM\Id
* #ORM\Column(name="group_name", type="string", length=128, options={"default":""})
*/
protected $group_name = '';
public function __toString() {
if (empty($this->corporate_attributes) && empty($this->api_user)) {
return 'New Corporate Attributes - API User Join';
}
else {
return (string)$this->corporate_attributes . ' | ' . (string)$this->api_user . ' | ' . $this->group_name;
}
}
/**
* Set group_name
*
* #param string $groupName
* #return CorporateAttributesApi
*/
public function setGroupName($groupName)
{
$this->group_name = $groupName;
return $this;
}
/**
* Get group_name
*
* #return string
*/
public function getGroupName()
{
return $this->group_name;
}
/**
* Set corporate_attributes
*
* #param \AppBundle\Entity\CorporateAttributes $corporateAttributes
* #return CorporateAttributesApi
*/
public function setCorporateAttributes(\AppBundle\Entity\CorporateAttributes $corporateAttributes)
{
$this->corporate_attributes = $corporateAttributes;
return $this;
}
/**
* Get corporate_attributes
*
* #return \AppBundle\Entity\CorporateAttributes
*/
public function getCorporateAttributes()
{
return $this->corporate_attributes;
}
}
I would try to modify your AppBundle/Admin/CorporateAttributesApiAdmin.php file in following way:
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper) {
$formMapper
->add('corporate_attributes', null, ['required' => true])
->add('group_name', 'choice', [
'choices' => ['a', 'b', 'c'],
'required' => false,
])
;
// If this is sonata_type_collection inside CorporateAttributes form,
// then we don't need 'corporate_attributes' field as it would be the parent entity
if ($this->getRoot() instanceof \AppBundle\Admin\CorporateAttributesAdmin) {
$formMapper->remove('corporate_attributes');
}
}
public function getNewInstance()
{
$object = parent::getNewInstance();
// Here we specify the 'corporate_attributes'
if ($this->getRoot()->getSubject() instanceof \AppBundle\Entity\CorporateAttributes) {
$object->setCorporateAttributes($this->getRoot()->getSubject());
}
return $object;
}
You also may want to try modify AppBundle/Admin/CorporateAttributesAdmin.php to set by_reference=false in form field definition:
// Fields to be shown on create/edit forms
// AppBundle/Admin/CorporateAttributesAdmin.php
protected function configureFormFields(FormMapper $formMapper) {
$formMapper
->add('apis', 'sonata_type_collection',
['required' => false, 'label' => 'API Clients', 'by_reference' => false],
['edit'=>'inline','inline'=>'table']
)
;
}
Here is documentation for by_reference option: http://symfony.com/doc/current/reference/forms/types/collection.html#by-reference
I want to create table Pracownik which can contain zero or few instances of Zaklady and control it using Sonata Admin. Both of tables are translated using a2lix_translatable.
So I have classes:
<?php
namespace JCuryllo\InstituteBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* Pracownik
*
* #ORM\Table()
* #ORM\Entity
*/
class Pracownik
{
use ORMBehaviors\Translatable\Translatable;
public function __call($method, $arguments)
{
return $this->proxyCurrentLocaleTranslation($method, $arguments);
}
/**
* #ORM\ManyToOne(targetEntity="ZakladyTranslation")
**/
private $zaklady;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* and other properties
*/
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/* and other getters and setter */
}
And Translation:
<?php
namespace JCuryllo\InstituteBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
/**
* #ORM\Entity
*/
class PracownikTranslation
{
use ORMBehaviors\Translatable\Translation;
public function __toString()
{
return $this->getTitle();
}
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/* and other properties */
/**
* Set name
*
* #param string $name
* #return Pracownik
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/* and other getters and setter *.
}
I've used very similar code in Zaklady and ZakladyTranslation. Then in PracownikAdmin I try to do sth like:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('zaklady', 'many_to_one',array(
'required' => false,
))
->add('translations', 'a2lix_translations')
;
}
but it doesn't work (error: Could not load type "many_to_one").
many_to_one is not an available form type for Sonata, you have to use sonata_type_model or sonata_type_model_list for a many to one relation.
Example:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('zaklady', 'sonata_type_model_list',array(
'required' => false,
))
->add('translations', 'a2lix_translations');
}
Documentation : http://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/form_field_definition.html#advanced-usage-many-to-one
Ok, I have done it.
In Zaklady I added:
public function __toString()
{
return $this->getTitle(); // getTitle is in ZakladyTranslation!
}
In Pracownik I changed:
/**
* #ORM\ManyToOne(targetEntity="ZakladyTranslation")
**/
private $zaklady;
to:
/**
* #ORM\ManyToOne(targetEntity="Zaklady")
**/
private $zaklady;
and PracownikAdmin:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('translations', 'a2lix_translations')
->add('zaklady', 'sonata_type_model', array(
'multiple' => true,
'by_reference' => false,
'required' => false
))
;
}
I have a form customer registration type with an embed address form (billingAddress and an other optional ShippingAddress).
If the user don't check the "different shipping Address" checkbox, I should have only one addrress in my db address table. Even so I get two differents addresses in my Address table (with the same informations).
However, I check with "addAddress" if the address is already exist before add a new address. In fact in my Customer FormType, I copy billingAddress form data in shippingAdress form but in hasAdress method, $this->addresses->contains($address) return always false. I don't understand why...
Thanks
Here the code:
Customer Class
<?php
namespace DRMS\CustomerBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use DRMS\AddressingBundle\Entity\Address;
/**
* DRMS\CustomerBundle\Entity\Customer
*
* #ORM\Entity(repositoryClass="DRMS\CustomerBundle\Repository\CustomerRepository")
* #ORM\Table(name="customer", uniqueConstraints={#ORM\UniqueConstraint(name="customer_id_UNIQUE", columns={"customer_id"})})
*/
class Customer
{
/**
* #ORM\Id
* #ORM\Column(type="integer", name="customer_id")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $customerId;
// Others attributes
// ...
/**
* #ORM\OneToOne(targetEntity="DRMS\AddressingBundle\Entity\Address")
* #ORM\JoinColumn(name="billing_address_id", referencedColumnName="address_id")
*/
protected $billingAddress;
/**
* #ORM\OneToOne(targetEntity="DRMS\AddressingBundle\Entity\Address")
* #ORM\JoinColumn(name="shipping_address_id", referencedColumnName="address_id")
*/
protected $shippingAddress;
/**
* #ORM\OneToMany(targetEntity="DRMS\AddressingBundle\Entity\Address", mappedBy="customer", cascade={"remove", "persist"})
** ORM\JoinColumn(name="customer_id", referencedColumnName="customer_id", onDelete="CASCADE")
*/
protected $addresses;
public function __construct()
{
$this->addresses = new ArrayCollection();
}
/**
* Set the value of customerId.
*
* #param integer $customerId
* #return \DRMS\CustomerBundle\Entity\Customer
*/
public function setCustomerId($customerId)
{
$this->customerId = $customerId;
return $this;
}
/**
* Get the value of customerId.
*
* #return integer
*/
public function getCustomerId()
{
return $this->customerId;
}
// Others Getters/Setters
// ...
/**
* Set billingAddress
*
* #param \DRMS\AddressingBundle\Entity\Address $billingAddress
* #return Customer
*/
public function setBillingAddress(Address $billingAddress = null)
{
$this->billingAddress = $billingAddress;
if (null !== $billingAddress && !$this->hasAddress($billingAddress)) {
$this->addAddress($billingAddress);
}
return $this;
}
/**
* Get billingAddress
*
* #return \DRMS\AddressingBundle\Entity\Address
*/
public function getBillingAddress()
{
return $this->billingAddress;
}
/**
* Set shippingAddress
*
* #param \DRMS\AddressingBundle\Entity\Address $shippingAddress
* #return Customer
*/
public function setShippingAddress(Address $shippingAddress = null)
{
$this->shippingAddress = $shippingAddress;
if (null !== $shippingAddress && !$this->hasAddress($shippingAddress)) {
$this->addAddress($shippingAddress);
}
return $this;
}
/**
* Get shippingAddress
*
* #return \DRMS\AddressingBundle\Entity\Address
*/
public function getShippingAddress()
{
return $this->shippingAddress;
}
/**
* Add Address entity to collection (one to many).
*
* #param \DRMS\AddressingBundle\Entity\Address $address
* #return \DRMS\CustomerBundle\Entity\Customer
*/
public function addAddress(Address $address)
{
if (!$this->hasAddress($address)) {
$this->addresses->add($address);
$address->setCustomer($this);
}
return $this;
}
/**
* Remove Address
*
* #param \DRMS\AddressingBundle\Entity\Address $address
* #return \DRMS\CustomerBundle\Entity\Customer
*/
public function removeAddress(Address $address) {
$this->addresses->removeElement($address);
return $this;
}
/**
* Get Address entity collection (one to many).
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getAddresses()
{
return $this->addresses;
}
/**
* Has address
*
* #param \DRMS\AddressingBundle\Entity\Address $address
* #return bool
*/
public function hasAddress(Address $address)
{
return $this->addresses->contains($address);
}
}
Address class
<?php
namespace DRMS\AddressingBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
/**
* DRMS\AddressingBundle\Entity\Address
*
* #ORM\Entity(repositoryClass="DRMS\AddressingBundle\Repository\AddressRepository")
* #ORM\Table(name="address"), uniqueConstraints={#ORM\UniqueConstraint(name="customer_adress_UNIQUE", columns={"customer_id","address_id"})}
*/
class Address
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $address_id;
// Others attributes
// ...
/**
* #ORM\ManyToOne(targetEntity="DRMS\CustomerBundle\Entity\Customer", inversedBy="addresses", cascade={"remove"})
* #ORM\JoinColumn(name="customer_id", referencedColumnName="customer_id", onDelete="CASCADE")
*/
protected $customer;
/**
* Get the value of address_id.
*
* #return integer
*/
public function getAddressId()
{
return $this->address_id;
}
/**
* Set customer
*
* #param \DRMS\CustomerBundle\Entity\Customer $customer
* #return Address
*/
public function setCustomer(\DRMS\CustomerBundle\Entity\Customer $customer)
{
$this->customer = $customer;
return $this;
}
/**
* Get customer
*
* #return \DRMS\CustomerBundle\Entity\Customer
*/
public function getCustomer()
{
return $this->customer;
}
}
Customer FormType
<?php
# src\DRMS\CustomerBundle\Form\Type\CustomerType.php
namespace DRMS\CustomerBundle\Form\Type;
/**
* Description of CustomerType
*
*/
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
class CustomerType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
if (!array_key_exists('differentShippingAddress', $data) || false === $data['differentShippingAddress']) {
$data['shippingAddress'] = $data['billingAddress'];
$event->setData($data);
}
});
$builder->add('customerName', null)
->add('customerFirstname', null)
->add('phone')
->add('mobilePhone')
->add('billingAddress', 'drms_address', array(
'label' => 'drms.form.customer.billing_address',
))
->add('differentShippingAddress', 'checkbox', array(
'mapped' => false,
'label' => 'drms.form.customer.different_shipping_address',
'required' => false,
))
->add('shippingAddress', 'drms_address', array(
'label' => 'drms.form.customer.shipping_address',
))
;
}
/**
* #param OptionsResolverInterface $resolver
*
* If checkbox vatNumberOwner is checked, apply "vat_number_required" validation group for activate Vat Number test
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'DRMS\CustomerBundle\Entity\Customer',
'validation_groups' => function(FormInterface $form) {
$validation_groups = array('Registration');
if($form->get('differentShippingAddress')->getData() == true) {
$validation_groups[] = 'ShippingAddressRequired';
}
return $validation_groups;
},
));
}
public function getName()
{
return 'drms_customer';
}
}
contains() is implemented like this https://github.com/doctrine/collections/blob/master/lib/Doctrine/Common/Collections/ArrayCollection.php#L189 That means you are doing a strict comparison on the object identity. Since the address object is created by the form and not managed by Doctrine in the identity map it will not compare to the objects created by Doctrine. Since custom collections are not supported i suggest you change the in_array logic to be not strict and put it in your entity directly.
I am stuck and frustrated with the bellow error message:
Catchable Fatal Error: Argument 1 passed to Medicine\UserBundle\Entity\User
::setUsertype() must be an instance of Medicine\UserBundle\Entity\Usertype,
instance of Doctrine\Common\Collections\ArrayCollection given, called in
/opt/lampp/htdocs/drugs/vendor/symfony/src/Symfony/Component/Form/Util
/PropertyPath.php on line 347 and defined in /opt/lampp/htdocs/drugs/src/
Medicine/UserBundle/Entity/User.php line 224
What I think this error is due to use of manytoone field in my entity, I even tried with keeping onetomany in another entity.
I have a user entity and a usertype entity, the usertype_id is a manytoone field in user table. here is the code for both the entities:-
User
namespace Medicine\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="Medicine\UserBundle\Repository\UserRepository")
* #ORM\Table(name="user")
* #ORM\HasLifecycleCallbacks()
*/
class User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\HasLifecycleCallbacks()
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $username;
/**
* #ORM\ManyToOne(targetEntity="Usertype", inversedBy="users")
* #ORM\JoinColumn(name="usertype_id", referencedColumnName="id")
*/
protected $usertype;
/**
* #ORM\Column(type="string")
*/
protected $image;
/**
* Set usertype
*
* #param Medicine\UserBundle\Entity\Usertype $usertype
*/
public function setUsertype(\Medicine\UserBundle\Entity\Usertype $usertype)
{
$this->usertype = $usertype;
}
/**
* Get usertype
*
* #return Medicine\UserBundle\Entity\Usertype
*/
public function getUsertype()
{
return $this->usertype;
}
}
I am just showing the concerned code, i have all the getter and setter methods for the above code.
UserType
namespace Medicine\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="Medicine\UserBundle\Repository\UsertypeRepository")
* #ORM\Table(name="usertype")
* #ORM\HasLifecycleCallbacks()
*/
class Usertype
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\HasLifecycleCallbacks()
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="User", mappedBy="usertype")
*/
protected $users;
public function __construct()
{
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add users
*
* #param Medicine\UserBundle\Entity\User $users
*/
public function addUser(\Medicine\UserBundle\Entity\User $users)
{
$this->users[] = $users;
}
/**
* Get users
*
* #return Doctrine\Common\Collections\Collection
*/
public function getUsers()
{
return $this->users;
}
}
Controller
This Executes when a user wants to login. He will fill in the username password and a UserType:
public function indexAction()
{
$entity = new User();
$form = $this->createForm(new LoginForm(), $entity);
$request = $this->getRequest();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
echo "<pre>"; print_r($entity->getUsertype()); exit;
$em = $this->getDoctrine()
->getEntityManager();
$em->persist($entity);
$userrepository = $em->getRepository('MedicineUserBundle:User');
echo "<pre>"; print_r($entity->getUsertype()); exit;
$all = $userrepository->findOneBy(array('login' => $entity->getLogin(), 'password' => $entity->getPassword()));
if($all)
{
return $this->redirect($this->generateUrl('MedicineUserBundle_login'));
}
}
}
return $this->render('MedicineUserBundle:User:loginpage.html.twig',array(
'form' => $form->createView()
));
}
Login Form
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('login', 'text', array('label' => 'Username',))
->add('password','password')
->add('usertype', 'entity', array('class' => 'MedicineUserBundle:Usertype', 'property'=>'name', 'multiple' => true, ))
;
}
The 'multiple' => true in combination with your entity association definition is causing this problem.
You should find that if you change multiple to false (and as such can only select one UserType for your User), things work properly.
If you want multiple UserTypes for one User, you have a Many-to-Many association - one user can have many UserTypes, and one UserType can have many Users. See Doctrine's ManyToMany association type to implement this. Documentation Here.
Hope this helps.