I'm trying to learn read/write data to/from database, and I have a huge problem :
My entities looks :
Kategorie:
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="kategorie")
*/
class Kategorie
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $idkategorii;
/**
* #ORM\Column(type="string", length=50)
*/
protected $nazwa;
/**
* #ORM\OneToMany(targetEntity="Ogloszenia", mappedBy="ogloszenia")
*/
protected $ogloszenia;
Ogloszenia:
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="ogloszenia")
*/
class Ogloszenia
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string",length=100)
*/
protected $tytul;
/**
* #ORM\Column(type="string", length=120)
*/
protected $tytul_seo; //tytul bez polskich znaków etc.
/**
* #ORM\Column(type="text")
*/
protected $tresc; //tresc ogloszenia
/**
* #ORM\Column(type="string",length=50)
*/
protected $dodal; //imie osoby ktora dodala ogloszenie
/**
* #ORM\Column(type="string", length=50)
*/
protected $kontakt; //nr tel lub mail
/**
* #ORM\ManyToOne(targetEntity="Kategorie", inversedBy="kategoria")
* #ORM\JoinColumn(name="kategoria", referencedColumnName="idkategorii")
*/
protected $kategoria;
Now, in my controller i'm trying to read all values :
public function odczytajAction()
{
$id = 1;
$kategoria = $this->getDoctrine()
->getRepository('FrontendOgloszeniaBundle:Kategorie')
->find($id);
$ogl = $kategoria->getOgloszenia();
foreach($ogl as $o)
{
print_r($o);
}
return new Response('test odczytu');
}
And unfortunately symfony2 gives me an following error
Notice: Undefined index: ogloszenia in /home/sl4sh/public_html/Projekt1/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php line 1574
500 Internal Server Error - ErrorException
So, please tell me what's wrong with mine code ?
You have invalid mappedBy annotation:
/**
* #ORM\OneToMany(targetEntity="Ogloszenia", mappedBy="kategoria")
*/
protected $ogloszenia;
And also inverse side:
/**
* #ORM\ManyToOne(targetEntity="Kategorie", inversedBy="ogloszenia")
* #ORM\JoinColumn(name="kategoria", referencedColumnName="idkategorii")
*/
protected $kategoria;
Related
Trying to utilize inheritance, I've created the following entities:
/**
* #ORM\Table(name="persons")
* #ORM\Entity()
*/
class Person
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
protected $name;
/**
* #ORM\OneToOne(targetEntity="Image", cascade={"persist"})
* #ORM\JoinColumn(name="image_id", referencedColumnName="id")
*/
protected $image;
}
/**
* #ORM\Table(name="actors")
* #ORM\Entity()
*/
class Actor extends Person
{
/**
* #ORM\Column(name="character", type="string", length=255)
*/
private $character;
}
/**
* #ORM\Table(name="images")
* #ORM\Entity()
*/
class Image
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="path", type="string", length=255)
*/
private $path;
}
Which almost works perfectly. The generated actors-table contains all the persons-fields, except for the image-relation. I've tried to change the relation to a ManyToOne, which didn't help.
How to make the Actor-entity also inherit all joined fields? I'm open to other solutions, if the above isn't ideal.
You need a parent construct in your Actor class:
public function __construct()
{
parent::__construct();
// your own logic
}
It is advised that you add an ID aswell.
I have a series of classes with a slightly complicated set of references between the properties of those classes. I am trying to remove an entity and have that remove be cascaded to its children, but I'm running into foreign key constraint errors. Here is an example of my class structure:
<?php
/**
* #ORM\Entity
* #ORM\Table(name="student_tests")
*/
class StudentTest implements IEntityAccess {
/**
*
* #var int
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var StudentTestItem[]
* #ORM\OneToMany(targetEntity="StudentTestItem", mappedBy="studentTest", cascade{"remove","persist"})
*/
protected $studentTestItems;
/**
* #var Test
* #ORM\ManyToOne(targetEntity="Test", inversedBy="studentTests")
*/
protected $test;
/**
* #var \DateTime
* #ORM\Column(type="datetime", nullable=true)
*/
protected $created;
/**
* #var User
* #ORM\ManyToOne(targetEntity="User", inversedBy="studentTests")
*/
protected $student;
}
//...
<?php
/**
* #ORM\Entity
* #ORM\Table(name="student_test_items")
*/
class StudentTestItem {
/**
*
* #var int
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var StudentTest
* #ORM\ManyToOne(targetEntity="StudentTest", inversedBy="studentTestItems")
*/
protected $studentTest;
/**
* #var User
* #ORM\ManyToOne(targetEntity="User", inversedBy="studentTestItems", cascade={"persist"})
*/
protected $student;
/**
* #var TestItem
* #ORM\ManyToOne(targetEntity="TestItem", inversedBy="studentTestItems", cascade{"persist"})
*/
protected $testItem;
}
//...
/**
*
* #ORM\Table(name="tests")
* #ORM\Entity
*
* #ORM\HasLifecycleCallbacks
*/
class Test implements IEntityAccess {
/**
*
* #var int
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var \DateTime
* #ORM\Column(type="datetime", nullable=true)
*/
protected $startDate;
/**
* #var StudentTest[]
* #ORM\OneToMany(targetEntity="StudentTest", mappedBy="test" )
*/
protected $studentTests;
/**
* #var TestItem[]
* #ORM\OneToMany(targetEntity="TestItem", mappedBy="test", cascade={"all"})
*/
protected $items;
}
//...
/**
*
* #ORM\Table(name="test_items")
* #ORM\Entity
*/
abstract class TestItem {
/**
*
* #var int
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var Test
* #ORM\ManyToOne(targetEntity="Test", inversedBy="items")
*/
/**
* #var StudentTestItem[]
* #ORM\OneToMany(targetEntity="StudentTestItem", mappedBy="testItem")
*/
protected $studentTestItems;
}
/**
* This is the primary user object. Used for login and all the other
* good stuff.
*
* #ORM\Table(name="users")
* #ORM\HasLifecycleCallbacks
class User implements AdvancedUserInterface, \Serializable, IEntityAccess
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #var int
*/
private $id;
/**
* #var StudentTest[]
* #ORM\OneToMany(targetEntity="StudentTest", mappedBy="student", cascade={"persist", "remove"})
*/
protected $studentTests;
/**
* #var StudentTestItem[]
* #ORM\OneToMany(targetEntity="StudentTestItem", mappedBy="student", cascade={"persist", "remove"})
*/
protected $studentTestItems;
}
Let's say I want to delete a student test, and have that delete cascaded to its StudentTestItem children. To do so, I run the following code inside of a controller.
//... blah blah class definition
/**
* Delete a student test
*
* #return \Symfony\Component\HttpFoundation\Response
* #Route("/studenttest/delete", name="student_test_delete")
*/
public function DeleteStudentTestAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$studentTest = $em->getRepository("MyAcmeBundle:StudentTest")->findOneBy(array("id" => 3));
$em->remove($studentTest);
$em->flush();
return $this->redirect($this->generateUrl('student_delete_success'));
}
When I try to run that code, I get the following error message:
An exception occurred while executing 'DELETE FROM student_tests WHERE id = ?' with params [3]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`my_acme_bundle/student_test_items`, CONSTRAINT `FK_71FA2A7F36BB1A1` FOREIGN KEY (`student_test_id`) REFERENCES `student_tests` (`id`))
500 Internal Server Error - DBALException
NOW, if I remove all references to studentTestItems from the classes, i.e. I comment out $studentTestItems from the TestItem and User classes, it deletes fine without that issue. Why is this happening? Does Doctrine keep track of the parent references through associations or something?
Looks like you forgot to add ON DELETE CASCADE to the foreign key constraint. Try changing the following association in class StudentTestItem:
/**
* #var StudentTest
* #ORM\ManyToOne(targetEntity="StudentTest", inversedBy="studentTestItems")
*/
protected $studentTest;
To this:
/**
* #var StudentTest
* #ORM\ManyToOne(targetEntity="StudentTest", inversedBy="studentTestItems")
* #ORM\JoinColumn(name="student_test_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $studentTest;
this is my entity:
/**
* #ORM\Table(name="Animal")
* #ORM\HasLifecycleCallbacks
*/
class Animal {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var localizedcontent $lctitle
*
* #ORM\ManyToOne(targetEntity="localizedcontent",fetch="EAGER", cascade={"persist"})
* #ORM\JoinColumn(name="lcTitle", referencedColumnName="pkId", nullable=false)
*/
private $lctitle;
/**
* #var localizedcontent $lcdescription
*
* #ORM\ManyToOne(targetEntity="localizedcontent",fetch="EAGER", cascade={"persist"})
* #ORM\JoinColumn(name="lcDescription", referencedColumnName="pkId", nullable=false)
*/
private $lcdescription;
/**
* #ORM\PostLoad
*/
public function postLoad(){
$lct = $this->lctitle;
$lcd = $this->lcdescription;
}
This is my dql:
SELECT a,lct FROM Animal JOIN e.lctitle lct WHERE a.id=:id
When i'm starting xdebug, it tells me that lcdescription is a proxy object and lctitle doesn't exists. I don't know why.
I think the postLoad event is too early because the localizedcontent isn't loaded at this moment, right? Is there an other listener for reading the value of lctitle in relation to the Animal Object?
Thanks
Doctrine always returns proxies. These classes inherit from the entity-classes. It might help if you declare your relations protected instead of private.
/**
* #var localizedcontent $lctitle
*
* #ORM\ManyToOne(targetEntity="localizedcontent",fetch="EAGER", cascade={"persist"})
* #ORM\JoinColumn(name="lcTitle", referencedColumnName="pkId", nullable=false)
*/
protected $lctitle;
or you could write a getter and call this one in your post-load function
public function getLctitle() {
return $this->lctitle;
}
public function getLcdescription() {
return $this->lcdescription;
}
/**
* #ORM\PostLoad
*/
public function postLoad(){
$lct = $this->getLctitle();
$lcd = $this->getLcdescription();
}
I have many relations of this type, but I can't see why this one is not working.
I have a Delegation and a Promotion entities:
Delegation
Promotion
/**
* Company\CBundle\Entity\Promotion
*
* #ORM\Entity
* #DoctrineAssert\UniqueEntity("promotionCode")
*/
class Promotion
{
const REGISTER_DAYS = 30;
const REGISTER_DISCOUNT = 100;
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(name="promotionCode", type="string", unique=true, nullable=true)
*/
protected $promotionCode;
/**
* #ORM\Column(name="name", type="string")
*/
protected $name;
/**
* #ORM\Column(name="description", type="string", nullable=true)
*/
protected $description;
/**
* #ORM\Column(name="days", type="integer")
*/
protected $days;
/**
* #ORM\Column(name="discount", type="float")
*/
protected $discount;
/**
* #ORM\ManyToOne(targetEntity="Delegation", inversedBy="promotions")
* #ORM\JoinColumn(name="delegation_id", referencedColumnName="id")
*/
private $delegation;
/**
* #ORM\ManyToOne(targetEntity="Product", inversedBy="promotions")
*/
private $product;
/**
* #var date $adquiredDate
*
* #ORM\Column(name="adquiredDate", type="date", nullable=true)
*/
private $adquiredDate;
When in a controller I create a promotion, the table Promotion has the new object related to the delegation one
private function createPromotion($delegation)
{
$em = $this->getDoctrine()->getEntityManager();
$promotion = Promotion::createPromotion($delegacion, Promotion::REGISTER_DAYS, Promotion::REGISTER_DISCOUNT);
$em->persist($promotion);
$em->persist($delegation);
$em->flush();
}
Database
*************************** 15. row ***************************
id: 32
delegation_id: 19
days: 20
discount: 50
adquiredDate: 2013-01-10
*************************** 16. row ***************************
id: 33
delegation_id: 19
days: 25
discount: 50
adquiredDate: 2013-01-10
*************************** 17. row ***************************
id: 34
delegation_id: 19
days: 30
discount: 50
adquiredDate: 2013-01-10
But when I call the $delegation->getPromotions() in another controller/action there is no promotions, returns a Doctrine\ORM\PersistentCollection with no data.
Can anyone help, please?
Edit with more information.
$delegation->getPromotions() is empty, but looking for a promotion of that delegation and calling $promotion->getDelegation() is returning the delegation correctly :?
Have you tried defining your $delegation property like
/**
* #ORM\ManyToOne(targetEntity="Delegation", inversedBy="promotions")
* #ORM\JoinColumn(name="delegation_id", referencedColumnName="id")
*/
private $delegation;
See Doctrine2 Docs: Association Mapping->Many-To-One
Also there are a lot of typos in your code. For example
/**
* #ORM\OneToMany(targetEntity="Promotion", mappedBy="delegacion", cascade={"all"}, orphanRemoval=true)
*/
protected $promotions;
mappedBy="delegacion" should be mappedBy="delegation".
Or
public function getDeleTacion()
{
return $this->deleTacion;
}
Should be
public function getDelegation()
{
return $this->delegation;
}
Edit
Okay, I created a minimalistic version for you that worked for me. You can built it up from there or watch for differences with your code:
Promotion.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Promotion
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Delegation", inversedBy="promotions", cascade={"persist"})
* #ORM\JoinColumn(name="delegation_id", referencedColumnName="id")
*/
public $delegation;
/**
* #ORM\ManyToOne(targetEntity="Product", inversedBy="promotions", cascade={"persist"})
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
*/
public $product;
}
Delegation.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Delegation
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="Promotion", mappedBy="delegation", cascade={"all"}, orphanRemoval=true)
*/
public $promotions;
public function __construct() {
$this->promotions = new \Doctrine\Common\Collections\ArrayCollection();
}
}
Product.php
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Product
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="Promotion", mappedBy="product", cascade={"all"}, orphanRemoval=true)
*/
public $promotions;
public function __construct() {
$this->promotions = new \Doctrine\Common\Collections\ArrayCollection();
}
}
If you now do something like
$delegation = new Delegation();
$product = new Product();
$promotion = new Promotion();
$promotion->delegation = $delegation;
$promotion->product = $product;
$em->persist($promotion);
$em->flush();
$products = $em->createQuery('select p from BundleName\Entity\Product p')->execute();
$delegations = $em->createQuery('select d from BundleName\Entity\Delegation d')->execute();
var_dump(count($products[0]->promotions), count($delegations[0]->promotions));
You should end up with
int(1)
int(1)
So the refrence is in fact saved and can be read. Phew. Good luck with that! :-)
I had a similar error where my many-to-one relationship on some freshly created entities contained entities, and an inverse one-to-many didn't, although database clearly had the corresponding rows in it.
I did persist and flush entities on the one-to-many side, but I had to also do
$entityManager->clear();
before getting those entities from a repository again for the one-to-many relationship to be able to access those entities.
I have this class:
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
class Parameter{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Project\Bundle\Entity\Anthropometry", inversedBy="parameter")
* #ORM\JoinColumn(name="anthropometry_id", referencedColumnName="id")
*
*/
protected $anthropometry;
/**
* #ORM\Column(name="data", type="string", length=255, nullable=true)
*/
protected $data;
...
}
and this:
/**
* #ORM\Table(name="anthropometry")
* #ORM\Entity
*/
class Anthropometry {
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\OneToMany(targetEntity="Project\Bundle\Entity\Parameter", mappedBy="anthropometry", cascade={"persist"})
*
*/
protected $parameter;
...
}
In my Controller I am creating a form and validating in the same Action.
To create the form I need instance one Parameter. But not need persist him.
So.. when I call $em->flush I got the error:
A new entity was found through the relationship ...
To solve this I put cascade={"persist"} in annotation:
//Class Anthropometry
...
/**
*
* #ORM\OneToMany(targetEntity="Project\Bundle\Entity\Parameter", mappedBy="anthropometry", cascade={"persist"})
*
*/
protected $parameter;
But now, in my Database, the parameters are being persisted with field 'Data' = NULL
Can I check with prePersist if the field is NULL before persist?
something like this?
//class Parameter
/**
*
* #ORM\prePersist
*/
public function prePersist(){
if($this->getData() == NULL){
return false;
}
}
Thx!
I didn't verify if it works but you could try unsetting the parameter before persisting the Anthropometry (since you don't need to persist parameters):
//class Anthropometry
/**
* #ORM\prePersist
*/
public function prePersist()
{
if(!is_null($this->parameter) && $this->parameter->getData() == null){
$this->parameter = null;
}
}