Reflect MySQL polymorphic association in Doctrine 2.2 - doctrine-orm

I'm using Doctrine 2.2.0 together with Codeigniter. I'm new to Doctrine (or to ORM in general).
I'm setting up entity and proxy classes based on YAML files which works fine. I do have problems in reflecting a polymorphic association in my DB in my Doctrine classes. I'm looking for a concrete example on how to implement the following polymorphic association in Doctrine.
In my DB I have a table called products. Depending on the value of field object_type and object_id I want to relate either to a record in the table videos or the table cars (I simplified it here). I want to keep both product types in 2 separate table because one has nothing to do with the other and both tables relate to other tables.
I took a look at the Doctrine Inheritance documentation and other examples, but it doesn't seem to help me. If possible I want to avoid adding the columns description and price to the tables videos and cars.
Many thanks!
|Table: products |
|-----------------------------------------------------|
| ID | description | price | object_type | object_id |
|-----------------------------------------------------|
| 1 | A video | 20.00 | video | 12 |
| 2 | A car | 159.00 | car | 5 |
|Table: videos |
|--------------------------------------------|
| ID | filename | artist_id | date |
|--------------------------------------------|
| 12 | somename.mp4 | 189 | 2011-02-15 |
|Table: cars |
|------------------------------|
| ID | brand_id | model | year |
|------------------------------|
| 5 | 17 | astra | 2010 |

