I follow the docs from here http://symfony.com/doc/current/book/doctrine.html
and I have a issue.
I created a relation between the category and the product model. The database has been updated correctly, model classes have right getters and setters, but if I try to run following code:
$product = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product')
->findById(1);
$categoryName = $product->getCategory()->getName();
I gets an error:
FatalErrorException: Error: Call to a member function getName() on a
non-object in
D:\www\Symfony\src\Acme\StoreBundle\Controller\DefaultController.php
line 28
I checked it out and the category model class has getName() method and it is a public method.
My Product.orm.yml looks like
Acme\StoreBundle\Entity\Product:
type: entity
manyToOne:
category:
targetEntity: Category
inversedBy: products
joinColumn:
name: category_id
referencedColumnName: id
table: null
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
name:
type: string
length: 255
price:
type: decimal
lifecycleCallbacks: { }
Category.orm.yml
Acme\StoreBundle\Entity\Category:
type: entity
oneToMany:
products:
targetEntity: Product
mappedBy: category
table: null
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
name:
type: string
length: '255'
lifecycleCallbacks: { }
Product.php
...
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
...
Category.php
...
/**
* #ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
protected $products;
public function __construct() {
$this->products = new ArrayCollection();
}
...
What's the problem?
You are retrieving a $category instead of a $product in your sample code.
$product = $this->getDoctrine()->getManager()->getRepository('AcmeStoreBundle:Product')->findOneById(1);
$categoryName = $product->getCategory()->getName();
note that you forgot the getManager()
Edit : You need to use findOneById() instead of findById. The first method will return only one single result (your object), the findBy* will return you an array of results on which you can't call getCategory() without traversing it inside a loop.
Related
I have 2 Entities:
Categories and products.
How can I build a relationship between these Entities?
Category Entity:
class Category
{
private $id;
private $name;
private $parent;
public function getChildren()
{
return $this->children;
}
//setters and getters
}
Items Entity:
class Items
{
private $id;
private $name;
private $price;
private $color;
private $size;
private $weight;
//getters and setters
}
Category yml:
AppBundle\Entity\Category:
type: entity
oneToMany:
children:
targetEntity: AppBundle\Entity\Category
mappedBy: parent
orderBy:
name: ASC
manyToOne:
parent:
targetEntity: AppBundle\Entity\Category
inversedBy: children
joinColumn:
name: parentId
referencedColumn: id
table: category
repositoryClass: AppBundle\Repository\CategoryRepository
id:
id:
column: id
type: integer
id: true
generator:
generator:
strategy: AUTO
fields:
name:
type: string
lenght: 255
Items yml:
AppBundle\Entity\Items:
type: entity
table: items
repositoryClass: AppBundle\Repository\ItemsRepository
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
name:
type: string
length: 255
price:
type: integer
color:
type: string
length: 255
nullable: true
size:
type: integer
weight:
type: integer
One product can belong to several categories, how can this be done? I think that is the ManyToMany relationship, but I can't build relations correctly.
.....................................................................................................................................................................
Add in your Category yml:
oneToMany:
items:
targetEntity: Namespace\TO\YOUR\Entity\Item
mappedBy: category
Add in your Item yml:
manyToOne:
catregory:
targetEntity: Namespace\TO\YOUR\Entity\Category
inversedBy: items
joinColumn:
name: category_id
referencedColumn: id
Add in your Item Entity:
/**
* #var Catregory
*/
protected $catregory;
public function setCategory(Catregory $catregory) {
$this->catregory = $catregory;
}
public function getCatregory() {
return $this->catregory;
}
Add in your Category Entity:
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
.................
/**
* #var Collection of Item
*/
protected $items;
public function __construct() {
$this->items = new ArrayCollection();
}
public function getItems() {
return $this->items;
}
public function setItems(Collection $items) {
$this->items = $items;
}
public function addItem(Item $item) {
if (!$this->Items->contains($item)) {
$item->setCategory($this);
$this->items->add($item);
}
}
public function removeItem(Item $item) {
if ($this->items->contains($item)) {
$this->items->remove($item);
}
}
public function clearItems() {
$this->items->clear();
}
I have two doctrine entities (Company and Supplier) linked together by a CompanySupplier entity. Entities and yaml resources are as below:
class Company
{
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $name;
}
class Supplier
{
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $name;
}
class CompanySupplier
{
/**
* #var integer
*/
private $id;
/**
* #var integer
*/
private $company_id;
/**
* #var integer
*/
private $supplier_id;
}
My resources are as below:
AppBundle\Entity\Company:
type: entity
table: companies
id:
id:
type: integer
fields:
name:
type: string
manyToMany:
Suppliers:
targetEntity: Supplier
joinTable:
name: company_suppliers
joinColumns:
company_id:
referencedColumnName: id
inverseJoinColumns:
supplier_id:
referencedColumnName: id
AppBundle\Entity\Supplier:
type: entity
table: suppliers
id:
id:
type: integer
fields:
name:
type: string
AppBundle\Entity\CompanySupplier:
type: entity
table: company_suppliers
id:
id:
type: integer
fields:
company_id:
type: integer
supplier_id:
type: integer
ManyToMany:
Supplier:
targetEntity: Supplier
joinColumn:
name: id
referencedColumnName: supplier_id
The problem is this seems to cause a “relation company_supplier does not exist” error which I can’t see how to resolve. What do I need to do to set the relations up so that these work?
It works if I don't have the CompanySupplier entity and resource, but as soon as I define those errors start appearing.
I'd appreciate any pointers this is driving me mad.
do change the namespaces and you don't need to write the relational table i think
see here
Company:
type: entity
manyToMany:
supplier:
targetEntity: CompanySupplier
inversedBy: company
joinTable:
name: company_suppliers
joinColumns:
name: id
referencedColumnName: supplier_id
inverseJoinColumns:
supplier_id:
referencedColumnName: id
Supplier:
type: entity
manyToMany:
company:
targetEntity: Company
mappedBy: supplier
I have a strange problem using a many-to-many relation in Symfony (with Doctrine), I've never had before in symfony projects with many-to-many relations and I can't find any difference to the other projects.
I have the two entitys Product and Tag and a many-to-many relation to each other. Unfortunately, if I try to add a product to a tag or vice versa, the error
Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "TestBundle\Entity\Product#$tags", got "TestBundle\Entity\Tag" instead.
appears.
The code used to add a tag to a product:
$tag1 = $em->getRepository('TestBundle:Tag')->findOneBy(array(
'tag' => "Bla"
));
$tag1->addProduct($product);
$em->persist($tag1);
$em->persist($product);
$em->flush();
Of course, the variable $tag1 and $product both contain a valid entity.
The YAML file for the many-to-many relations (I cut away irrelevant parts):
TestBundle\Entity\Tag:
type: entity
table: tags
repositoryClass: TestBundle\Repository\TagRepository
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
tag:
type: string
length: 255
unique: true
manyToMany:
products:
targetEntity: Product
mappedBy: tags
lifecycleCallbacks: { }
Product:
TestBundle\Entity\Product:
type: entity
table: products
repositoryClass: TestBundle\Repository\ProductRepository
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
name:
type: string
length: 255
unique: true
manyToOne:
manufacturer:
targetEntity: Manufacturer
inversedBy: products
joinColumn:
name: manufacturer_id
referencedColumnName: id
onDelete: CASCADE
manyToMany:
tags:
targetEntity: Product
inversedBy: products
joinTable:
name: tags2products
joinColumns:
tag_id:
referencedColumnName: id
inverseJoinColumns:
product_id:
referencedColumnName: id
lifecycleCallbacks: { }
The setter and getter functions also don't contain any special tricks:
The Tag.php entity file contains:
/**
* Constructor
*/
public function __construct()
{
$this->product = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add product
*
* #param \TestBundle\Entity\Product $product
*
* #return Tag
*/
public function addProduct(\TestBundle\Entity\Product $product)
{
$product->addTag($this);
$this->product[] = $product;
return $this;
}
public function removeProduct(\TestBundle\Entity\Product $product)
{
$this->product->removeElement($product);
}
/**
* Get products
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProducts()
{
return $this->products;
}
While the Product.php contains:
/**
* Add tag
*
* #param \TestBundle\Entity\Tag $tag
*
* #return Product
*/
public function addTag(Tag $tag)
{
$this->tags->add($tag);
//$this->tags[] = $tag;
return $this;
}
/**
* Remove tag
*
* #param \TestBundle\Entity\Tag $webpage
*/
public function removeTag(Tag $tag)
{
$this->tags->removeElement($tag) ;
}
/**
* Get webpages
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}
I also tried to add a $this->tags = new ArrayCollection(); to the constructor of the product, but it didnt change anything.
Also, there is no problem adding, reading and persisting tags to products. The error is thrown as soon as I call $em->flush().
Does anybody know why my Product entity expects a array collection? I never told him to expect one! Thank you very much in advance!
The error is telling you that the property "#tags" of the entity TestBundle\Entity\Product that you are trying to flush, contains an object of type TestBundle\Entity\Tag instead of a collection of this object. Doctrine expects this collection/array because the metadata for that property states that TestBundle\Entity\Product is in a many-yo-many with TestBundle\Entity\Tag and the relation is done via the property "#tags". This should happen if:
//You did this
$this->tags = $tag;
//instead of what you actually did which is correct
$this->tags->add($tag);
//Or
$this->tags[] = $tag;
But the code that you posted here should not produce that exception.
Are you sure there is no other place where an accessor method is called that changes the tags property of TestBundle\Entity\Product? Something like and event listener?
I finally found out what the strange problem was. Thank you Alexandr Cosoi for confirming the way I tried to add my entity.
The Problem was a configuration error I didn't notice.
manyToMany:
tags:
targetEntity: Product
inversedBy: products
joinTable:
name: tags2products
joinColumns:
tag_id:
referencedColumnName: id
inverseJoinColumns:
product_id:
referencedColumnName: id
targetEntity was set to Product but it had to be set to "Tag". Changing it just solved my problem as expected. :)
I understood how Query Builder works but I am trying to use the ORM correctly.
I have two entities: Days and Tasks
The Tasks entity is linked to the Day Entity with a ManyToOne association.
Tasks.orm.yml
DJU\ MyBundle\ Entity\ Tasks:
type: entity
table: null
repositoryClass: DJU\ MyBundle\ Entity\ TasksRepository
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
description:
type: text
manyToOne:
days:
targetEntity: Days
inversedBy: tasks
joinColumn:
name: days_id
referencedColumnName: id
Tasks.php
class Tasks {
/**
* Get temps
*
* #return \CIT\CalendarBundle\Entity\Temps
*/
public function getTemps()
{
return $this->temps;
}
}
Here is my controller:
class DefaultController extends Controller
{
public function example2CalAction() {
$em = $this->getDoctrine()->getManager();
$tasks = $em->getRepository('DJUMyBundle:Tasks')->findAll();
foreach($tasks as $onetask) {
if ( $onetask->getDays()->getId() == '1' ) {
$myt = $onetask->getDays();
}
}
return $this->render('DJUMyBundle:Default:sample2.html.twig', array('tasks' => $myt));
}
}
As you can see my request has poor performance. I would like to find Tasks by Days id. How can I do?
Thank you
Repositories are your solution.
class TasksRepository {
public function findByDay(Day $day)
{
$q = $this
->createQueryBuilder('t')
->select('t')
->leftJoin('t.days', 'd')
->where("d.id = :dayId")
->setParameter('dayId', $dayId)
->getQuery();
$result = $q->getResult();
return $result;
}
}
Find your tasks for day 1 using:
$day = $em->getRepository('DJUMyBundle:Day')->find(1);
$tasks = $em->getRepository('DJUMyBundle:Tasks')->findByDay($day);
for some reason whenever i use php app/console doctrine:schema:update --dump-sql it gives me this error:
[ReflectionException]
Property sava\UserBundle\Entity\User::$Tickets does not exist
usually i first create the orm and then generate with doctrine:generate:entities, my problem is whenever im trying to update the schema, it gives me this error, i have already tried:
clear doctrine cache with php app/console doctrine:cache:clear-query, clear mapping, ect.
manually deleting the cache folder.
deleting ticket entity and generating them again.
setting all the fields to protected.
i ran out of ideas.
error this are my dependencys.
User.Orm:
sava\UserBundle\Entity\User:
type: entity
table: User
fields:
id:
id: true
type: integer
generator:
strategy: AUTO
nombreCliente:
type: string
length: 200
fixed: false
nullable: false
column: nombre_cliente
rifCedula:
type: string
length: 40
fixed: false
nullable: false
column: rif_cedula
telefono:
type: string
length: 30
fixed: false
nullable: true
celular:
type: string
length: 30
fixed: false
nullable: true
direccion:
type: string
length: 250
fixed: false
nullable: true
oneToMany:
Tickets:
targetEntity: sava\SoporteBundle\Entity\TblTicket
mappedBy: idUser
cascade: ["persist", "remove"]
lifecycleCallbacks: { }
Ticket.Orm.
sava\SoporteBundle\Entity\TblTicket:
type: entity
table: tbl_ticket
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
titulo:
type: string
length: '80'
contenido:
type: text
isClosed:
type: boolean
fecha:
type: date
oneToMany:
respuestas:
targetEntity: sava\SoporteBundle\Entity\TblRespuesta
mappedBy: ticket
cascade: ["persist", "remove"]
oneToOne:
idUser:
targetEntity: sava\UserBundle\Entity\User
inversedBy: Tickets
#nullable: true
joinColumn:
name: id_user
referencedColumnName: id
lifecycleCallbacks: { }
Ticket entity(deleted some unrelated fields for clarity):
<?php
namespace sava\SoporteBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* TblTicket
*/
class TblTicket
{
/**
* #var integer
*/
private $id;
/**
* #var \Doctrine\Common\Collections\Collection
*/
public function __construct()
{
$this->respuestas = new \Doctrine\Common\Collections\ArrayCollection();
}
protected $idUser;
public function setIdUser(\sava\UserBundle\Entity\User $idUser = null)
{
$this->idUser = $idUser;
return $this;
}
/**
* Get idUser
*
* #return \sava\UserBundle\Entity\User
*/
public function getIdUser()
{
return $this->idUser;
}
}
>
this is my ticket entity extended by fos/user/bundle (some fields where deleted for clarity):
namespace sava\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
/**
* user
*
*/
class User extends BaseUser
{
public function __construct()
{
parent::__construct();
//$this->User = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* #var \Doctrine\Common\Collections\Collection
*/
protected $Tickets;
/**
* Add Tickets
*
* #param \sava\SoporteBundle\Entity\TblTicket $tickets
* #return User
*/
public function addTicket(\sava\SoporteBundle\Entity\TblTicket $tickets)
{
$this->Tickets[] = $tickets;
return $this;
}
/**
* Remove Tickets
*
* #param \sava\SoporteBundle\Entity\TblTicket $tickets
*/
public function removeTicket(\sava\SoporteBundle\Entity\TblTicket $tickets)
{
$this->Tickets->removeElement($tickets);
}
/**
* Get Tickets
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTickets()
{
return $this->Tickets;
}
}
nevermind, an old bundle where i was testing the userbundle had an entity that somehow was being targeted by doctrine. deleted the old bundle and its working fine.
if you ever have this problem check your bundles for extra unwanted entities or the namespaces.
You have to update your entity first:
php app/console doctrine:generate:entities [YourBundle:YouEntity]