I've got fos_user entity that is in relation OneToOne with reservedArea entity.
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToOne(targetEntity="ReservedAreaBundle\Entity\ReservedArea", cascade={"persist"})
* #ORM\JoinColumn(name="reserved", referencedColumnName="id", onDelete="SET NULL")
*/
protected $reserved;
public function __construct()
{
parent::__construct();
}
public function getReserved()
{
return $this->reserved;
}
public function setReserved($reserved)
{
$this->reserved = $reserved;
}
}
In my reservedArea entity i've got only a OneToMany relation with File entity.
class ReservedArea
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="ReservedAreaBundle\Entity\File", mappedBy="reserved_area", cascade={"persist"})
*/
protected $file;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Constructor
*/
public function __construct()
{
$this->file = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add file
*
* #param \ReservedAreaBundle\Entity\File $file
*
* #return ReservedArea
*/
public function addFile(\ReservedAreaBundle\Entity\File $file)
{
$this->file[] = $file;
return $this;
}
/**
* Remove file
*
* #param \ReservedAreaBundle\Entity\File $file
*/
public function removeFile(\ReservedAreaBundle\Entity\File $file)
{
$this->file->removeElement($file);
}
/**
* Get file
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getFile()
{
return $this->file;
}
}
And in my File entity i've got just a simple string.
class File
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $file;
/**
* #ORM\ManyToOne(targetEntity="ReservedAreaBundle\Entity\ReservedArea", inversedBy="file")
* #ORM\JoinColumn(name="reserved_area", referencedColumnName="id")
*/
protected $reservedArea;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set reservedArea
*
* #param \ReservedAreaBundle\Entity\ReservedArea $reservedArea
*
* #return File
*/
public function setReservedArea(\ReservedAreaBundle\Entity\ReservedArea $reservedArea = null)
{
$this->reservedArea = $reservedArea;
return $this;
}
/**
* Get reservedArea
*
* #return \ReservedAreaBundle\Entity\ReservedArea
*/
public function getReservedArea()
{
return $this->reservedArea;
}
/**
* Set file
*
* #param string $file
*
* #return File
*/
public function setFile($file)
{
$this->file = $file;
return $this;
}
/**
* Get file
*
* #return string
*/
public function getFile()
{
return $this->file;
}
Now if i try to access to user file doing something like that :
$files = $this->getUser()->getReserved()->getFile();
foreach($files as $file) {
var_dump($file); //or $file->getFile();
}
I get an error :
Notice: Undefined index: reserved_area
In my database I add an user with a reserved area and two file and if i direct make :
SELECT u.username, f.file FROM fos_user u INNER JOIN reserved_area r ON u.reserved=r.id INNER JOIN reserved_area_file f ON f.reserved_area=r.id;
I get in output the right result.
Where i'm going wrong?
Thanks in advice.
I found the solution to the problem and I post it beacause maybe will help someone.
The problem is here:
/**
* #ORM\OneToMany(targetEntity="ReservedAreaBundle\Entity\File", mappedBy="reserved_area", cascade={"persist"})
*/
protected $file;
I can't use in mappedBy the name of the table in #JoinColumn(name="reserved_are") but I have to use the name of the attribute.
So :
mappedBy="reservedArea"
solved the problem.
EDIT: I answered the original question: https://stackoverflow.com/revisions/35969467/1
which was then edited by the author.
The annotation mapping of $reservedArea in File class is incorrect.
The mappedBy and inversedBy attributes must always contain name of the attribute from entity on the other side of the association.
So in your case File::$reservedArea should have inversedBy="file".
See http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-many-bidirectional for more examples.
Related
I have a problem with an empty ArrayCollection.
With one-to-many and many-to-one relationships
This is Brand entity:
class Brand
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Model[]
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Model", mappedBy="brand")
*/
private $models;
/**
* Brand constructor.
*/
public function __construct()
{
$this->models= new ArrayCollection();
}
/**
* #return Model[]|ArrayCollection
*/
public function getModels()
{
return $this->models;
}
/**
* #param Model $model
* #return $this
*/
public function addModel(Model $model)
{
$this->models[] = $model;
return $this;
}
}
And this is the Model entity:
class Model
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="modelName", type="string", length=60)
*/
private $modelName;
/**
* #var Brand
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Brand", inversedBy="models")
* #ORM\JoinColumn(name="brand_id", referencedColumnName="id")
*/
private $brand;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set modelName
*
* #param string $modelName
*
* #return Model
*/
public function setModelName($modelName)
{
$this->modelName = $modelName;
return $this;
}
/**
* Get modelName
*
* #return string
*/
public function getModelName()
{
return $this->modelName;
}
/**
* #param Brand $brand
* #return $this
*/
public function setBrand(Brand $brand)
{
$this->brand= $brand;
return $this;
}
/**
* #return Brand
*/
public function getBrand()
{
return $this->brand;
}
}
And Controller:
$UserRepo = $this->getDoctrine()->getRepository(Brand::class);
$all = $UserRepo->find($brandId);
Symfony does not return any error.
However, it only downloads the brandName corresponding to $ brandId. Unfortunately, the ArrayCollection is empty.
Can someone tell me where I made a mistake :(
in my symfony app, i'm using embedded forms. In my case, an object "CompetenceGroupe" can have multiple objects "CompetenceItem", but an object "CompetenceItem" belongs to only one object "CompetenceGroupe", so the relation is manyToOne.
The form work perfectly, and I have two tables (one for each entity), and it's well saved in the database.
But when I select an CompetenceGroupe object with doctrine in my controller, I have all informations of the object, and he's got an empty "competenceItems" property, so I can't retrieve the childs object (CompetenceItem).
My "CompetenceGroupe" entity :
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="competences_groupes")
*/
class CompetenceGroupe
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id_competence_groupe;
/**
* #var User $user
*
* #ORM\ManyToOne(targetEntity="User", cascade={"persist", "merge"})
* #ORM\JoinColumn(name="id_user", referencedColumnName="id_user", nullable=false)
*/
private $user;
/**
* #ORM\Column(type="string", length=60, nullable=true)
*/
protected $titre;
protected $competence_items;
public function __construct()
{
$this->competence_items = new ArrayCollection();
}
public function getCompetenceItems()
{
return $this->competence_items;
}
/**
* Get idCompetenceGroupe
*
* #return integer
*/
public function getIdCompetenceGroupe()
{
return $this->id_competence_groupe;
}
/**
* Set titre
*
* #param string $titre
*
* #return CompetenceGroupe
*/
public function setTitre($titre)
{
$this->titre = $titre;
return $this;
}
/**
* Get titre
*
* #return string
*/
public function getTitre()
{
return $this->titre;
}
/**
* Set user
*
* #param \AppBundle\Entity\User $user
*
* #return CompetenceGroupe
*/
public function setUser(\AppBundle\Entity\User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \AppBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
public function addItem(CompetenceItem $item)
{
$this->competence_items->add($item);
}
public function removeItem(CompetenceItem $item)
{
// ...
}
/**
* Set competenceItems
*
* #param \AppBundle\Entity\CompetenceItem $competenceItems
*
* #return CompetenceGroupe
*/
public function setCompetenceItems(\AppBundle\Entity\CompetenceItem $competenceItems = null)
{
$this->competence_items = $competenceItems;
return $this;
}
}
And my "CompetenceItem" entity :
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="competences_items")
*/
class CompetenceItem
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id_competence_item;
/**
* #ORM\Column(type="string", length=60, nullable=false)
*/
protected $libelle;
/**
* #var CompetenceNiveau $niveau
*
* #ORM\ManyToOne(targetEntity="CompetenceNiveau", cascade={"persist", "merge"})
* #ORM\JoinColumn(name="id_competence_niveau", referencedColumnName="id_competence_niveau", nullable=true)
*/
private $niveau;
/**
* #var CompetenceGroupe $competence_groupe
*
* #ORM\ManyToOne(targetEntity="CompetenceGroupe", cascade={"persist", "merge"})
* #ORM\JoinColumn(name="id_competence_groupe", referencedColumnName="id_competence_groupe", nullable=false)
*/
private $competence_groupe;
/**
* Get idCompetenceItem
*
* #return integer
*/
public function getIdCompetenceItem()
{
return $this->id_competence_item;
}
/**
* Set libelle
*
* #param string $libelle
*
* #return CompetenceItem
*/
public function setLibelle($libelle)
{
$this->libelle = $libelle;
return $this;
}
/**
* Get libelle
*
* #return string
*/
public function getLibelle()
{
return $this->libelle;
}
/**
* Set niveau
*
* #param \AppBundle\Entity\CompetenceNiveau $niveau
*
* #return CompetenceItem
*/
public function setNiveau(\AppBundle\Entity\CompetenceNiveau $niveau = null)
{
$this->niveau = $niveau;
return $this;
}
/**
* Get niveau
*
* #return \AppBundle\Entity\CompetenceNiveau
*/
public function getNiveau()
{
return $this->niveau;
}
/**
* Set competenceGroupe
*
* #param \AppBundle\Entity\CompetenceGroupe $competenceGroupe
*
* #return CompetenceItem
*/
public function setCompetenceGroupe(\AppBundle\Entity\CompetenceGroupe $competenceGroupe)
{
$this->competence_groupe = $competenceGroupe;
return $this;
}
/**
* Get competenceGroupe
*
* #return \AppBundle\Entity\CompetenceGroupe
*/
public function getCompetenceGroupe()
{
return $this->competence_groupe;
}
}
I think I have a missing annotation of the "competence_items" property in the CompetenceGroupe entity, but i'm really not sure ...
Thanks for your help !
A good practice may be to have a competence form, which would be call inside your competence group form
You may add a CollectionType as parrent and include query to search which competence already exist
There are some good example with post form type in symfony demo blog
Or you can use form events (onSubmit, preSubmit, etc...) to charge your entity with your required competence. This example show a message form which allow to choose friend from preset data, this is a good example.
You have tow choice , even to create a Many-To-One, Unidirectional , in this case , you need clean some code , take a look:
In CompetenceGroupe class :
class CompetenceGroupe
{
/**
* Many competence have One Group.
* #ManyToOne(targetEntity="CompetenceItem")
* #JoinColumn(name="id_competence_item", referencedColumnName="id_competence_item")
*/
protected $competence_items;
public function __construct()
{
// $this->competence_items = new ArrayCollection();
//delete that line
}
In CompetenceItem class :
class CompetenceItem
{
You need to delete private $competence_groupe; attribute with his annotation :
By this way, when you dump a CompetenceGroupe object you gonna find the competence items.
Also, you can do it with One-To-Many, Bidirectional ,if you want to get the data from the inverse side and from the owning side .
EDIT: If one competenceGroupe can have many competenceItems, then that is a OneToMany relationship; this is the inverse side of the relationship as defined by doctrine, but that is ok. Your question asked how to pull a competenceGroupe and retrieve all related competenceItems. You can do this by making the competenceItems an ArrayCollection in your CompetenceGroupe entity, just as you have done. You do have to define that further in the annotation, see (updated) code below.
For an ArrayCollection, you can remove your method setCompetenceItems and instead define a method addCompetenceItem in your CompetenceGroupe entity.
class CompetenceGroupe
{
/**
* #ORM\OneToMany(targetEntity="CompetenceItem", mappedBy="competence_groupe")
*/
protected $competenceItems;
public function __construct()
{
$this->competenceItems= new ArrayCollection();
}
/**
* Add competenceItem
*
* #param CompetenceItem $competenceItem
* #return CompetenceGroupe
*/
public function addCompetenceItem(CompetenceItem $competenceItem)
{
$this->competence_items->add($competenceItem);
return $this;
}
}
You'll also need to define the owning side to make all this work.
I want to keep the previous version of an entity. When the 'old' entity is updated I want to save it with the same id but with a different revision number so it looks something like this
id: 1 revision_number: 1
id: 1 revision_number: 2
This is the entity
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Form
*
* #ORM\Table()
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
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="export_template", type="string", length=255, nullable = true)
*/
private $exportTemplate;
/**
* #var \DateTime
*
* #ORM\Column(name="revision", type="datetime", nullable = true)
*/
private $revision;
/**
* #var integer
*
* #ORM\Column(name="revision_number", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $revisionNumber;
/**
* #ORM\ManyToOne(targetEntity="Client", inversedBy="forms")
* #ORM\JoinColumn(name="form_id", referencedColumnName="id")
*/
protected $client;
/**
* #ORM\OneToMany(targetEntity="Section", mappedBy="form", cascade={"persist"})
*/
protected $sections;
/**
* #ORM\OneToMany(targetEntity="Inspection", mappedBy="form")
*/
protected $inspections;
public function __construct()
{
$this->sections = new ArrayCollection();
$this->inspections = 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 exportTemplate
*
* #param string $exportTemplate
* #return Form
*/
public function setExportTemplate($exportTemplate)
{
$this->exportTemplate = $exportTemplate;
return $this;
}
/**
* Get exportTemplate
*
* #return string
*/
public function getExportTemplate()
{
return $this->exportTemplate;
}
/**
* Set revision
*
* #param \DateTime $revision
* #return Form
*/
public function setRevision($revision)
{
$this->revision = $revision;
return $this;
}
/**
* Get revision
*
* #return \DateTime
*/
public function getRevision()
{
return $this->revision;
}
/**
* #param $revisionNumber
* #return Form
*/
public function setRevisionNumber($revisionNumber)
{
$this->revisionNumber = $revisionNumber;
return $this;
}
/**
* #return int
*/
public function getRevisionNumber()
{
return $this->revisionNumber;
}
/**
* Set client
*
* #param \AppBundle\Entity\Client $client
* #return Form
*/
public function setClient(\AppBundle\Entity\Client $client = null)
{
$this->client = $client;
return $this;
}
/**
* Get client
*
* #return \AppBundle\Entity\Client
*/
public function getClient()
{
return $this->client;
}
/**
* Add sections
*
* #param \AppBundle\Entity\Section $sections
* #return Form
*/
public function addSection(\AppBundle\Entity\Section $sections)
{
$this->sections[] = $sections;
return $this;
}
/**
* Remove sections
*
* #param \AppBundle\Entity\Section $sections
*/
public function removeSection(\AppBundle\Entity\Section $sections)
{
$this->sections->removeElement($sections);
}
/**
* Get sections
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSections()
{
return $this->sections;
}
/**
* Add inspections
*
* #param \AppBundle\Entity\Inspection $inspections
* #return Form
*/
public function addInspection(\AppBundle\Entity\Inspection $inspections)
{
$this->inspections[] = $inspections;
return $this;
}
/**
* Remove inspections
*
* #param \AppBundle\Entity\Inspection $inspections
*/
public function removeInspection(\AppBundle\Entity\Inspection $inspections)
{
$this->inspections->removeElement($inspections);
}
/**
* Get inspections
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getInspections()
{
return $this->inspections;
}
/**
*
* #ORM\PrePersist()
*/
public function preSetDate(){
$this->revision = new \DateTime();
}
}
Is there a way I can do what I described?
I think what you may need is Loggable extension for Doctrine. Check this link:
https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/loggable.md
Loggable behavior tracks your record changes and is able to manage versions.
Using loggable behavior you can revert version from your repository with revert() method. You can find many examples on site I gave you the link above.
If you dont fancy using a 3rd party bundle for this:
your ID's will still have to be unique. If you need to track where the copy originated from then you could add a new parameter.
Once you have decided upon this, I would simply clone it, alter the revision number and add the original id if thats which way you want to go and then persist it.
class Form {
// ....
$orig_id = null;
// any getters/setters you need
// .....
}
then in the controller:
public function copyEntity($entity) {
$new_ent = clone $entity;
$new_ent->setOrigId( $entity->getId() );
$new_ent->setRevision( true ); // I would probably bin this as origId being !== null would do the same job
$this->entityManager->persist( $new_ent );
$this->entityManager->flush();
// .....
}
I have a Property:
(Note: the legacy_id was not my doing and is now ingrained in the app so can't be changed at this time)
<?php
namespace Entity\Beaverusiv;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Entity\Beaverusiv\Property
*
* #ORM\Entity()
* #ORM\Table(name="properties", indexes={#ORM\Index(name="fk_properties_smoking_options1_idx", columns={"smoking_id"}), #ORM\Index(name="fk_properties_linen_options1_idx", columns={"linen_id"}), #ORM\Index(name="fk_properties_pets_options1_idx", columns={"pets_id"}), #ORM\Index(name="fk_properties_property_city1_idx", columns={"city_id"})})
*/
class Property
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\Column(type="integer")
*/
protected $legacy_id;
/**
* #ORM\ManyToMany(targetEntity="FeaturesOption", mappedBy="properties")
*/
protected $featuresOptions;
public function __construct()
{
$this->featuresOptions = new ArrayCollection();
}
/**
* Set the value of id.
*
* #param integer $id
* #return \Entity\Beaverusiv\Property
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* Get the value of id.
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set the value of legacy_id.
*
* #param integer $legacy_id
* #return \Entity\Beaverusiv\Property
*/
public function setLegacyId($legacy_id)
{
$this->legacy_id = $legacy_id;
return $this;
}
/**
* Get the value of legacy_id.
*
* #return integer
*/
public function getLegacyId()
{
return $this->legacy_id;
}
/**
* Add FeaturesOption entity to collection.
*
* #param \Entity\Beaverusiv\FeaturesOption $featuresOption
* #return \Entity\Beaverusiv\Property
*/
public function addFeaturesOption(FeaturesOption $featuresOption)
{
$this->featuresOptions[] = $featuresOption;
return $this;
}
/**
* Get FeaturesOption entity collection.
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getFeaturesOptions()
{
return $this->featuresOptions;
}
}
And FeaturesOption:
<?php
namespace Entity\Beaverusiv;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Entity\Beaverusiv\FeaturesOption
*
* #ORM\Entity()
* #ORM\Table(name="features_options")
*/
class FeaturesOption
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $display_order;
/**
* #ORM\Column(type="string", length=200, nullable=true)
*/
protected $text;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $status;
/**
* #ORM\ManyToMany(targetEntity="Property", inversedBy="featuresOptions")
* #ORM\JoinTable(name="properties_features",
* joinColumns={#ORM\JoinColumn(name="feature_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="property_id", referencedColumnName="id")}
* )
*/
protected $properties;
public function __construct()
{
$this->properties = new ArrayCollection();
}
/**
* Set the value of id.
*
* #param integer $id
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* Get the value of id.
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set the value of display_order.
*
* #param integer $display_order
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function setDisplayOrder($display_order)
{
$this->display_order = $display_order;
return $this;
}
/**
* Get the value of display_order.
*
* #return integer
*/
public function getDisplayOrder()
{
return $this->display_order;
}
/**
* Set the value of text.
*
* #param string $text
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function setText($text)
{
$this->text = $text;
return $this;
}
/**
* Get the value of text.
*
* #return string
*/
public function getText()
{
return $this->text;
}
/**
* Set the value of status.
*
* #param integer $status
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* Get the value of status.
*
* #return integer
*/
public function getStatus()
{
return $this->status;
}
/**
* Add Property entity to collection.
*
* #param \Entity\Beaverusiv\Property $property
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function addProperty(Property $property)
{
$property->addFeaturesOption($this);
$this->properties[] = $property;
return $this;
}
/**
* Get Property entity collection.
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProperties()
{
return $this->properties;
}
}
And the pivot:
<?php
namespace Entity\Beaverusiv;
use Doctrine\ORM\Mapping as ORM;
/**
* Entity\Beaverusiv\PropertiesFeature
*
* #ORM\Entity()
* #ORM\Table(name="properties_features", indexes={#ORM\Index(name="fk_properties_features_features_options1_idx", columns={"feature_id"}), #ORM\Index(name="fk_properties_features_properties1_idx", columns={"property_id"})})
*/
class PropertiesFeature
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
*/
protected $feature_id;
/**
* #ORM\Id
* #ORM\Column(type="integer")
*/
protected $property_id;
/**
* #ORM\ManyToOne(targetEntity="FeaturesOption", inversedBy="propertiesFeatures")
* #ORM\JoinColumn(name="feature_id", referencedColumnName="id", nullable=false)
*/
protected $featuresOption;
/**
* #ORM\ManyToOne(targetEntity="Property", inversedBy="propertiesFeatures")
* #ORM\JoinColumn(name="property_id", referencedColumnName="id", nullable=false)
*/
protected $property;
public function __construct()
{
}
/**
* Set the value of feature_id.
*
* #param integer $feature_id
* #return \Entity\Beaverusiv\PropertiesFeature
*/
public function setFeatureId($feature_id)
{
$this->feature_id = $feature_id;
return $this;
}
/**
* Get the value of feature_id.
*
* #return integer
*/
public function getFeatureId()
{
return $this->feature_id;
}
/**
* Set the value of property_id.
*
* #param integer $property_id
* #return \Entity\Beaverusiv\PropertiesFeature
*/
public function setPropertyId($property_id)
{
$this->property_id = $property_id;
return $this;
}
/**
* Get the value of property_id.
*
* #return integer
*/
public function getPropertyId()
{
return $this->property_id;
}
/**
* Set FeaturesOption entity (many to one).
*
* #param \Entity\Beaverusiv\FeaturesOption $featuresOption
* #return \Entity\Beaverusiv\PropertiesFeature
*/
public function setFeaturesOption(FeaturesOption $featuresOption = null)
{
$this->featuresOption = $featuresOption;
$this->feature_id = $featuresOption->getId();
return $this;
}
/**
* Get FeaturesOption entity (many to one).
*
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function getFeaturesOption()
{
return $this->featuresOption;
}
/**
* Set Property entity (many to one).
*
* #param \Entity\Beaverusiv\Property $property
* #return \Entity\Beaverusiv\PropertiesFeature
*/
public function setProperty(Property $property = null)
{
$this->property = $property;
$this->property_id = $property->getLegacyId();
return $this;
}
/**
* Get Property entity (many to one).
*
* #return \Entity\Beaverusiv\Property
*/
public function getProperty()
{
return $this->property;
}
}
I am having to bring in data from an older DB, like this:
<?php
public function sync()
{
$persist_count = 0; // Keep track of home many properties are ready to be flushed
$flush_count = 20; // Persist and flush the properties in groups of...
$i = 0;
$CI =& get_instance();
$legacy_properties = null;
while ($legacy_properties !== false)
{
$legacy_properties = $this->doctrine->mssql
->getRepository('Entity\MSSQL\TblProperty')
->getProperties($i, $flush_count);
if (count($legacy_properties)===0)
{
break;
}
foreach ($legacy_properties as $legacy_property)
{
// Legacy ID
$legacy_id = $legacy_property['propertyID'];
// Lets see if this property already exists in the new database. If it does, we'll just use that.
$property = $this->doctrine->em
->getRepository('Entity\Beaverusiv\Property')
->findOneBy(array(
'legacy_id' => $legacy_id
));
// If the property from the legacy database does not exist in the new database, let's add it.
if (! $property)
{
$property = new Entity\Beaverusiv\Property; // create a new property instance
$property->setLegacyId($legacy_id);
}
// Update property details
// Set all the other Property fields
$legacy_features = $this->doctrine->mssql
->getRepository('Entity\MSSQL\TblProperty')
->findOneBy(array('propertyID' => $legacy_id))
->getTblPropertyFeaturesJoins();
foreach ($legacy_features as $legacy_feature) {
$feature_id = $legacy_feature->getTblPropertyFeature()->getFeatureID();
$feature = $this->doctrine->em
->getRepository('Entity\Beaverusiv\FeaturesOption')
->findOneBy(array(
'id' => $feature_id
));
$feature_pivot = new Entity\Beaverusiv\PropertiesFeature;
$feature_pivot->setFeaturesOption($feature);
$feature_pivot->setProperty($property);
$this->doctrine->em->merge($feature_pivot);
}
// Persist this property, ready forz flushing in groups of $persist_bunch
$this->doctrine->em->persist($property);
$persist_count++;
// If the number of properties ready to be flushed is the number set in $flush_count, lets flush these properties
if ($persist_count == $flush_count) {
$this->doctrine->em->flush();
$this->doctrine->em->clear();
$this->doctrine->mssql->clear();
}
}
// Flush any remaining properties
$this->doctrine->em->flush();
$i += $flush_count;
}
}
Obviously this is wrong, but I haven't been able to find anywhere to show me a proper example. At the moment it just runs out of memory for some reason and complains about duplicates in the pivot table. How do I get a proper relationship set up so I don't reference the pivot table and can instead directly add FeatureOptions to a Property?
Ok, managed to get it working by changing in Property this:
/**
* #ORM\ManyToMany(targetEntity="FeaturesOption", mappedBy="properties")
*/
protected $featuresOptions;
to this:
/**
* #ORM\ManyToMany(targetEntity="FeaturesOption")
* #ORM\JoinTable(name="properties_features",
* joinColumns={#ORM\JoinColumn(name="property_id", referencedColumnName="legacy_id")},
* inverseJoinColumns={#ORM\JoinColumn(name="feature_id", referencedColumnName="id")}
* )
*/
protected $featuresOptions;
Dropping the pivot table entity, and dropping the inverse reference stuff in the FeaturesOption entity.
I have a one-to-many self referencing entity. Everything works fine as long as the parent value is set to null. When I set the parent item to something actually in the list, I get the error:
Class integer does not exist
500 Internal Server Error - ReflectionException
Here is the code for my entity:
<?php
namespace WorkRecorder\WorkBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="WorkRecorder\WorkBundle\Repository\WorkRepository")
* #ORM\Table(name="strategyUsed")
*/
class StrategyUsed
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="integer")
*/
protected $sortOrder;
/**
* #ORM\Column(type="string", length=50)
*/
protected $name;
/**
* #ORM\Column(type="text")
*/
protected $description;
/**
* #ORM\OneToMany(targetEntity="StrategyUsed", mappedBy="parent")
*/
private $children;
/**
* #ORM\ManyToOne(targetEntity="StrategyUsed", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
private $parent;
public function __construct() {
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* 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 description
*
* #param text $description
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* Get description
*
* #return text
*/
public function getDescription()
{
return $this->description;
}
/**
* Set sortOrder
*
* #param integer $sortOrder
*/
public function setSortOrder(\integer $sortOrder)
{
$this->sortOrder = $sortOrder;
}
/**
* Get sortOrder
*
* #return integer
*/
public function getSortOrder()
{
return $this->sortOrder;
}
/**
* Add children
*
* #param WorkRecorder\WorkBundle\Entity\StrategyUsed $children
*/
public function addStrategyUsed(\WorkRecorder\WorkBundle\Entity\StrategyUsed $children)
{
$this->children[] = $children;
}
/**
* Get children
*
* #return Doctrine\Common\Collections\Collection
*/
public function getChildren()
{
return $this->children;
}
/**
* Set parent
*
* #param WorkRecorder\WorkBundle\Entity\StrategyUsed $parent
*/
public function setParent(\WorkRecorder\WorkBundle\Entity\StrategyUsed $parent)
{
$this->parent = $parent;
}
/**
* Get parent
*
* #return WorkRecorder\WorkBundle\Entity\StrategyUsed
*/
public function getParent()
{
return $this->parent;
}
}
What am I doing wrong?
You can't type hint on a scalar type (integer/string/boolean etc) in PHP. e.g.
public function setSortOrder(\integer $sortOrder)
Should be:
public function setSortOrder($sortOrder)
You can validate the type of the value within the method and perhaps throw an InvalidArgumentException if passed something that isn't an integer.