Found the solution myself. I've listed below the different steps I've done. This answer is very big, but I tried to be as complete as possible.
The most important things are in the Product YAML files inheritanceType: JOINED, discriminatorColumn:, discriminatorMap: and the Video and Car entity classes class Video extends Product, class Car extends Product.
1) DB Schema
CREATE TABLE IF NOT EXISTS `artists` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `brands` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `cars` (
`id` int(11) NOT NULL,
`model` varchar(255) NOT NULL,
`release_date` date NOT NULL,
`brand_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`description` varchar(255) NOT NULL,
`price` double NOT NULL,
`object_type` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `videos` (
`id` int(11) NOT NULL,
`file_name` varchar(255) NOT NULL,
`release_date` date NOT NULL,
`artist_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
2) Doctrine YAML files (from which you need to create the Entity and proxy classes)
Entities.Artist.dcm.yml
Entities\Artist:
type: entity
table: artists
id:
id:
type: integer
primary: true
notnull: true
generator:
strategy: AUTO
fields:
name:
type: string(255)
notnull: true
oneToMany:
videos:
targetEntity: Video
mappedBy: artist
options:
charset: utf8
type: InnoDB
Entities.Brand.dcm.yml
Entities\Brand:
type: entity
table: brands
id:
id:
type: integer
primary: true
notnull: true
generator:
strategy: AUTO
fields:
name:
type: string(255)
notnull: true
oneToMany:
cars:
targetEntity: Car
mappedBy: brand
options:
charset: utf8
type: InnoDB
Entities.Car.dcm.yml
Entities\Car:
type: entity
table: cars
fields:
model:
type: string
notnull: true
release_date:
type: date
notnull: true
oneToOne: #unidirectional
brand:
targetEntity: Brand
joinColumns:
brand_id:
referencedColumnName: id
options:
charset: utf8
type: InnoDB
Entities.Product.dcm.yml
Entities\Product:
type: entity
table: products
id:
id:
type: string
primary: true
notnull: true
generator:
strategy: AUTO
fields:
description:
type: string(255)
notnull: true
price:
type: decimal
notnull: true
inheritanceType: JOINED
discriminatorColumn:
name: object_type
type: string
length: 255
discriminatorMap:
video: Video
car: Car
options:
charset: utf8
type: InnoDB
Entities.Video.dcm.yml
Entities\Video:
type: entity
table: videos
fields:
file_name:
type: string
notnull: true
release_date:
type: date
notnull: true
oneToOne: #unidirectional
artist:
targetEntity: Artist
joinColumns:
artist_id:
referencedColumnName: id
options:
charset: utf8
type: InnoDB
3) Create Entity and Proxy classes
I use CodeIgniter. I've used Joel Verhagen's excellent guide
!! It's important you extend Video and Car with Product - See below !!
This results in the following Entity classes
Artist.php
namespace Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Entities\Artist
*
* #ORM\Table(name="artists")
* #ORM\Entity
*/
class Artist
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(targetEntity="Entities\Video", mappedBy="artist")
*/
private $videos;
public function __construct()
{
$this->videos = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Artist
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add videos
*
* #param Entities\Video $videos
*/
public function addVideo(\Entities\Video $videos)
{
$this->videos[] = $videos;
}
/**
* Get videos
*
* #return Doctrine\Common\Collections\Collection
*/
public function getVideos()
{
return $this->videos;
}
}
Brand.php
namespace Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Entities\Brand
*
* #ORM\Table(name="brands")
* #ORM\Entity
*/
class Brand
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(targetEntity="Entities\Car", mappedBy="brand")
*/
private $cars;
public function __construct()
{
$this->cars = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Brand
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add cars
*
* #param Entities\Car $cars
*/
public function addCar(\Entities\Car $cars)
{
$this->cars[] = $cars;
}
/**
* Get cars
*
* #return Doctrine\Common\Collections\Collection
*/
public function getCars()
{
return $this->cars;
}
}
Car.php
namespace Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Entities\Car
*
* #ORM\Table(name="cars")
* #ORM\Entity
*/
class Car extends Product //Important that Car extends Product
{
/**
* #var string $model
*
* #ORM\Column(name="model", type="string")
*/
private $model;
/**
* #var date $release_date
*
* #ORM\Column(name="release_date", type="date")
*/
private $release_date;
/**
* #var Entities\Brand
*
* #ORM\OneToOne(targetEntity="Entities\Brand")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="brand_id", referencedColumnName="id", unique=true)
* })
*/
private $brand;
/**
* Set model
*
* #param string $model
* #return Car
*/
public function setModel($model)
{
$this->model = $model;
return $this;
}
/**
* Get model
*
* #return string
*/
public function getModel()
{
return $this->model;
}
/**
* Set release_date
*
* #param date $releaseDate
* #return Car
*/
public function setReleaseDate($releaseDate)
{
$this->release_date = $releaseDate;
return $this;
}
/**
* Get release_date
*
* #return date
*/
public function getReleaseDate()
{
return $this->release_date;
}
/**
* Set brand
*
* #param Entities\Brand $brand
* #return Car
*/
public function setBrand(\Entities\Brand $brand = null)
{
$this->brand = $brand;
return $this;
}
/**
* Get brand
*
* #return Entities\Brand
*/
public function getBrand()
{
return $this->brand;
}
}
Product.php
namespace Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Entities\Product
*
* #ORM\Table(name="products")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="", type="", length=)
* #ORM\DiscriminatorMap({"video" = "Entities\Video", "car" = "Entities\Car"})
* #ORM\Entity
*/
class Product
{
/**
* #var string $id
*
* #ORM\Column(name="id", type="string")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string $description
*
* #ORM\Column(name="description", type="string", length=255)
*/
private $description;
/**
* #var decimal $price
*
* #ORM\Column(name="price", type="decimal")
*/
private $price;
/**
* Get id
*
* #return string
*/
public function getId()
{
return $this->id;
}
/**
* Set description
*
* #param string $description
* #return Product
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set price
*
* #param decimal $price
* #return Product
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* #return decimal
*/
public function getPrice()
{
return $this->price;
}
}
Video.php
namespace Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Entities\Video
*
* #ORM\Table(name="videos")
* #ORM\Entity
*/
class Video extends Product //Important that Video extends Product
{
/**
* #var string $file_name
*
* #ORM\Column(name="file_name", type="string")
*/
private $file_name;
/**
* #var date $release_date
*
* #ORM\Column(name="release_date", type="date")
*/
private $release_date;
/**
* #var Entities\Artist
*
* #ORM\OneToOne(targetEntity="Entities\Artist")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="artist_id", referencedColumnName="id", unique=true)
* })
*/
private $artist;
/**
* Set file_name
*
* #param string $fileName
* #return Video
*/
public function setFileName($fileName)
{
$this->file_name = $fileName;
return $this;
}
/**
* Get file_name
*
* #return string
*/
public function getFileName()
{
return $this->file_name;
}
/**
* Set release_date
*
* #param date $releaseDate
* #return Video
*/
public function setReleaseDate($releaseDate)
{
$this->release_date = $releaseDate;
return $this;
}
/**
* Get release_date
*
* #return date
*/
public function getReleaseDate()
{
return $this->release_date;
}
/**
* Set artist
*
* #param Entities\Artist $artist
* #return Video
*/
public function setArtist(\Entities\Artist $artist = null)
{
$this->artist = $artist;
return $this;
}
/**
* Get artist
*
* #return Entities\Artist
*/
public function getArtist()
{
return $this->artist;
}
}
3) Creating a new Car and a new Video
This is what goes in my CodeIgniter controller. The code presumes you've created an artist with the name Metallica and a brand with the name Ford.
public function createVideo()
{
//Instantiate new Entities\Video object
$video = new Entities\Video;
//Since it extends Entities\Product you can set the common Product properties
$video->setDescription('This is a Metallica clip');
$video->setPrice(19.95);
//Setting the custom Video properties
$artist = $this->doctrine->em->getRepository('Entities\Artist')->findOneBy(array('name' => 'Metallica'));
$video->setArtist($artist);
$video->setReleaseDate(new DateTime());
$video->setFileName('metallica.mp4');
//Save
$this->doctrine->em->persist($video);
$this->doctrine->em->flush();
}
public function createCar()
{
//Instantiate new Entities\Car object
$car = new Entities\Car;
//Since it extends Entities\Product you can set the common Product properties
$car->setDescription('This is Ford Mondeo of 2011');
$car->setPrice(19.95);
//Setting the custom Car properties
$brand = $this->doctrine->em->getRepository('Entities\Brand')->findOneBy(array('name' => 'Ford'));
$car->setBrand($brand);
$car->setReleaseDate(DateTime::createFromFormat('Y-m-d', '2011-11-15'));
$car->setModel('Mondeo');
//Save
$this->doctrine->em->persist($car);
$this->doctrine->em->flush();
}
4) Extracting all products
An example on how to extract all Products
public function extractAllProducts()
{
$products = $this->doctrine->em->getRepository('Entities\Product')->findAll();
foreach($products as $product)
{
printf('%s for € %s<br />', $product->getDescription(), $product->getPrice());
}
}
This results into
This is a Metallica clip for € 19.95
This is Ford Mondeo of 2011 for € 19.95
An example onn how to extract all Videos
public function extractAllVideos()
{
$videos = $this->doctrine->em->getRepository('Entities\Video')->findAll();
foreach($videos as $video)
{
printf('%s, released %s for € %s<br />', $video->getDescription(), $video->getReleaseDate()->format('Y'), $video->getPrice());
}
}
This results into
This is a Metallica clip, released 2012 for € 19.95

