Doctrine ArrayCollection Call to a member function setValue() on null - php

I'm writing an application using Zend Framework 3. To manage database I decided to use Doctrine. I have two tables pages and pages_meta(something based on wordpress db). They are realted to each other in one-to-many, many-to-one relation. In pages_meta I have key page_id. Now when I try to get meta form Page Entity I got following error:
File: /home/platne/serwer18346/vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php:169
Message: Call to a member function setValue() on null
Now the application code:
Page Entity(removed some code to show important part):
namespace Core\Model;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Class Page
* #package Core\Model
* #ORM\Entity
* #ORM\Table(name="pages")
*/
class Page
{
/**
* #var int
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(name="id")
*/
protected $id;
//other fields definition(here is slug to found by)
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="\Core\Model\PageMeta", mappedBy="pages")
* #ORM\JoinColumn(name="id", referencedColumnName="page_id")
*/
protected $meta;
/**
* Page constructor.
*/
public function __construct()
{
$this->meta = new ArrayCollection();
}
/**
* #return int
*
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $key
* #return ArrayCollection
*/
public function getPageMeta($key = null){
if(!$key) return $this->meta;
return $this->meta->current(); //this is causing the problem tried other functions as well
}
}
PageMeta Entity(same here I removed some code):
namespace Core\Model;
use Doctrine\ORM\Mapping as ORM;
/**
* Class PageMeta
* #package Core\Model
* #ORM\Entity
* #ORM\Table(name="page_meta")
*/
class PageMeta
{
/**
* #var int
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(name="id")
*/
protected $id;
/**
* #var int
* #ORM\Column(type="integer", name="page_id")
*/
protected $page_id;
/**
* #var Page
* #ORM\ManyToOne(targetEntity="\Core\Model\Page", inversedBy="page_meta")
* #ORM\JoinColumn(name="page_id", referencedColumnName="id")
*/
protected $page;
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #return int
*/
public function getPageId(): int
{
return $this->page_id;
}
/**
* #param int $page_id
* #return PageMeta
*/
public function setPageId(int $page_id): PageMeta
{
$this->page_id = $page_id;
return $this;
}
//other field definition
/**
* #return Page
*/
public function getPage(){ //this works fine
return $this->page;
}
}
In the controller:
$this->getEntityManager()->getRepository(Page::class);
$page = $pagesTable->findOneBySlug($slug);
//check if page exists
$page->getPageMeta('test'); //this line cause the problem.
Full stack error you can see on page: http://bibliotekadomowa.pl/o-nas

I think it may be an issue with the "mappedBy" param in Page, try changing that to
mappedBy="page"
As it should match the variable name not the table name

Related

Symfony 2 Entity Repository find() returns empty array

