I have 4 entities : Country, Region, Province, Town.
<?php
namespace Entities;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity (repositoryClass="Repositories\Region")
* #Table(name="regions")
* #HasLifecycleCallbacks
*/
class Region {
/**
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
private $id;
/** #Column(type="string", length=30,unique=TRUE) */
private $regionname;
/** #Column(type="boolean") */
private $active;
/**
* #ManyToOne(targetEntity="Country", inversedBy="regions")
* #JoinColumn(name="countries_id", referencedColumnName="id",nullable=FALSE)
*/
private $countries_id;
/**
* #OneToMany(targetEntity="Province", mappedBy="provinces")
*/
private $provinces;
public function __construct() {
$this->provinces = new ArrayCollection();
$this->active = true;
}
<?php
namespace Entities;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity (repositoryClass="Repositories\Province")
* #Table(name="provinces")
* #HasLifecycleCallbacks
*/
class Province {
/**
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
private $id;
/** #Column(type="string", length=30,unique=TRUE) */
private $provincename;
/** #Column(type="boolean") */
private $active;
/**
* #ManyToOne(targetEntity="Region", inversedBy="provinces")
* #JoinColumn(name="regions_id", referencedColumnName="id",nullable=FALSE)
*/
private $regions_id;
/**
* #OneToMany(targetEntity="Town", mappedBy="towns")
*/
private $towns;
public function __construct() {
$this->towns = new ArrayCollection();
$this->active = true;
}
<?php
namespace Entities;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #Entity (repositoryClass="Repositories\Town")
* #Table(name="towns")
* #HasLifecycleCallbacks
*/
class Town {
/**
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
private $id;
/** #Column(type="string", length=30,unique=FALSE) */
private $townname;
/** #Column(type="boolean") */
private $active;
// so that we know when a user has added a town
/** #Column(type="boolean") */
private $verified;
/**
* #OneToMany(targetEntity="User", mappedBy="users")
*/
private $users;
/**
* #ManyToOne(targetEntity="Province", inversedBy="towns")
* #JoinColumn(name="provinces_id", referencedColumnName="id",nullable=FALSE)
*/
private $provinces_id;
public function __construct() {
$this->users = new ArrayCollection();
$this->active = true;
}
I want to create a query using DQL that will give me a list of towns for a given region.
To get a simple list of active towns I am using :
public function findActiveTowns($provinces_id = null)
// we can pass in a specific provinces_id if we want
{
$qb = $this->_em->createQueryBuilder();
$qb->select('a.townname, a.id')
->from('Entities\Town', 'a');
if (!is_null($provinces_id)){
$qb->where('a.provinces_id = :provinces_id AND a.active = TRUE')
->setParameter('provinces_id', $provinces_id);
} else {
$qb->where('a.active = TRUE');
}
$towns=$qb->getQuery()->getResult();
// make pairs array suitable for select lists
$options = array();
foreach ($towns as $key => $value) {
$options[$value['id']] = $value['townname'];
}
return $options;
}
Now, to get to the point. How do I set up the joins and get this working so that we can pass in a region_id and return all of the towns in the region.
In native SQL I'd do something like this :
SELECT towns.id
FROM `towns`
INNER JOIN `provinces`
INNER JOIN `regions`
WHERE regions.id =1
Thanks.
A few things first.
Don't name your fields with _id, because they are not identifiers, but relations to other objects. Join column annotation goes with the real DB name, field in object model go without.
Write/generate get/set/add methods for all fields to encapsulate them, so u can actually use them. You can't read private fields from "the outside".
As for you question, haven't tested it, but something like this should work.
class Town {
/**
* #ManyToOne(targetEntity="Province", inversedBy="towns")
* #JoinColumn(name="provinces_id", referencedColumnName="id",nullable=FALSE)
*/
private $province;
class Province {
/**
* #ManyToOne(targetEntity="Region", inversedBy="provinces")
* #JoinColumn(name="regions_id", referencedColumnName="id",nullable=FALSE)
*/
private $region;
$qb->select('a.townname, a.id')
->from('Entities\Town', 'a')
->leftJoin('a.province', 'p');
if (!is_null($provinces_id) && !is_null($region_id)){
$qb->where('a.province = :province AND a.active = TRUE')
->andWhere('p.region = :region')
->setParameter('province', $provinces_id)
->setParameter('region', $region_id);
} else {
$qb->where('a.active = TRUE');
}
Related
I'm currently working with Symfony and Doctrine and I'm having a little bit of trouble to reference two entity.
I have a entity called cinema and another one called theater. It's a relation of OneToMany, where one cinema can have many theater.
I create a cinema_id into theater so I can relate cinema and theater.
I have create a controller to consume data from an API and store the data into a Postgres database. Here is the controller:
TheaterController
namespace App\Controller;
use GuzzleHttp\Client;
use App\Entity\Cinema;
use App\Entity\Theater;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
class TheaterController extends AbstractController
{
/**
* #Route("/theater", name="theater")
*/
public function Theater(Request $request)
{
$client = new Client();
$res = $client->request('GET','api-content');
$arrayContent = json_decode($res->getBody());
foreach ($arrayContent as $value)
{
$entityManager = $this->getDoctrine()->getManager();
$theater_cinema_id = $entityManager->getReference(Cinema::Cinema, $id);
$theater->addId($theater_cinema_id);
$theater_booking_cinema = 'value';
$theater_booking_id = $value->id;
$theater = new theater();
$theater->setId($theater_cinema_id);
$theater->setBookingCinema($theater_booking_cinema);
$theater->setBookingId($theater_booking_id);
//echo $theater;
$entityManager->persist($theater);
$entityManager->flush();
}
}
}
My problem here is, how can I reference the id from cinema to the cinema_id from theater? What am I doing wrong?
The two entities are:
Cinema
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\CinemaRepository")
*/
class Cinema
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="integer")
*/
private $is_active;
/**
* #ORM\Column(type="datetime")
*/
private $created_at;
/**
* #ORM\Column(type="datetime")
*/
private $updated_at;
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getIsActive(): ?int
{
return $this->is_active;
}
public function setIsActive(int $is_active): self
{
$this->is_active = $is_active;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->created_at;
}
public function setCreatedAt(\DateTimeInterface $created_at): self
{
$this->created_at = $created_at;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updated_at;
}
public function setUpdatedAt(\DateTimeInterface $updated_at): self
{
$this->updated_at = $updated_at;
return $this;
}
}
Theater
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\TheaterRepository")
*/
class Theater
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Cinema")
* #ORM\JoinColumn(nullable=false)
*/
private $cinema;
/**
* #ORM\Column(type="string", length=255)
*/
private $booking_cinema;
/**
* #ORM\Column(type="integer")
*/
private $booking_id;
public function getId(): ?int
{
return $this->id;
}
public function getCinema(): ?cinema
{
return $this->cinema;
}
public function setCinema(?cinema $cinema): self
{
$this->cinema = $cinema;
return $this;
}
public function getBookingCinema(): ?string
{
return $this->booking_cinema;
}
public function setBookingCinema(string $booking_cinema): self
{
$this->booking_cinema = $booking_cinema;
return $this;
}
public function getBookingId(): ?int
{
return $this->booking_id;
}
public function setBookingId(int $booking_id): self
{
$this->booking_id = $booking_id;
return $this;
}
}
As I understood, you have many cinemas in one theater. So, you have add the following code to your Theater entity:
// ...
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
// ...
/**
* #var ArrayCollection $cinemas
* #ORM\OneToMany(targetEntity="App\Entity\Theater", mappedBy="theater")
*/
public $cinemas;
// ...
/**
* Theater constructor.
*/
public function __construct()
{
$this->cinemas = new ArrayCollection();
}
// ...
/**
* #return array
*/
public function getCinemas(): array
{
return $this->cinemas->toArray()
}
/**
* #return Theater
*/
public function addCinema(Cinema $cinema): self
{
$this->cinemas->add($cinema);
return $this;
}
// ...
And the following code to your Cinema entity:
// ...
use Doctrine\ORM\Mapping as ORM;
// ...
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Theater", inversedBy="cinemas")
* #ORM\JoinColumn(name="theater_id", referencedColumnName="id", nullable=FALSE)
*/
private $theater;
// ...
Then you can access to your cinemas entities from Theater entity:
$theaterRepository = $this->getDoctrine()->getManager()->getRepository(Theater::class);
$theater = $theaterRepository->findBy(['id' => 1]);
$cinemas = $theater->getCinemas(); // array
/** #var Cinema $cinema */
foreach($cinemas as $cinema) {
// ...
}
Or add new Cinema to your Theater:
$theaterRepository = $this->getDoctrine()->getManager()->getRepository(Theater::class);
$theater = $theaterRepository->findBy(['id' => 1]);
$cinema = new Cinema();
// ...
$theater->addCinema($cinema)
// Persist, flush, e.t.c
About the ArrayCollection you can read here
And you can access to your Theater entity from any Cinema entity:
$cinemaRepository = $this->getDoctrine()->getManager()->getRepository(Cinema::class);
$cinema = $cinemaRepository->findBy(['id' => 1]);
$theater = $cinema->getTheater(); // Theater object
Or add the Theater to your Cinema:
$cinema = new Cinema();
$theater = new Theater();
// ...
$cinema->setTheater($theater);
// ...
// Persist, flush, e.t.c
Doctrine is an ORM, which means you don't have to think about tables, but entities. You don't think about foreign keys, but relations between entities.
Your API is giving you the cinema ID, or you can access it another way? You can retrieve the cinema using this :
$cinema = $entityManager->getRepository('App:Cinema')->findOneById($cinema_id);
You want to tell what cinema the theater belongs to? Use this :
$theater->setCinema($cinema);
Doctrine will itself build and execute the queries to get the desired datas.
I need to hyrdate multiple objests in one form. Here is what I use:
Product Form - I have a form where I call three fieldsets
Product Fieldset
Promotion Fieldset
Category Fieldset
I have Models for all the necessary tables, here is an example for the product model:
class Product implements ProductInterface
{
/**
* #var int
*/
protected $Id;
/**
* #var string
*/
protected $Title;
/**
* #var float
*/
protected $Price;
/**
* #var string
*/
protected $Description;
/**
* #var string
*/
protected $Url;
/**
* #var \DateTime
*/
protected $DateAdded;
/**
* #var string
*/
protected $Image;
/**
* #var int
*/
protected $Status;
/**
* #return int
*/
public function getId()
{
return $this->Id;
}
/**
* #param int $Id
*/
public function setId($Id)
{
$this->Id = $Id;
}
/**
* #return string
*/
public function getTitle()
{
return $this->Title;
}
/**
* #param string $Title
*/
public function setTitle($Title)
{
$this->Title = $Title;
}
/**
* #return float
*/
public function getPrice()
{
return $this->Price;
}
/**
* #param float $Price
*/
public function setPrice($Price)
{
$this->Price = $Price;
}
/**
* #return string
*/
public function getDescription()
{
return $this->Description;
}
/**
* #param string $Description
*/
public function setDescription($Description)
{
$this->Description = $Description;
}
/**
* #return string
*/
public function getUrl()
{
return $this->Url;
}
/**
* #param string $Url
*/
public function setUrl($Url)
{
$this->Url = $Url;
}
/**
* #return \DateTime
*/
public function getDateAdded()
{
return $this->DateAdded;
}
/**
* #param \DateTime $DateAdded
*/
public function setDateAdded($DateAdded)
{
$this->DateAdded = $DateAdded;
}
/**
* #return string
*/
public function getImage()
{
return $this->Image;
}
/**
* #param string $Image
*/
public function setImage($Image)
{
$this->Image = $Image;
}
/**
* #return int
*/
public function getStatus()
{
return $this->Status;
}
/**
* #param int $Status
*/
public function setStatus($Status)
{
$this->Status = $Status;
}
In my controllers I want to bind the data to my view so I can edit them.
try {
$aProduct = $this->productService->findProduct($iId);
} catch (\Exception $ex) {
// ...
}
$form = new ProductForm();
$form->bind($aProduct);
In the first place I need to select all the necessary information from the DB. I join three tables product, promotion and category tables. I must return the data to my controller as objects and bind them in my form to be able to edit on the view page.
Please give me some ideas how to accomplish this so I can continue with my development. I am stuck.
I will appreciate all the links which can help me or give me any ideas/examples from the real life.
public function findProduct($Id)
{
$iId = (int) $Id;
$sql = new Sql($this->dbAdapter);
$select = $sql->select('product');
$select->join('promotion', 'promotion.ProductId = product.Id', array('Discount', 'StartDate', 'EndDate', 'PromotionDescription' => 'Description', 'PromotionStatus', 'Type'), 'left');
$select->join('producttocategory', 'producttocategory.ProductId = product.Id', array('CategoryId'), 'left');
$select->join('category', 'category.Id = producttocategory.CategoryId', array('ParentId', 'Title', 'Description', 'Url', 'DateAdded', 'Image', 'Status'), 'left');
$where = new Where();
$where->equalTo('product.Id', $iId);
$select->where($where);
$stmt = $sql->prepareStatementForSqlObject($select);
$result = $stmt->execute();
if ($result instanceof ResultInterface && $result->isQueryResult()) {
$resultSet = new HydratingResultSet($this->hydrator, $this->productPrototype);
return $resultSet->initialize($result);
}
throw new \Exception("Could not find row $Id");
}
I need to hydrate the result and return an object which I will use in the controller to bind the form.
You can to fill entities from a database manually.
If you want to fill automatically need to create a map between a database and entities. I made a library for making a map between DB and entities use annotations in entities https://github.com/newage/annotations.
Next step.
When you get different data from tables. Example:
SELECT
table1.id AS table1.id,
table1.title AS table1.title,
table2.id AS table2.id,
table2.alias AS table2.alias
FROM table1
JOIN table2 ON table1.id = table2.id
Need do foreach by rows and set data to entities comparing row with table name and Entity from a generated map.
Auto generating tree of entities from DB is my next project.
But it's do not finished. https://github.com/newage/zf2-simple-orm.
I have a rather strange problem. I'm using Doctrine 2 under Zend Framework 1.11. I have a database called "Sessions", which are training sessions for students. Each session has an associated note, called a SOAPE note. Edit: I am now including both of the entities in question.
Sessions:
use Doctrine\ORM\Mapping as ORM;
/**
* #Entity(repositoryClass="Repositories\Sessions")
* #Table(name="Sessions")
*/
class Sessions
{
/**
* #var integer Id
*
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var integer $schId
*
* #Column(name="schId", type="integer", nullable=false)
*/
protected $schId;
/**
* #var integer $stdId
*
* #Column(name="stdId", type="integer", nullable=false)
*/
protected $stdId;
/**
* #var integer $trainerPsnId
*
* #Column(name="trainerPsnId", type="integer", nullable=false)
*/
protected $trainerPsnId;
/**
* #var boolean $isLegacy
*
* #Column(name="isLegacy", type="boolean", nullable=false)
*/
protected $isLegacy;
/**
* #var float $charge
*
* #Column(name="charge", type="float", nullable=false)
*/
protected $charge;
/**
* #var float $trainerPay
*
* #Column(name="trainerPay", type="float", nullable=false)
*/
protected $trainerPay;
/**
* #var integer $modeId
*
* #Column(name="modeId", type="integer", nullable=false)
*/
protected $modeId;
/**
* #var text $notes
*
* #Column(name="notes", type="text", nullable=true)
*/
protected $notes;
/**
* #var string $twitterNote
*
* #Column(name="twitterNote", type="string", length=20, nullable=true)
*/
protected $twitterNote;
// ASSOCIATIONS
/**
* #OneToOne(targetEntity="Schedule", inversedBy="session")
* #JoinColumn(name="schId", referencedColumnName="id")
*/
protected $schedule;
/**
* #OneToOne(targetEntity="SnSoapeNotes", mappedBy="session")
* #JoinColumn(name="id", referencedColumnName="snId")
*/
protected $soapeNote;
/**
* #ManyToOne(targetEntity="Students")
* #JoinColumn(name="stdId", referencedColumnName="id")
*/
protected $student;
/**
* #ManyToOne(targetEntity="Personnel", inversedBy="sessions")
* #JoinColumn(name="trainerPsnId", referencedColumnName="id")
*/
protected $trainer;
// Getters and Setters
public function getId()
{
return $this->id;
}
public function getSchId()
{
return $this->schId;
}
public function setSchId($schId)
{
$this->schId = $schId;
}
public function getStdId()
{
return $this->stdId;
}
public function setStdId($stdId)
{
$this->stdId = $stdId;
}
public function getTrainerPsnId()
{
return $this->trainerPsnId;
}
public function setTrainerPsnId($trainerPsnId)
{
$this->stdId = $trainerPsnId;
}
public function getIsLegacy()
{
return $this->isLegacy;
}
public function setIsLegacy($isLegacy)
{
$this->isLegacy = $isLegacy;
}
public function getCharge()
{
return $this->charge;
}
public function setCharge($charge)
{
$this->charge = $charge;
}
public function getTrainerPay()
{
return $this->trainerPay;
}
public function setTrainerPay($trainerPay)
{
$this->trainerPay = $trainerPay;
}
public function getModeId()
{
return $this->modeId;
}
public function setModeId($modeId)
{
$this->modeId = $modeId;
}
public function getNotes()
{
return $this->notes;
}
public function setNotes($notes)
{
$this->notes = $notes;
}
public function getTwitterNote()
{
return $this->twitterNote;
}
public function setTwitterNote($twitterNote)
{
$this->twitterNote = $twitterNote;
}
// Foreign Data
public function getSchedule()
{
return $this->schedule;
}
public function getStudent()
{
return $this->student;
}
public function getTrainer()
{
return $this->trainer;
}
public function getSoapeNote()
{
return $this->soapeNote;
}
}
SnSoapeNotes:
namespace Entities;
use Doctrine\Mapping as ORM;
/**
* SnSoapeNotes
*
* #Table(name="SnSoapeNotes")
* #Entity(repositoryClass="Repositories\SnSoapeNotes")
*/
class SnSoapeNotes
{
/**
* #var integer Id
*
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var integer $mental
*
* #Column(name="mental", type="integer", nullable=false)
*/
private $mental;
/**
* #var integer $physical
*
* #Column(name="physical", type="integer", nullable=false)
*/
private $physical;
/**
* #var text $subjective
*
* #Column(name="subjective", type="text", nullable=false)
*/
private $subjective;
/**
* #var text $objective
*
* #Column(name="objective", type="text", nullable=false)
*/
private $objective;
/**
* #var text $plan
*
* #Column(name="plan", type="text", nullable=false)
*/
private $plan;
/**
* #var text $action
*
* #Column(name="action", type="text", nullable=false)
*/
private $action;
/**
* #var text $education
*
* #Column(name="education", type="text", nullable=false)
*/
private $education;
/**
* #var text $warning
*
* #Column(name="warning", type="text", nullable=true)
*/
private $warning;
/**
* #var text $incident
*
* #Column(name="incident", type="text", nullable=true)
*/
private $incident;
/**
* #var text $technical
*
* #Column(name="technical", type="text", nullable=true)
*/
private $technical;
// ASSOCIATIONS
/**
* #Var Sessions $sessions
*
* #Column(name="snId", type="integer", nullable=false)
* #OneToOne(targetEntity="Sessions", inversedBy="soapeNote")
* #JoinColumn(name="snId", referencedColumnName="id")
*/
protected $sessions;
// Getters and Setters
public function getSnId()
{
return $this->snId;
}
public function setSnId($snId)
{
$this->snId = $snId;
}
public function getMental()
{
return $this->mental;
}
public function setMental($mental)
{
$this->mental = $mental;
}
public function getPhysical()
{
return $this->physical;
}
public function setPhysical($physical)
{
$this->physical = $physical;
}
public function getSubjective()
{
return $this->subjective;
}
public function setSubjective($subjective)
{
$this->subjective = $subjective;
}
public function getObjective()
{
return $this->objective;
}
public function setObjective($objective)
{
$this->objective = $objective;
}
public function getPlan()
{
return $this->plan;
}
public function setPlan($plan)
{
$this->plan = $plan;
}
public function getAction()
{
return $this->action;
}
public function setAction($action)
{
$this->action = $action;
}
public function getEducation()
{
return $this->education;
}
public function setEducation($education)
{
$this->education = $education;
}
public function getWarning()
{
return $this->warning;
}
public function setWarning($warning)
{
$this->warning = $warning;
}
public function getIncident()
{
return $this->incident;
}
public function setIncident($incident)
{
$this->incident = $incident;
}
public function getTechnical()
{
return $this->technical;
}
public function setTechnical($technical)
{
$this->technical = $technical;
}
public function getSession()
{
return $this->session;
}
// A quick way to make sure the soape note has been completed.
// Note that objective is left out here because it can be
// filled out beforehand
public function getIsComplete()
{
return !empty($this->subjective)
&& !empty($this->action)
&& !empty($this->plan)
&& !empty($this->education);
}
}
When calling $em->getRepository('Entities\Sessions')->findOneBy('id'), everything works fine--I get the session and its accompanying SOAPE note. Ditto for other associated tables' data.
But now I am trying to write a custom repository to get the notes prior to this session. The function is as follows:
<?php
namespace Repositories;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\DBAL\Types\Type;
/**
* Sessions
*/
class Sessions extends EntityRepository
{
public function getPastSoapeNotes($params) {
$studentId = $params['studentId'];
$latestSession = $params['snDatetime'] ?: date('Y-m-d H:i');
$qb = $this->_em->createQueryBuilder();
$qb->select('n.subjective, n.objective, n.plan, n.action, n.education')
->from('Entities\Sessions', 'sn')
->innerJoin('sn.Entities\SnSoapeNotes', 'n');
return $qb->getQuery()->getResult();
}
}
When I call this, I get the following error:
[Semantical Error] line 0, col 126 near 'n': Error: Class Entities\Sessions has no association named Entities\SnSoapeNotes
I have also tried using the "mappedBy" and "inersedBy" annotations in every possible combination, but to no avail; Doctrine can't seem to find the association. I am at a complete loss as to what is going on.
I figured out what I did wrong. In the join statement, I used 'sn.Entities\SnSoapeNotes' when I should have used just 'soapeNote', which is the property in the Sessions class, not the table name itself.
Say I have an simple entity UserType. I would like usertype to be available in various languages because it will appear in drop-downs in the UI. How should I set i18n up to work in my project? It was not clear in the docs.
<?php
namespace Entities;
/**
* #Entity (repositoryClass="Repositories\UserType")
* #Table(name="usertypes")
* #HasLifecycleCallbacks
*/
class UserType {
/**
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
private $id;
/** #Column(type="string", length=30,unique=TRUE) */
private $usertype;
/** #Column(type="boolean") */
private $active;
public function __construct() {
$this->active = true;
}
/**
* #return the $id
*/
public function getId() {
return $this->id;
}
/**
* #return the $usertype
*/
public function getUserType() {
return $this->usertype;
}
/**
* #return the $active
*/
public function getActive() {
return $this->active;
}
/**
* #param field_type $usertype
*/
public function setUsertype($usertype) {
$this->usertype = $usertype;
}
/**
* #param field_type $active
*/
public function setActive($active) {
$this->active = $active;
}
}
You simply add "#gedmo:Translatable" in your comment block for translable fields
<?php
namespace Entities;
/**
* #Entity (repositoryClass="Repositories\UserType")
* #Table(name="usertypes")
* #HasLifecycleCallbacks
*/
class UserType {
/**
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #gedmo:Translatable
* #Column(type="string", length=30,unique=TRUE)
*/
private $usertype;
/** #Column(type="boolean") */
private $active;
/**
* #gedmo:Locale
*/
private $locale;
public function __construct() {
$this->active = true;
}
/**
* #return the $id
*/
public function getId() {
return $this->id;
}
/**
* #return the $usertype
*/
public function getUserType() {
return $this->usertype;
}
/**
* #return the $active
*/
public function getActive() {
return $this->active;
}
/**
* #param field_type $usertype
*/
public function setUsertype($usertype) {
$this->usertype = $usertype;
}
/**
* #param field_type $active
*/
public function setActive($active) {
$this->active = $active;
}
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
}
I am starting my first Zend Framework + Doctrine 2 project and I have a question. I use PostgreSQL 9 and Apache 2.2
I have the following entities (the names of the entities and attributes are just for this example):
<?php
namespace Xproject\Entities;
/**
* Entity1
* #Table()
* #Entity
*/
class Entity1
{
/***
* #var integer $ent1Code
* #Column(name="ent1Code", type="integer", length=4)
* #Id
* #GeneratedValue(strategy="IDENTITY")
*/
private $ent1Code;
/**
* #var decimal $att1
* #Column(name="att1", type="decimal")
*/
private $att1;
/**
* OWNING SIDE
* #var \Doctrine\Common\Collections\ArrayCollection
* #ManyToOne(targetEntity="Entity2", inversedBy="entity1")
* #JoinColumn(name="ent2Code", referencedColumnName="ent2Code")
*/
private $entity2;
/**
* UNIDIRECTIONAL
* #var \Doctrine\Common\Collections\ArrayCollection
* #ManyToOne(targetEntity="Entity3")
* #JoinColumn(name="ent3Code", referencedColumnName="ent3Code")
*/
private $entity3;
/**
* UNIDIRECTIONAL
* #var \Doctrine\Common\Collections\ArrayCollection
* #ManyToOne(targetEntity="Entity4")
* #JoinColumn(name="ent4Code", referencedColumnName="ent4Code")
*/
private $entity4;
public function __construct() {
$this->entity2 = new \Doctrine\Common\Collections\ArrayCollection();
$this->entity3 = new \Doctrine\Common\Collections\ArrayCollection();
$this->entity4 = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getEnt1Code(){
return $this->ent1Code;
}
public function getAtt1(){
return $this->att1;
}
public function setAtt1($value){
$this->att1=$value;
}
public function addEntity2(Entity2 $value){
$value->addEntity1($this);
$this->entity2->add($value);
}
public function addEntity3(Entity3 $value){
$this->entity3->add($value);
}
public function addEntity4(Entity4 $value){
$this->entity4->add($value);
}
}
<?php
namespace Xproject\Entities;
/**
* Entity2
* #Table()
* #Entity
*/
class Entity2
{
/**
* #var integer $ent2Code
* #Column(name="ent2Code", type="integer", length=4)
* #Id
* #GeneratedValue(strategy="IDENTITY")
*/
private $ent2Code;
/**
* INVERSE SIDE
* #var entity1
* #OneToMany(targetEntity="Entity1", mappedBy="entity2")
*/
private $entity1;
public function __construct() {
$this->entity1 = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getEnt2Code(){
return $this->ent2Code;
}
public function addEntity1(Entity1 $value){
$this->entity1->add($value);
}
}
<?php
namespace Xproject\Entities;
/**
* Entity3
* #Table()
* #Entity
*/
class Entity3
{
/**
* #var integer $ent3Code
* #Column(name="ent3Code", type="integer", length=4)
* #Id
* #GeneratedValue(strategy="IDENTITY")
*/
private $ent3Code;
/**
* #var string $att1
* #Column(name="att1", type="string", length=150)
*/
private $att1;
public function getEnt3Code(){
return $this->ent3Code;
}
public function getAtt1(){
return $this->att1;
}
public function setAtt1($value){
$this->att1=$value;
}
}
<?php
namespace Xproject\Entities;
/**
* Entity4
* #Table()
* #Entity
*/
class Entity4
{
/**
* #var integer $ent4Code
* #Column(name="ent4Code", type="integer", length=4)
* #Id
* #GeneratedValue(strategy="IDENTITY")
*/
private $ent4Code;
/**
* #var string $att1
* #Column(name="att1", type="string", length=150)
*/
private $att1;
public function getEnt4Code(){
return $this->ent4Code;
}
public function getAtt1(){
return $this->att1;
}
public function setAtt1($value){
$this->att1=$value;
}
}
Just to try if everything is working I use the following code in Xproject's indexController:
<?php
class IndexController extends Zend_Controller_Action
{
public function init()
{
$this->doctrine = Zend_Registry::get('doctrine');
$this->em = $this->doctrine->getEntityManager();
}
public function indexAction()
{
$ent2 = new Xproject\Entities\Entity2();
$this->em->persist($ent2);
$ent3 = new Xproject\Entities\Entity3();
$ent3->setAtt1('xyz');
$this->em->persist($ent3);
$ent4= new Xproject\Entities\Entity4();
$ent4->setAtt1('abc');
$this->em->persist($ent4);
//1st flush
$this->em->flush();
$ent1= new Xproject\Entities\Entity1();
$ent1->setAtt1(350.00);
$ent1->addEntity2(ent2);
$ent1->addEntity3(ent3);
$ent1->addEntity4(ent4);
$this->em->persist($ent1);
//2nd flush
//$this->em->flush();
}
}
The first flush works OK and everything is saved OK into the database, but if I use both the first and the second flush, the browser indicates an Application Error and $ent1 is not saved at all into the database.
Using a var_dump($ent1) I can see that the object $ent1 state is correct (att1 and all the collections are loaded OK).
Apache error log doesn't show any error or warning during the loading of this script.
I definitely think I am missing some important thing here related to the ArrayCollections and how they work when you flush them.
Am I missing something crucial?
Your relationships are all ManyToOne, so there should be no ArrayCollections involved.
Since there are no collections, you don't want to add stuff, you want to set stuff:
In Entity1:
public function setEntity2(Entity2 $entity2){
$this->entity2 = $entity2
return $this;
}
In your controller:
$entity1->setEntity2($entity2);
And that's it. Your calls like $this->entity2->add() are working, because you're initializing those properties as ArrayCollections. But doctrine is just ignoring them.
In other words, for a *ToOne relationship, the object properties are just the foreign entity type. Treat them like simple values, and set them via typical set*() mutator.