You were looking in the right place, inheritance mapping is certainly what you need to achieve this. From what I can tell this is a perfect example of "class table inheritance".
Check out the manual for some example / explanation on how to implement this.
http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/inheritance-mapping.html#class-table-inheritance

Related

Doctrine not loading annotations from my entities

I'm trying to load Doctrine entities but it keeps creating the tables without any regard for the annotations I've provided. What I really want to do is put a unique constraint on $email but just to prove something's funny, I changed the size of the $email field to 200.
I'm trying to run the ./vendor/bin/doctrine orm:schema:create --dump-sql. I get the following output:
CREATE TABLE user (
id INT AUTO_INCREMENT NOT NULL,
email VARCHAR(255) NOT NULL,
unverifiedEmail VARCHAR(255) DEFAULT NULL,
unverifiedEmailHash VARCHAR(255) DEFAULT NULL,
passwordHash VARCHAR(255) NOT NULL,
passwordResetHash VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
I formatted it pretty, but changed nothing else.
Here's my entity at vendor/redacted/user-entity/src/User.php
namespace Redacted\User\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="user")
*/
class User
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(name="id", type="integer")
* #var int
*/
protected $id;
/**
* #ORM\Column(name="email", type="string", length=255, unique=true)
* #var string
*/
protected $email;
/**
* #ORM\Column(name="unverifiedEmail", type="string", length=255, nullable=true)
* #var string
*/
protected $unverifiedEmail;
/**
* #ORM\Column(name="unverifiedEmailHash", type="string", length=255, nullable=true)
* #var string
*/
protected $verifyEmailHash;
/**
* #var string
* At this time, http://php.net/manual/en/function.password-hash.php recommends using 255 length for hashes
* #ORM\Column(name="passwordHash", type="string", length=255)
*/
protected $passwordHash;
/**
* #var string
* #ORM\Column(name="passwordResetHash", type="string", length=255, nullable=true)
*/
protected $passwordResetHash;
/**
* #return mixed
*/
public function getUnverifiedEmail()
{
return $this->unverifiedEmail;
}
/**
* #param mixed $unverifiedEmail
*/
public function setUnverifiedEmail($unverifiedEmail)
{
$this->unverifiedEmail = $unverifiedEmail;
}
/**
* #return mixed
*/
public function getVerifyEmailHash()
{
return $this->verifyEmailHash;
}
/**
* #param mixed $verifyEmailHash
*/
public function setVerifyEmailHash($verifyEmailHash)
{
$this->verifyEmailHash = $verifyEmailHash;
}
/**
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* #param string $email
*/
public function setEmail($email)
{
$this->email = $email;
}
/**
* #return string
*/
public function getPasswordHash()
{
return $this->passwordHash;
}
/**
* #param string $passwordHash
*/
public function setPasswordHash($passwordHash)
{
$this->passwordHash = $passwordHash;
}
/**
* #return string
*/
public function getPasswordResetHash(): string
{
return $this->passwordResetHash;
}
/**
* #param string $passwordResetHash
*/
public function setPasswordResetHash(string $passwordResetHash)
{
$this->passwordResetHash = $passwordResetHash;
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id)
{
$this->id = $id;
}
public function toArray()
{
return [
'email' => $this->getEmail(),
'id' => $this->getId()
];
}
}
And here's my cli-config.php.
require __DIR__.'/vendor/autoload.php';
$paths = array(__DIR__."/vendor/redacted/user-entity/src");
$isDevMode = false;
// the connection configuration
$dbParams = array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => 'redacted',
'dbname' => 'user'
);
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode, null, null, false);
$entityManager = EntityManager::create($dbParams, $config);
return ConsoleRunner::createHelperSet($entityManager);
One more thing I should mention: I have never got this working before in several projects. We just have so many on the go and they all have this issue and I'm getting around to resolve it, but I did have this working in tons of ZF2 projects, but they don't share this setup scheme.
As #malarzm said above, you may need to clear your cache. Here are the commands I run any time I change doctrine configurations in my ZF2 app:
rm -Rf data/DoctrineModule/cache/*
rm -Rf data/DoctrineORMModule/Proxy/*

Doctrine 2 one-to-many relationship

I have the following:
User have one group, group can have many users
User
<?php namespace Application\Model;
use Doctrine\Common\Collections;
use Doctrine\ORM\Mapping as ORM;
/**
* User model
* Read-only entity
* #ORM\Table(name="VLOGGER_WEBCALENDAR_USR")
* #ORM\Entity
* #package Application\Model
*/
class User
{
/**
* #var int
* #ORM\Id
* #ORM\Column(name="USR_ID", type="integer")
*/
protected $id;
/**
* #var string
* #ORM\Column(name="USR_LOGIN", type="string")
*/
protected $login;
/**
* #var string
* #ORM\Column(name="USR_CODE", type="string")
*/
protected $code;
/**
* #var int
* #ORM\Column(name="GRP_ID", type="integer")
*/
protected $groupId;
/**
* #var string
* #ORM\Column(name="GRP_CODE", type="string")
*/
protected $groupCode;
/**
* #var User\Group
* #ORM\ManyToOne(targetEntity="Application\Model\User\Group",fetch="EAGER")
* #ORM\JoinColumn(name="GRP_ID", referencedColumnName="GRP_ID")
*/
protected $group;
/**
* #var Event
* #ORM\OneToMany(targetEntity="Application\Model\Event", mappedBy="user")
* #ORM\JoinColumn(name="USR_ID", referencedColumnName="USR_ID")
*/
protected $events;
/**
* Constructor
*/
public function __construct()
{
$this->events = new Collections\ArrayCollection();
}
/**
* #return string
*/
public function getCode()
{
return $this->code;
}
/**
* #param string $code
* #return User
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* #return Event
*/
public function getEvents()
{
return $this->events;
}
/**
* #param Event $events
* #return User
*/
public function setEvents($events)
{
$this->events = $events;
return $this;
}
/**
* #return User\Group
*/
public function getGroup()
{
return $this->group;
}
/**
* #param User\Group $group
* #return User
*/
public function setGroup($group)
{
$this->group = $group;
return $this;
}
/**
* #return string
*/
public function getGroupCode()
{
return $this->groupCode;
}
/**
* #param string $groupCode
* #return User
*/
public function setGroupCode($groupCode)
{
$this->groupCode = $groupCode;
return $this;
}
/**
* #return int
*/
public function getGroupId()
{
return $this->groupId;
}
/**
* #param int $groupId
* #return User
*/
public function setGroupId($groupId)
{
$this->groupId = $groupId;
return $this;
}
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #param mixed $id
* #return User
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* #return string
*/
public function getLogin()
{
return $this->login;
}
/**
* #param string $login
* #return User
*/
public function setLogin($login)
{
$this->login = $login;
return $this;
}
}
Group
<?php namespace Application\Model\User;
use Application\Model;
use Doctrine\Common\Collections;
use Doctrine\ORM\Mapping as ORM;
/**
* User group model
* Read-only entity
* #ORM\Table(name="VLOGGER_WEBCALENDAR_GRP")
* #ORM\Entity
* #package Application\Model
*/
class Group
{
/**
* #var int
* #ORM\Id
* #ORM\Column(name="GRP_ID", type="integer")
*/
protected $id;
/**
* #var string
* #ORM\Column(name="GRP_CODE", type="string")
*/
protected $code;
/**
* #var Collections\ArrayCollection
* #ORM\OneToMany(targetEntity="Application\Model\User", mappedBy="group")
* #ORM\JoinColumn(name="GRP_ID", referencedColumnName="GRP_ID")
*/
protected $users;
/**
* Constructor
*/
public function __construct()
{
$this->users = new Collections\ArrayCollection();
}
/**
* #return mixed
*/
public function getCode()
{
return $this->code;
}
/**
* #param mixed $code
* #return Group
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* #param int $id
* #return Group
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* #return mixed
*/
public function getUsers()
{
return $this->users;
}
/**
* #param mixed $users
* #return Group
*/
public function setUsers($users)
{
$this->users = $users;
return $this;
}
}
When I try to retrieve the relation from the groups, it works great, but when I slect the users and try to get their group, Doctrine create some proxy objects and the result is an empty object with only the relationship key filled.
Can someone point me to the good direction ?
Here my code:
$query = $em->createQueryBuilder()
->select('u')
->from('Application\Model\User', 'u');
$data = $query->getQuery()->getResult();
$data = reset($data);
var_dump($data->getGroup()); // proxy
###########################
$query = $em->createQueryBuilder()
->select('g')
->from('Application\Model\User\Group', 'g');
$data = $query->getQuery()->getResult();
$data = reset($data);
var_dump($data->getUsers()); // ok
you don't need the $GRP_ID in the User Entity - it's already mapped with the $group relation. Doctrine handles the IDs automatically.
Also your naming-convention looks a bit weird. Normally you should use lowe-camel-case (to save you from strange errors)
Example:
$USR_CODE should be $usrCode -> to match your getter/setter: setUsrCode(), getUsrCode().
just noticed: you don't have any setters. You have to define setters for your attributes, with the naming-convention (look at my example above)
Edit:
you can map the column with the doctrine orm notation:
/**
*
* #ORM\Column(name="USR_CODE", type="string")
*/
private $usrCode;
And yes, you need setters otherwise doctrine won't be able to set the values.
You also need addUser() and removeUser() functions (since user is a Collection):
public function addUsers(Collection $users)
{
foreach($users as $user)
{
if( ! $this->users->contains($user))
{
$this->users->add($user);
$user->setGroup($this);
}
}
}
public function removeUsers(Collection $users)
{
foreach($users as $user)
{
if($this->users->contains($user)){
$this->users->remove($user);
$user->setGroup(null);
}
}
}