Thank you all for your answers from now. Thatś the question. I have a symfony 2 app with two entities (Tasks and Products). When i tried to find (findBy,findOneBy,findAll) a product it returns an empty array.
Tasks Entity
<?php
namespace pablo\UserBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Task
*
* #ORM\Table(name="tasks")
* #ORM\Entity(repositoryClass="pablo\UserBundle\Repository\TaskRepository")
* #ORM\HasLifecycleCallbacks()
*/
class Task
{
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="tasks")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $user;
/**
* #ORM\ManyToOne(targetEntity="Product", inversedBy="task")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $product;
public function __construct()
{
$this->tasks = new ArrayCollection();
}
/**
* Set product
*
* #param \pablo\UserBundle\Entity\Product $product
*
* #return Task
*/
public function setProduct(\pablo\UserBundle\Entity\Product $product = null)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* #return \pablo\UserBundle\Entity\Product
*/
public function getProduct()
{
return $this->product;
}
/**
* #return ArrayCollection
*/
public function getTasks()
{
return $this->tasks;
}
/**
* #param ArrayCollection $tasks
*/
public function setTasks($tasks)
{
$this->tasks = $tasks;
}
And Products Entity
<?php
namespace pablo\UserBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* Products
*
* #ORM\Table(name="products")
* #ORM\Entity(repositoryClass="pablo\UserBundle\Repository\ProductsRepository")
* #UniqueEntity("productsName")
*/
class Product
{
/**
* #ORM\OneToMany(targetEntity="Task", mappedBy="product")
*/
protected $task;
/**
* #ORM\OneToMany(targetEntity="Publicaciones", mappedBy="product")
*/
protected $publicaciones;
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="products_name", type="string", length=255)
* #Assert\NotBlank()
*/
private $productsName;
public function __construct()
{
$this->task = new ArrayCollection();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set productsName
*
* #param string $productsName
*
* #return Product
*/
public function setProductsName($productsName)
{
$this->productsName = $productsName;
return $this;
}
/**
* Get productsName
*
* #return string
*/
public function getProductsName()
{
return $this->productsName;
}
public function __toString() {
return $this->productsName;
}
/**
* Get task
*
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getTask()
{
return $this->task;
}
/**
* Set task
*
* #param \Doctrine\Common\Collections\ArrayCollection $typeSponsor
*
* #return Task
*/
public function setTask($task)
{
$this->task = $task;
}
/**
* #return mixed
*/
public function getPublicaciones()
{
return $this->publicaciones;
}
/**
* #param mixed $publicaciones
*/
public function setPublicaciones($publicaciones)
{
$this->publicaciones = $publicaciones;
}
}
Now, when i tried to find a product from controller it returns an empty array ({}). I can't see what is wrong with this.
$productId = '18';
$product = $this->get('doctrine.orm.default_entity_manager')->getRepository('pabloUserBundle:Product')->find($productId);
Actually you have a result, it just is an empty object because you have not defined which of the properties should be printed.
The best solution is for your entity to implement JsonSerializable.
class Product implements \JsonSerializable
{
...
public function jsonSerialize()
{
return [
"id"=> $this->getId(),
"name" => $this->getProductsName()
];
}
Now it knows what it should print when converting the class to json object.
If you want the task collection also, implement JsonSerializable for the Task Entity and add in Product Entity:
public function jsonSerialize()
{
return [
"id"=> $this->getId(),
"name" => $this->getProductsName(),
"task" => $this->getTask()->toArray()
];
}
The JsonSerializable interface

I can't get objects of related entity in Symfony3

I use Symfony 3.2. I have two related entities:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
* #ORM\Table(name="user", options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"}, indexes={ #Index(name="idx_email", columns={"email"}) })
* #UniqueEntity(fields={"email"}, message="Пользователь с данным email'ом существует.", groups={"Registration"})
* #ORM\HasLifecycleCallbacks()
*/
class User
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
*
* #ORM\OneToMany(targetEntity="AppBundle\Entity\VisitedPage", mappedBy="user")
*/
private $visitedPages;
public function __construct()
{
$this->visitedPages = new ArrayCollection();
}
public function addVisitedPage(VisitedPage $visitedPage)
{
$this->visitedPages[] = $visitedPage;
return $this;
}
/**
* Remove visitedPage
*
* #param \AppBundle\Entity\VisitedPage $visitedPage
*/
public function removeVisitedPage(\AppBundle\Entity\VisitedPage $visitedPage)
{
$this->visitedPages->removeElement($visitedPage);
}
/**
* Get visitedPages
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getVisitedPages()
{
return $this->visitedPages;
}
}
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* VisitedPage
*
* #ORM\Table(name="visited_page")
* #ORM\Entity(repositoryClass="AppBundle\Repository\VisitedPageRepository")
*/
class VisitedPage
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="visitedPages")
*/
private $user;
/**
* #var string
* #ORM\Column(name="page", type="text")
*/
private $page;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set user
*
* #param \AppBundle\Entity\User $user
*
* #return VisitedPage
*/
public function setUser(\AppBundle\Entity\User $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \AppBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Set page
*
* #param string $page
*
* #return VisitedPage
*/
public function setPage($page)
{
$this->page = $page;
return $this;
}
/**
* Get page
*
* #return string
*/
public function getPage()
{
return $this->page;
}
}
When i try call VisitedPage::getUser() (i mean $visitedPage->getUser()) i get object type of user.
But when i call method User::getVisitedPages() i get null.
Method User::addVisitedPage($page) works and relations are saved.
How can i decide this problem?
//Some text to pass validation
When you add Visited Page from user try this:
class User
{
//......
public function addVisitedPage(VisitedPage $visitedPage)
{
$visitedPage->setUser($this);
$this->visitedPages->add($visitedPage);
return $this;
}
}
also I think you will need to add cascade={"persist"} to your private $visitedPages; inside of User object:
/**
*
* #ORM\OneToMany(targetEntity="AppBundle\Entity\VisitedPage", mappedBy="user", cascade={"persist"})
*/
private $visitedPages;
I fixed the issue by running this command - bin/console doctrine:cache:clear-metadata
You should run
php app/console cache:clear --env=prod
or
php app/console cache:clear --env=dev
depending upon env you are working

Embedded forms relations doctrine

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.

Foreign key on composite primary key not working

