I need to save user with his profile fields. I establish relations. User has one Profile, Profile has one User. I add fields to register form. But when I saving object, I get error,
Undefined index: profile in /var/www/Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php line 2714 . Where my mistake, please help me. I am newbie)
Here is the code:
namespace Acme\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Profile
*
* #ORM\Table(name="acme_profile")
* #ORM\Entity
*/
class Profile
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="fio", type="string", length=255)
*/
protected $fio;
/**
* #ORM\Column(name="birthDate", type="date")
*/
protected $birthDate;
/**
* #ORM\OneToOne(targetEntity="Acme\UserBundle\Entity\User", cascade={"persist"})
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getFio()
{
return $this->fio;
}
/**
* #param $fio
* #return $this
*/
public function setFio($fio)
{
$this->fio = $fio;
return $this;
}
/**
* #return mixed
*/
public function getBirthDate()
{
return $this->birthDate;
}
/**
* #param $birthDate
* #return $this
*/
public function setBirthDate($birthDate)
{
$this->birthDate = $birthDate;
return $this;
}
/**
* #return mixed
*/
public function getUser()
{
return $this->user;
}
/**
* #param User $user
* #return $this
*/
public function setUser(User $user = null)
{
$this->user = $user;
return $this;
}
}
namespace Acme\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="acme_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToOne(targetEntity="Acme\UserBundle\Entity\Profile", cascade={"persist"})
*/
protected $profile;
public function __construct()
{
parent::__construct();
}
public function setProfile(Profile $profile = null)
{
$this->profile = $profile;
return $this;
}
public function getProfile()
{
return $this->profile;
}
}
namespace Acme\UserBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RegistrationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// add your custom field
$builder->add('profile', new ProfileType());
}
public function getParent()
{
return 'fos_user_registration';
}
public function getName()
{
return 'acme_user_registration';
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\UserBundle\Entity\User'
));
}
}
You should use the MappedBy and InversedBy as specified in the documentation here : http://docs.doctrine-project.org/en/2.0.x/reference/association-mapping.html#owning-side-and-inverse-side
/**
* #ORM\OneToOne(targetEntity="Acme\UserBundle\Entity\Profile",
mappedBy="user"))
*/
and the other side you use :
/**
* #ORM\OneToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="profile" cascade={"persist"})
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
Related
I'm working with symfony 3.4 and the bundle l3-db-userbundle, i have a problem when I tried add atributtes to the Entity of bundle...
This is my Entity in AppBundle\Entity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use L3\Bundle\DbUserBundle\Entity\User;
/**
* XUser
*
* #ORM\Table(name="x_user")
* #ORM\Entity
*/
class XUser extends User
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="nombre", type="string", length=100, nullable=false)
*/
private $nombre;
/**
* #var string
*
* #ORM\Column(name="apellido", type="string", length=100, nullable=false)
*/
private $apellido;
/**
* #var string
*
* #ORM\Column(name="dni", type="string", length=20, nullable=false)
*/
private $dni;
/**
* #var string
*
* #ORM\Column(name="uid", type="string", length=15, nullable=false)
*/
private $uid;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="XRole", inversedBy="user")
* #ORM\JoinTable(name="x_user_role",
* joinColumns={
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="role_id", referencedColumnName="id")
* }
* )
*/
private $role;
/**
* Constructor
*/
public function __construct()
{
$this->role = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set id
*
* #param string $id
* #return User
*/
public function setId($id) {
$this->id = $id;
return $this;
}
/**
* #return string
*/
public function getNombre()
{
return $this->nombre;
}
/**
* #param string $nombre
*/
public function setNombre(string $nombre)
{
$this->nombre = $nombre;
}
/**
* #return string
*/
public function getApellido()
{
return $this->apellido;
}
/**
* #param string $apellido
*/
public function setApellido(string $apellido)
{
$this->apellido = $apellido;
}
/**
* #return string
*/
public function getDni()
{
return $this->dni;
}
/**
* #param string $dni
*/
public function setDni(string $dni)
{
$this->dni = $dni;
}
/**
* #return string
*/
public function getUid()
{
return $this->uid;
}
/**
* Set uid
*
* #param string $uid
* #return User
*/
public function setUid($uid) {
$this->uid = $uid;
return $this;
}
/**
* #return \Doctrine\Common\Collections\Collection
*/
public function getRole()
{
return $this->role;
}
/**
* #param \Doctrine\Common\Collections\Collection $role
*/
public function setRole(\Doctrine\Common\Collections\Collection $role)
{
$this->role = $role;
}
}
And this is the class of vendor
<?php
namespace L3\Bundle\DbUserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Table(name="x_user")
* #ORM\Entity(repositoryClass="L3\Bundle\DbUserBundle\Repository \UserRepository")
*/
class User implements UserInterface, \Serializable {
/**
* #var integer $id
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="uid", type="string", length=15)
*/
private $uid;
/**
* #ORM\ManyToMany(targetEntity="Role", cascade={"persist"})
* #ORM\JoinTable(name="x_user_role",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="role_id", referencedColumnName="id")}
* )
* #var ArrayCollection $roles
*/
private $roles;
public function __construct() {
}
/**
* Get id
*
* #return integer
*/
public function getId() {
return $this->id;
}
/**
* Set id
*
* #param string $id
* #return User
*/
public function setId($id) {
$this->id = $id;
return $this;
}
/**
* Get uid
*
* #return string
*/
public function getUid() {
return $this->uid;
}
/**
* Set uid
*
* #param string $uid
* #return User
*/
public function setUid($uid) {
$this->uid = $uid;
return $this;
}
//Source : http://www.metod.si/symfony2-error-usernamepasswordtokenserialize-must-return-a-string-or-null/
public function serialize() {
return serialize(array(
$this->id,
$this->uid
));
}
public function unserialize($serialize) {
list(
$this->id,
$this->uid
) = unserialize($serialize);
}
public function eraseCredentials() {
//pas d'implémentation nécessaire
}
public function getPassword() {
//pas d'implémentation nécessaire
}
public function getRoles() {
$roles = array();
foreach ($this->roles as $role) {
if (!in_array($role->getRole(), $roles)) {
$roles[] = $role->getRole();
}
}
$roles[] = "ROLE_USER";
return $roles;
}
public function getSalt() {
//pas d'implémentation nécessaire
}
public function getUsername() {
return $this->getUid();
}
public function __toString() {
return $this->getUid();
}
}
When I try to get data from database, it show me an error: Attempted to call an undefined method named "getNombre" of class "L3\Bundle\DbUserBundle\Entity\User".
This is the method where i have the problem:
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\XUser;
use AppBundle\Entity\XUserOffice;
use AppBundle\Form\UserType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class UserController
* #Route("/users")
*/
class UserController extends Controller
{
/**
* #Route("/", name="users_list")
* #Template("#App/user/index.html.twig")
*/
public function indexAction(Request $request)
{
$users = $this->getDoctrine()->getRepository('AppBundle:XUser')->findAll();
$list = [];
foreach ($users as $user) {
$role = $this->getRole($user->getId());
$dat['id'] = $user->getId();
$dat['name'] = $user->getNombre() . ' ' . $user->getApellido();
$dat['dni'] = $user->getDni();
$dat['role'] = $role['role'];
$list[] = $dat;
}
return [
'list' => $list
];
}
I have this issues "Warning: spl_object_hash() expects parameter 1 to be object, string given" when I try to save the onetomay entity side of my relationship, the code below may be give you some ideas:
<?php
namespace BackendBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* BulletinSalaire
*
* #ORM\Table(name="bulletin_salaire")
* #ORM\Entity(repositoryClass="BackendBundle\Repository\BulletinSalaireRepository")
*/
class BulletinSalaire
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="periode", type="date")
*/
private $periode;
/**
* #var string
*
* #ORM\Column(name="mode_reglement", type="string", length=255)
*/
private $modeReglement;
/**
*
* #ORM\ManyToOne(targetEntity="Employee", inversedBy="employees", cascade={"persist"})
* #ORM\JoinColumn(name="id_employee", referencedColumnName="id")
*/
private $employee;
/**
*
* #ORM\OneToMany(targetEntity="LibelleBulletin", mappedBy="bulletinsalaire", cascade={"persist"})
* #ORM\JoinColumn(name="id_libelleBulltin", referencedColumnName="id")
*/
private $libelleBulletins;
public function __construct()
{
$this->libelleBulletins= new ArrayCollection();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set libelle
*
* #param string $libelle
*
* #return BulletinSalaire
*/
public function setLibelle($libelle)
{
$this->libelle = $libelle;
return $this;
}
/**
* Get libelle
*
* #return string
*/
public function getLibelle()
{
return $this->libelle;
}
/**
* Set base
*
* #param integer $base
*
* #return BulletinSalaire
*/
public function setBase($base)
{
$this->base = $base;
return $this;
}
/**
* Get base
*
* #return int
*/
public function getBase()
{
return $this->base;
}
/**
* Set retenues
*
* #param float $retenues
*
* #return BulletinSalaire
*/
public function setRetenues($retenues)
{
$this->retenues = $retenues;
return $this;
}
/**
* Get retenues
*
* #return float
*/
public function getRetenues()
{
return $this->retenues;
}
/**
* Set periode
*
* #param \DateTime $periode
*
* #return BulletinSalaire
*/
public function setPeriode($periode)
{
$this->periode = $periode;
return $this;
}
/**
* Get periode
*
* #return \DateTime
*/
public function getPeriode()
{
return $this->periode;
}
/**
* Set modeReglement
*
* #param string $modeReglement
*
* #return BulletinSalaire
*/
public function setModeReglement($modeReglement)
{
$this->modeReglement = $modeReglement;
return $this;
}
/**
* Get modeReglement
*
* #return string
*/
public function getModeReglement()
{
return $this->modeReglement;
}
/**
* #return mixed
*/
public function getEmployee()
{
return $this->employee;
}
/**
* #param mixed $employee
*/
public function setEmployee($employee)
{
$this->employee = $employee;
}
/**
* #param LibelleBulletin $libellebulletin
* #return $this
*/
public function addLibelleBulletin(LibelleBulletin $libellebulletin)
{
$this->libelleBulletins[] = $libellebulletin;
$libellebulletin->setBulletinSalaire($this);
return $this;
}
/**
* #param LibelleBulletin $libellebulletin
*/
public function removeLibelleBulletin(LibelleBulletin $libellebulletin)
{
$this->libelleBulletins->removeElement($libellebulletin);
}
public function getLibelleBulletins()
{
return $this->libelleBulletins;
}
}
/---------------------Entity Many libelle to one bulletin de salaire ----------------/
<?php
/**
* Created by PhpStorm.
* User: achouri
* Date: 17/11/2016
* Time: 4:05 PM
*/
namespace BackendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* BulletinSalaire
*
* #ORM\Table(name="libelle_bulletins")
* #ORM\Entity()
*/
class LibelleBulletin
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="BulletinSalaire", inversedBy="libellebulletins")
* #ORM\JoinColumn(nullable=false)
*/
private $bulletinSalaire;
/**
* #var string
*
* #ORM\Column(name="libelle", type="string", length=255)
*
*/
private $libelle;
/**
* #var int
*
* #ORM\Column(name="base", type="integer")
*/
private $base;
/**
* #var float
*
* #ORM\Column(name="retenues", type="float")
*/
private $retenues;
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* #param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return string
*/
public function getLibelle()
{
return $this->libelle;
}
/**
* #param string $libelle
*/
public function setLibelle($libelle)
{
$this->libelle = $libelle;
}
/**
* #return int
*/
public function getBase()
{
return $this->base;
}
/**
* #param int $base
*/
public function setBase($base)
{
$this->base = $base;
}
/**
* #return float
*/
public function getRetenues()
{
return $this->retenues;
}
/**
* #param float $retenues
*/
public function setRetenues($retenues)
{
$this->retenues = $retenues;
}
/**
* #return mixed
*/
public function getBulletinSalaire()
{
return $this->bulletinSalaire;
}
/**
* #param mixed $bulletinSalaire
*/
public function setBulletinSalaire($bulletinSalaire)
{
$this->bulletinSalaire = $bulletinSalaire;
}
}
/---------------------bulletinsallaireType---------------------------/
<?php
namespace BackendBundle\Form;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use BackendBundle\Form\LibelleBulletinType;
class BulletinSalaireType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('libelleBulletins',LibelleBulletinType::class,array('label' => '','data_class' => null))
->add('periode')->add('modeReglement')
->add('employee',EntityType::class,array('attr' => array(
'class' => 'form-control'),
'class' => 'BackendBundle:Employee',
'choice_label' => function ($employee) {
return $employee->getNom()." ".$employee->getPrenom();
}));
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'BackendBundle\Entity\BulletinSalaire'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'backendbundle_bulletinsalaire';
}
}
/------------------------libelleBultinType-----------------------/
<?php
namespace BackendBundle\Form;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use BackendBundle\Form\EmployeeType;
class LibelleBulletinType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('libelle')->add('base')->add('retenues');
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'BackendBundle\Entity\LibelleBulletin'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'backendbundle_libellebulletin';
}
}
/----------------------Action du save-----------------/
/**
* Creates a new bulletinSalaire entity.
*
* #Route("/new", name="bulletinsalaire_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$bulletinSalaire = new Bulletinsalaire();
$libellebulletin= new LibelleBulletin();
$form = $this->createForm('BackendBundle\Form\BulletinSalaireType', $bulletinSalaire);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$bulletinSalaire->addLibelleBulletin($libellebulletin);
$em->persist($bulletinSalaire);
$em->flush($bulletinSalaire);
return $this->redirectToRoute('bulletinsalaire_show', array('id' => $bulletinSalaire->getId()));
}
return $this->render('BackendBundle:bulletinsalaire:new.html.twig', array(
'bulletinSalaire' => $bulletinSalaire,
'form' => $form->createView(),
));
}
As #xabbuh pointed, we need to see how do you create the object. Looks like you are trying to set $employee or $libelleBulletins with a string instead of an object.
This is wrong.
$bulletin->setEmployee('some value');
This is right.
$employee = $dm->getRepository('BackendBundle:Employee')->findOneById('employeeId');
$bulletin->setEmployee($employee);
i want to remove an role from the roles-ArrayCollection in the User Entity.
User and Role have an M:N connection.
In my Controller:
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('UserBundle:User')->find($userId);
$user->removeRole($roleID);
$em->flush();
If I execute the controller, there are no error messages.
But the Role is still assigned to the user.
User Entity
namespace Chris\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* User
*
* #ORM\Table(name="usermanagement_users")
* #ORM\Entity(repositoryClass="Chris\UserBundle\Entity\UserRepository")
*/
class User implements UserInterface,\Serializable
{
/**
* #ORM\ManyToMany(targetEntity="Role", inversedBy="users")
*
*/
private $roles;
public function __construct()
{
$this->roles = new ArrayCollection();
$this->isActive = true;
}
/**
* #inheritDoc
*/
public function getRoles()
{
return $this->roles->toArray();
}
public function setRoles($roles){
$this->roles[] = $roles;
}
public function removeRole($role){
unset($this->roles->toArray()[$role]);
}
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=25, unique=true)
*/
private $username;
/**
* #ORM\Column(type="string", length=64)
*/
private $password;
/**
* #ORM\Column(type="string", length=60, unique=true)
*/
private $email;
/**
* #ORM\Column(type="string", length=60)
*/
private $vorname;
/**
* #ORM\Column(type="string", length=60)
*/
private $nachname;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $letzterLogin;
/**
* #ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
public function setId($id){
$this->id = $id;
}
/**
* #inheritDoc
*/
public function getId()
{
return $this->id;
}
/**
* #inheritDoc
*/
public function eraseCredentials()
{
}
/**
* #see \Serializable::serialize()
*/
public function serialize()
{
return serialize(array(
$this->id,
$this->username,
$this->password,
// see section on salt below
// $this->salt,
));
}
/**
* #see \Serializable::unserialize()
*/
public function unserialize($serialized)
{
list (
$this->id,
$this->username,
$this->password,
// see section on salt below
// $this->salt
) = unserialize($serialized);
}
}
Role Entity
<?php
/**
* Created by PhpStorm.
* User: christianschade
* Date: 02.02.15
* Time: 19:29
*/
namespace Chris\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\Role\RoleInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Role
* #ORM\Entity(repositoryClass="Chris\UserBundle\Entity\RoleRepository")
* #ORM\Table(name="usermanagement_roles")
*/
class Role implements RoleInterface {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="role", type="string", length=20, unique=true)
*/
private $role;
public function getRole() {
return $this->role;
}
/**
* #ORM\ManyToMany(targetEntity = "User", inversedBy = "roles")
*
* #var ArrayCollection $users
*/
protected $users;
/**
* #return ArrayCollection
*/
public function getUsers()
{
return $this->users;
}
/**
* #param ArrayCollection $users
*/
public function setUsers($users)
{
$this->users = $users;
}
public function setRoles($roles)
{
$this->role = $roles;
// allows for chaining
return $this;
}
/**
* #inheritDoc
*/
public function getId()
{
return $this->id;
}
/**
* #ORM\ManyToMany(targetEntity = "Chris\UserBundle\Entity\Group", inversedBy = "groups")
*
* #var ArrayCollection $group
*/
private $group;
/**
* #return ArrayCollection
*/
public function getGroup()
{
return $this->group;
}
/**
* #param ArrayCollection $group
*/
public function setGroup($group)
{
$this->group = $group;
}
}
You should use ArrayCollection::removeElement() to remove the role.
public function removeRole($role)
{
$this->roles->removeElement($role);
}
On a side note, I feel your getRoles() implementation is unorthodox as it would be recommended to return the ArrayCollection as is and call toArray() if you need to once you have retrieved it.
public function getRoles()
{
return $this->roles;
}
I'm working with Symfony2 2.3 and I need sharing data between two entities trough the DotrineFixturesBundle
But the Sharing Objects between Fixtures dont work.
When the command is executed
php app/console doctrine:fixtures:load --purge-with-truncate
the data is load, But the fields with relations are NULL
Table Divterrigral
ID DESCRIPTION
1 description
Table with FK Divterribase
ID DIVTERRIGRAL_ID DESCRIPTION
1 Null descriptionInfo
if I do mysql through I can map the relationship works.
the class LoadDivterrigral.
<?php
namespace Soint\InventarioBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Soint\InventarioBundle\Entity\Divterrigral;
class LoadDivterrigral extends AbstractFixture implements OrderedFixtureInterface{
/**
* {#inheritDoc}
*/
public function load(ObjectManager $manager){
$ahuachapan = new Divterrigral();
$ahuachapan->setNombre('Ahuachapan');
$manager->persist($ahuachapan);
$manager->flush();
$this->addReference('dep-ahuachapan', $ahuachapan);
}
/**
* {#inheritDoc}
*/
public function getOrder(){
return 1; // el orden en el cual serán cargados los accesorios
}
}
The class LoadDivTerribase
<?php
namespace Soint\InventarioBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Soint\InventarioBundle\Entity\Divterribase;
class LoadDivterribase extends AbstractFixture implements OrderedFixtureInterface {
/**
* {#inheritDoc}
*/
public function load(ObjectManager $manager){
$ahuachapan = new Divterribase();
$ahuachapan->setNombre('Ahuachapan');
$ahuachapan->setDivterrigral($this->getReference('dep-ahuachapan'));
$manager->persist($ahuachapan);
$manager->flush();
}
/**
* {#inheritDoc}
*/
public function getOrder(){
return 2;
}
}
Entity Divterrigral
<?php
namespace Soint\InventarioBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Soint\InventarioBundle\Entity\Divterribase;
/**
* #ORM\Entity
*/
class Divterrigral {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue;
*/
protected $id;
/** #ORM\Column(type="string", length=100) */
protected $nombre;
/**
* #ORM\OneToMany(targetEntity="Divterribase", mappedBy="divterrigral")
*/
protected $divterribases;
public function __construct() {
$this->divterribases = new ArrayCollection();
}
public function addDivterribases(Articulo $articulos){
$this->divterribases[] = $articulos;
}
public function getDivterribases(){
return $this->divterribases;
}
/**
* Get id
* #return integer
*/
public function getId(){
return $this->id;
}
/**
* Set nombre
* #param string $nombre
* #return Divterrigral
*/
public function setNombre($nombre){
$this->nombre = $nombre;
return $this;
}
/**
* Get nombre
* #return string
*/
public function getNombre(){
return $this->nombre;
}
public function __toString(){
return $this->getNombre();
}
}
Entity Divterribase
<?php
namespace Soint\InventarioBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Soint\InventarioBundle\Entity\Divterrigral;
/**
* #ORM\Entity
*/
class Divterribase {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue;
*/
protected $id;
/** #ORM\Column(type="string", length=100) */
protected $nombre;
/**
* #ORM\ManyToOne(targetEntity="Divterrigral", inversedBy="divterribases")
* #ORM\JoinColumn(name="divterrigral_id", referencedColumnName="id")
* #return integer
*/
protected $divterrigral;
/**
* Get id
* #return integer
*/
public function getId(){
return $this->id;
}
/**
* Set nombre
* #param string $nombre
* #return Divterribase
*/
public function setNombre($nombre){
$this->nombre = $nombre;
return $this;
}
/**
* Get nombre
* #return string
*/
public function getNombre(){
return $this->nombre;
}
/**
* Set divTerriGral
* #param Soint\InventarioBundle\Entity\Divterrigral $divTerriGral
* #return Divterribase
*/
public function setDivterrigral(Divterrigral $divTerriGral = null){
$this->divTerriGral = $divTerriGral;
return $this;
}
/**
* Get divTerriGral
* #return Soint\InventarioBundle\Entity\Divterrigral
*/
public function getDivterrigral(){
return $this->divTerriGral;
}
public function __toString(){
return $this->getNombre();
}
}
Entity Divterrigral
/**
* #ORM\OneToMany(targetEntity="Divterribase", mappedBy="divterrigral",cascade={"persist", "remove"})
*/
protected $divterribases;
Further reading : http://doctrine-orm.readthedocs.org/en/2.0.x/reference/working-with-associations.html#transitive-persistence-cascade-operations
I'm building a form generator using Symfony 2.2 with Doctrine. The base principle is that the user create a new form by filling its name and selecting the widgets he'd likes to have in a select menu.
We can think of WidgetInputText, WidgetSelect, WidgetFile, etc.
Here is an example of my model:
<?php
namespace Ineat\FormGeneratorBundle\Entity\Widget;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
/**
* Widget
*
* #ORM\Table(name="widget")
* #ORM\Entity
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="discr", type="string")
* #ORM\DiscriminatorMap({"widget_text" = "WidgetText", "widget_input_text" = "WidgetInputText", "widget_select" = "WidgetSelect"})
*/
abstract class Widget
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Form", inversedBy="widgets")
*/
private $form;
/**
* #var integer
*
* #ORM\OneToOne(targetEntity="Question")
*/
private $question;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set form
*
* #param \Ineat\FormGeneratorBundle\Entity\Form $form
* #return Widget
*/
public function setForm(\Ineat\FormGeneratorBundle\Entity\Form $form = null)
{
$this->form = $form;
return $this;
}
/**
* Get form
*
* #return \Ineat\FormGeneratorBundle\Entity\Form
*/
public function getForm()
{
return $this->form;
}
/**
* Set question
*
* #param \Ineat\FormGeneratorBundle\Entity\Question $question
* #return Widget
*/
public function setQuestion(\Ineat\FormGeneratorBundle\Entity\Question $question = null)
{
$this->question = $question;
return $this;
}
/**
* Get question
*
* #return \Ineat\FormGeneratorBundle\Entity\Question
*/
public function getQuestion()
{
return $this->question;
}
}
<?php
namespace Ineat\FormGeneratorBundle\Entity\Widget;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
/**
* Widget
*
* #ORM\Entity
* #ORM\Table(name="widget_text")
*/
class WidgetText extends Widget
{
/**
* #var string
*
* #ORM\Column(type="text")
*/
private $text;
/**
* Set text
*
* #param string $text
* #return WidgetText
*/
public function setText($text)
{
$this->text = $text;
return $this;
}
/**
* Get text
*
* #return string
*/
public function getText()
{
return $this->text;
}
}
<?php
namespace Ineat\FormGeneratorBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Form
*
* #ORM\Table(name="form")
* #ORM\Entity(repositoryClass="Ineat\FormGeneratorBundle\Entity\FormRepository")
* #UniqueEntity("name")
* #UniqueEntity("slug")
*/
class Form
{
/**
* #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;
/**
* #var string
*
* #ORM\Column(name="slug", type="string", length=255)
*/
private $slug;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="Widget", mappedBy="form", cascade={"persist"})
*/
private $widgets;
public function __construct()
{
$this->widgets = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Form
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set slug
*
* #param string $slug
* #return Form
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Add widgets
*
* #param \Ineat\FormGeneratorBundle\Entity\Widget\Widget $widget
* #return Form
*/
public function addWidget(\Ineat\FormGeneratorBundle\Entity\Widget\Widget $widget)
{
$this->widgets[] = $widget;
return $this;
}
/**
* Remove widgets
*
* #param \Ineat\FormGeneratorBundle\Entity\Widget\Widget $widget
*/
public function removeWidget(\Ineat\FormGeneratorBundle\Entity\Widget\Widget $widget)
{
$this->widgets->removeElement($widget);
}
/**
* Get widgets
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getWidgets()
{
return $this->widgets;
}
/**
* Set widgets
*
* #param \Doctrine\Common\Collections\Collection $widgets
*/
public function setWidget(\Doctrine\Common\Collections\Collection $widgets)
{
$this->widgets = $widgets;
}
public function __set($name, $obj)
{
if (is_a($obj, '\Ineat\FormGeneratorBundle\Entity\Widget\Widget')) {
$this->addWidget($obj);
}
}
}
As you can see a form can have multiple widgets attached to him.
I've made an abstract class Widget because all widgets have common fields and are of type Widget and because in the Form entity it seems really really bad to had one collection per Widget type (bad and boring).
This model works, I've unit tested it and I'm able to attach a WidgetText to a form and then retrieve it.
The issue comes when I try to use forms with it.
<?php
namespace Ineat\FormGeneratorBundle\Form;
use Ineat\FormGeneratorBundle\Entity\Widget\WidgetText;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class FormType extends AbstractType
{
protected $widgets;
public function __construct(array $widgets = array())
{
$this->widgets = $widgets;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('slug', 'text')
->add('WidgetText', 'collection', array(
'type' => new WidgetTextType(),
'allow_add' => true,
'attr' => array('class' => 'widget-text'),
'by_reference' => false
))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Ineat\FormGeneratorBundle\Entity\Form',
));
}
public function getName()
{
return 'ineat_formgeneratorbundle_formtype';
}
}
<?php
namespace Ineat\FormGeneratorBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class WidgetTextType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('text', 'text')
;
}
public function getName()
{
return 'ineat_formgeneratorbundle_widgettexttype';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Ineat\FormGeneratorBundle\Entity\Widget\WidgetText',
));
}
}
When I try to display the form I've got the following error:
Neither property "WidgetText" nor method "getWidgetText()" nor method "isWidgetText()" exists in class "Ineat\FormGeneratorBundle\Entity\Form"
It's like Symfony doesn't know that my WidgetText is of type Widget too.
If in the controller (generated by Symfony) I change this line:
$this->createForm(new FormType(), new Form())
To:
$this->createForm(new FormType())
The form displays well but when submitting I've got no data binded.
I'm completly stuck there, from an OOP point of view I think this should work but I'm not sure if Symfony allows me to do what I want.
As mentioned in the comments of your question, you should change the name of the "WidgetText" field to "widgets". The reason behind that is that the names of the fields should match the accessors in your model (i.e. "name" for (set|get)Name(), "widgets" for (set|get)Widgets() etc.)
If you really want the name of a field to differ from the accessor in the model, you can also use the "property_path" option (which is set to the field's name by default):
$builder->add('WidgetText', ..., array(
...
'property_path' => 'widgets',
));