zf2 doctrine 2 - Output OnetoOne Unidirectional

After annotating an OneToOne Unidirectional, i want to output the joined column, without using a form.
One People Entity has got a column to store the id of Country Entity.
What i can do: I can store the id of the country into the People Entity using a form with a dropdown select, which is bound to the Country Entity.
Problem: I can not enter the value country of the, hopefully correct, joined table.
People Entity:
<?php
namespace People\Entity;
use Doctrine\ORM\Mapping as ORM;
// ...
/**
* A people entity.
*
* #ORM\Entity
* #ORM\Table(name="icd_people")
* #property int $id
// ...
* #property string $ic_hq_country
*/
class People implements InputFilterAwareInterface
{
protected $inputFilter;
/**
* #ORM\Id
* #ORM\Column(type="integer");
*/
protected $id;
/**
* #ORM\Column(type="integer")
* #ORM\OneToOne(targetEntity="Country")
* #ORM\JoinColumn(name="ic_hq_country", referencedColumnName="id")
*/
protected $ic_hq_country;
// getter and setter
}
The Country Entity:
<?php
namespace People\Entity;
use Doctrine\ORM\Mapping as ORM;
//...
/**
* A Country entity.
*
* #ORM\Entity
* #ORM\Table(name="pre_country")
* #property int $id
* #property string $country
*/
class Country implements InputFilterAwareInterface
{
protected $inputFilter;
/**
* #ORM\Id
* #ORM\Column(type="integer");
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $country;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set country
*
* #param string $country
* #return Country
*/
public function setCountry($country)
{
$this->country = $country;
return $this;
}
/**
* Get country
*
* #return string
*/
public function getCountry()
{
return $this->country;
}
/**
* Convert the object to an array.
*
* #return array
*/
public function getArrayCopy()
{
return get_object_vars($this);
}
public function setInputFilter(InputFilterInterface $inputFilter)
{
throw new \Exception("Not used");
}
public function getInputFilter()
{
throw new \Exception("Not used");
}
}
The Controller Action:
public function indexAction()
{
$userid = $this->zfcUserAuthentication()->getIdentity()->getId();
return new ViewModel(array(
'pea' => $this->getEntityManager()->find('People\Entity\People', $userid),
));
}
The View giving the id of the country, but not the name:
<?php echo $this->escapeHtml($pea->ic_hq_country);?>
I actually expected something like this being possible, to output the country name and not the id:
<?php echo $this->escapeHtml($pea->country);?>
Thank you for reading, and for any help, which could lead me into the right direction!
You should not use the #Column anotation in the $ic_hq_country field of the Peopleentity.
/**
* #ORM\OneToOne(targetEntity="Country")
* #ORM\JoinColumn(name="ic_hq_country", referencedColumnName="id")
*/
protected $ic_hq_country;
like this, hopefully ic_hq_country will be a proxy to the entity instead of the id.
so in your view you can use:
<?php echo $pea->ic_hq_country->getId();?>
and also
<?php echo $this->escapeHtml($pea->ic_hq_country->getCountry());?>