I have an entity that references another entity with a composite primary key.
I'm simply doing a ManyToOne relationship. Each company can have many trades. Each company is part of some Stock Exchange and its unique identifier is both the Stock Exchange they're listed on and their stock symbol.
The error that I get when I try to update the schema is:
Column name ``id`` referenced for relation from Application\Entity\Trade towards Application\Entity\Company does not exist.
I think it's trying to default to id on the company. Is there any way to specify multiple foreign keys for the primary key on one table?
<?php
namespace Application\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="trade")
*/
class Trade
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(name="id",type="integer")
*/
protected $id;
/**
* #ORM\Column(type="integer")
*/
protected $price;
/**
* #ORM\Column(type="integer")
*/
protected $size;
/**
* #ORM\Column(type="datetime")
*/
protected $dateTime;
/**
* #ORM\ManyToOne(targetEntity="Application\Entity\Company", inversedBy="trade")
*/
protected $company;
/**
* #return mixed
*/
public function getPrice()
{
return $this->price;
}
/**
* #param mixed $price
*/
public function setPrice($price)
{
$this->price = $price;
}
/**
* #return mixed
*/
public function getSize()
{
return $this->size;
}
/**
* #param mixed $size
*/
public function setSize($size)
{
$this->size = $size;
}
/**
* #return mixed
*/
public function getDateTime()
{
return $this->dateTime;
}
/**
* #param mixed $dateTime
*/
public function setDateTime($dateTime)
{
$this->dateTime = $dateTime;
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return mixed
*/
public function getCompany()
{
return $this->company;
}
/**
* #param mixed $company
*/
public function setCompany($company)
{
$this->company = $company;
}
}
Here's the company entity if that helps
<?php
namespace Application\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="company")
*/
class Company
{
/**
* #ORM\Id
* #ORM\Column(length=5)
*/
protected $symbol;
/**
* #ORM\Id #ORM\ManyToOne(targetEntity="\Application\Entity\Exchange", inversedBy="company")
* #ORM\JoinColumn(name="exchangeKey", referencedColumnName="exchangeKey")
*/
protected $exchange;
/**
* #return mixed
*/
public function getSymbol()
{
return $this->symbol;
}
/**
* #param mixed $symbol
*/
public function setSymbol($symbol)
{
$this->symbol = $symbol;
}
/**
* #return mixed
*/
public function getExchange()
{
return $this->exchange;
}
/**
* #param mixed $exchange
*/
public function setExchange($exchange)
{
$this->exchange = $exchange;
}
}
You should be able to reference multiple columns using the #ORM\JoinColumns annotation. Inside you can define one or more #ORM\JoinColumn annotations.
For example
/**
* #ORM\ManyToOne(targetEntity="Application\Entity\Company", inversedBy="trade")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="symbol", referencedColumnName="symbol"),
* #ORM\JoinColumn(name="exchange", referencedColumnName="exchangeKey")
* });
*/
protected $company;
I was going to link to the documentation, however all I can find is this.
An array of #JoinColumn annotations for a #ManyToOne or #OneToOne relation with an entity that has multiple identifiers.

Symfony2 Doctrine OneToMany Error

I have a big understanding problem with OneToMany Relationship - i searched a lot but that didnt help, maybe someone can help me with this.
I have a Event Entity with OneToMany Relation
<?php
namespace #\#\#;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Turmforum\BookingBundle\Entity\Contact;
/**
* Event
*
* #ORM\Table(name="events")
* #ORM\Entity
*/
class Event
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Contact", mappedBy="event")
*/
protected $event_contacts;
/**
*
*/
public function __construct() {
$this->contacts = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function getContacts() {
return $this->contacts;
}
public function addContact(Contact $contact) {
$this->contacts[] = $contact;
return $this;
}
And have a Contact Entity with ManyToOne Relation
<?php
namespace #\#\#;
use Doctrine\ORM\Mapping as ORM;
use Turmforum\BookingBundle\Entity\Event;
/**
* Contact
*
* #ORM\Table(name="contacts")
* #ORM\Entity
*/
class Contact
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Event", inversedBy="event_contacts")
* #ORM\JoinColumn(name="event_id", referencedColumnName="id")
*/
protected $event;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getEvent() {
return $this->event;
}
When i try to save my event details over a form i get the error:
Neither the property "event_id" nor one of the methods "getEventId()",
"eventId()", "isEventId()", "hasEventId()", "__get()" exist and have
public access in class "Turmforum\BookingBundle\Entity\Event".
What am i missing?

Categories