Add NULL Value in Bridge Table using many-to-many self referencing relationship

I have two tables:
category
id | name
1 | Programming
2 | Designing
3 | PHP
4 | C#
5 | Adobe Photoshop
category_tree
category_id | parent_id
1 | NULL
2 | NULL
3 | 1
4 | 1
5 | 2
Here is the Entity class:
/**
* #ORM\Entity
* #ORM\Table(name="category")
*/
class Category
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(type="text", name="name")
*/
protected $name;
/**
* #ORM\Column(type="text", name="description")
*/
/**
* #ORM\ManyToMany(targetEntity="Category")
* #ORM\JoinTable(name="category_tree",
* joinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="parent_id", referencedColumnName="id")}
* )
*/
protected $categories;
public function __construct()
{
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addCategory(Category $category)
{
$this->categories[] = $category;
return $this;
}
public function getCategories()
{
return $this->categories;
}
public function getId()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getName()
{
return $this->name;
}
}
How can i add NULL Value in "Category_tree" table?

Add NULL Values using Self referencing many-to-many Relationship

I have two tables:
category
id | name
1 | Programming
2 | Designing
3 | PHP
4 | C#
5 | Adobe Photoshop
category_tree
category_id | parent_id
1 | NULL
2 | NULL
3 | 1
4 | 1
5 | 2
Here is the Entity class:
/**
* #ORM\Entity
* #ORM\Table(name="category")
*/
class Category
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\Column(type="text", name="name")
*/
protected $name;
/**
* #ORM\Column(type="text", name="description")
*/
/**
* #ORM\ManyToMany(targetEntity="Category")
* #ORM\JoinTable(name="category_tree",
* joinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="parent_id", referencedColumnName="id")}
* )
*/
protected $categories;
public function __construct()
{
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addCategory(Category $category)
{
$this->categories[] = $category;
return $this;
}
public function getCategories()
{
return $this->categories;
}
public function getId()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getName()
{
return $this->name;
}
}
I am using select form element to insert these values in database, When i selected any root category thats work fine , but when i select root or leave blank this can't insert NULL value in "category_tree" table. How can i add NULL value in "category_tree" table?