Relation between entity doctrine. How to references "foreign key"? - postgresql

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.

Related

Trying to insert data ManyToOne FOSRestBundle

I'm trying to creating an API REST with the bundle FOSRestBundle (SF5).
I've an entity "Categorie" which can have an parent "Categorie".
Here is the entity :
<?php
namespace App\Entity\Main;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation\Expose;
use JMS\Serializer\Annotation\ExclusionPolicy;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity(repositoryClass="App\Repository\CategorieRepository")
* #ORM\Table(name="categorie")
* #ExclusionPolicy("all")
*/
class Categorie
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #Expose
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var string
* #Assert\NotBlank()
* #Expose
* #ORM\Column(type="string", length=255)
*/
private $libelle;
/**
* #var string
* #Assert\NotBlank()
* #Expose
* #ORM\Column(type="string", length=255)
*/
private $icone;
/**
* #var Categorie
* #ORM\ManyToOne(targetEntity="App\Entity\Main\Categorie", inversedBy="categories", cascade={"all"}, fetch="EAGER")
* #ORM\JoinColumn(name="categorie_parent_id", referencedColumnName="id", nullable=true)
*/
private $categorieParent;
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="App\Entity\Main\Categorie", mappedBy="categorieParent")
*/
private $categories;
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="App\Entity\Main\Produit", mappedBy="categorie")
*/
private $produits;
public function __construct()
{
$this->produits = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getLibelle(): ?string
{
return $this->libelle;
}
public function setLibelle(string $libelle): self
{
$this->libelle = $libelle;
return $this;
}
public function getIcone(): ?string
{
return $this->icone;
}
public function setIcone(string $icone): self
{
$this->icone = $icone;
return $this;
}
public function setCategorieParent(Categorie $categorieParent): self
{
$this->categorieParent = $categorieParent;
return $this;
}
public function getCategorieParent(Categorie $categorieParent)
{
return $this->categorieParent;
}
}
Here is my action in controller :
/**
* #Rest\View(statusCode=Response::HTTP_CREATED)
* #Rest\Post("/api/{_locale}/categorie/create", name="api_categorie_create")
* #ParamConverter("categorie", converter="fos_rest.request_body")
* #IsGranted("ROLE_SUPER_ADMIN")
* #return Categorie|View
*/
public function create(Categorie $categorie, ConstraintViolationList $violations)
{
if (count($violations)) {
return $this->view($violations, Response::HTTP_BAD_REQUEST);
}
$em = $this->getDoctrine()->getManager('main');
$em->persist($categorie);
$em->flush();
return $categorie;
}
When I use postman to insert data with this content :
{
"libelle":"Blonde",
"icone":"blonde.png",
"categorieParent.id": 1
}
"libelle" and "icone" are inserted but "categorieParent" wasn't set.
I've try :
{
"libelle":"Blonde",
"icone":"blonde.png",
"categorieParent": 1
}
{
"libelle":"Blonde",
"icone":"blonde.png",
"categorieParent": {
"id": 1
}
}
For each try, I set id with number and string.
And anything doesn't work.
Thx for help :) !
CategorieParent will only accept a Categorie entity; libelle and icone work because they are simple strings. You should use the passed integer to fetch the Entity, then save the values.

hydrate multiple objects zf2

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.

Duplicate definition of column 'urbanization' on entity

I'm working with FOSUserBundle and I need to build Users Profile. This is what I did:
Create the User class and extends from BaseUser as FOSUser docs said
namespace Sunahip\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToOne(targetEntity="Profile", mappedBy="user")
*/
protected $profile;
/**
* #ORM\ManyToMany(targetEntity="Sunahip\UserBundle\Entity\Group")
* #ORM\JoinTable(name="fos_user_user_group",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
}
Create a Profile entity
namespace Sunahip\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
/**
* #ORM\Entity
* #ORM\Table(name="profile")
*/
class Profile extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Id
* #ORM\OneToOne(targetEntity="User", inversedBy="profile")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
/**
* #ORM\Column(name="register_type", type="smallint", length=1)
*/
protected $register_type;
/**
* #ORM\Column(name="rif", type="string", length=25)
*/
protected $rif;
/**
* #ORM\Column(name="ci", type="string", length=25)
*/
protected $ci;
/**
* #ORM\Column(name="firstname", type="string", length=25)
*/
protected $firstname;
/**
* #ORM\Column(name="lastname", type="string", length=25)
*/
protected $lastname;
/**
* #ORM\Column(name="state", type="string", length=150)
*/
protected $state;
/**
* #ORM\Column(name="city", type="string", length=150)
*/
protected $city;
/**
* #ORM\Column(name="town", type="string", length=150)
*/
protected $town;
/**
* #ORM\Column(name="urbanization", type="string", length=150)
*/
protected $urbanization;
/**
* #ORM\Column(name="urbanization", type="string", length=150)
*/
protected $street;
/**
* #ORM\Column(name="aparment", type="string", length=150)
*/
protected $aparment;
/**
* #ORM\Column(name="aparment_no", type="string", length=150)
*/
protected $aparment_no;
/**
* #ORM\Column(name="reference", type="string", length=250)
*/
protected $reference;
/**
* #ORM\Column(name="zipcode", type="string", length=250)
*/
protected $zipcode;
/**
* #ORM\Column(name="fax", type="string", length=250)
*/
protected $fax;
/**
* #ORM\Column(name="local_phone", type="string", length=250)
*/
protected $local_phone;
/**
* #ORM\Column(name="movil_phone", type="string", length=250)
*/
protected $movil_phone;
/**
* #ORM\Column(name="alt_email", type="string", length=250)
*/
protected $alt_email;
/**
* #ORM\Column(name="alt_email", type="string", length=250)
*/
protected $website;
public function getId()
{
return $this->id;
}
public function setUser(User $user)
{
$this->user = $user;
}
public function getUser()
{
return $this->user;
}
public function setRegisterType($register_type)
{
$this->register_type = $register_type;
}
public function getRegisterType()
{
return $this->register_type;
}
public function setRif($rif)
{
$this->rif = $rif;
}
public function getRif()
{
return $this->rif;
}
public function setCI($ci)
{
$this->ci = $ci;
}
public function getCI()
{
return $this->ci;
}
public function setFirstname($firstname)
{
$this->firstname = $firstname;
}
public function getFirstname()
{
return $this->firstname;
}
public function setLastname($lastname)
{
$this->lastname = $lastname;
}
public function getLastname()
{
return $this->lastname;
}
public function setState($state)
{
$this->state = $state;
}
public function getState()
{
return $this->state;
}
public function setCity($city)
{
$this->city = $city;
}
public function getCity()
{
return $this->city;
}
public function setTown($town)
{
$this->town = $town;
}
public function getTown()
{
return $this->town;
}
public function setUrbanization($urbanization)
{
$this->urbanization = $urbanization;
}
public function getUrbanization()
{
return $this->urbanization;
}
public function setStreet($street)
{
$this->street = $street;
}
public function getStreet()
{
return $this->street;
}
public function setAparment($aparment)
{
$this->aparment = $aparment;
}
public function getAparment()
{
return $this->aparment;
}
public function setAparmentNo($aparment_no)
{
$this->aparment_no = $aparment_no;
}
public function getAparmentNo()
{
return $this->aparment_no;
}
public function setReference($reference)
{
$this->reference = $reference;
}
public function getReference()
{
return $this->reference;
}
public function setZipcode($zipcode)
{
$this->zipcode = $zipcode;
}
public function getZipcode()
{
return $this->zipcode;
}
public function setFax($fax)
{
$this->fax = $fax;
}
public function getFax()
{
return $this->fax;
}
public function setLocalPhone($local_phone)
{
$this->local_phone = $local_phone;
}
public function getLocalPhone()
{
return $this->local_phone;
}
public function setMovilPhone($movil_phone)
{
$this->movil_phone = $movil_phone;
}
public function getMovilPhone()
{
return $this->movil_phone;
}
public function setAltEmail($alt_email)
{
$this->alt_email = $alt_email;
}
public function getAltEmail()
{
return $this->alt_email;
}
public function setWebsite($website)
{
$this->website = $website;
}
public function getWebsite()
{
return $this->website;
}
}
Now, I'm trying to validate that entities by running the command doctrine:schema:validate and I get this error:
[Doctrine\ORM\Mapping\MappingException] Duplicate definition of
column 'urbanization' on entity 'Sunahip\UserBundle\Entity\Profile' in
a field or discriminator column mapping.
My questions:
I don't know what is wrong and also don't know what the error means is the first time I got this error.
I don't know if I'm building users profiles in the right way I mean if I should extends from BaseUser or from User
Can I give some help here? Advices? Ideas?
You have (had) basically two probles here:
Duplicated urbanization column name somewhere there which needs to be removed. Only one column with the same name is allowed
Duplicated #ORM\Id annotation in your Profile entity. Remove one from $user because it is not your Id

How to integrate i18n doctrine translation into zend framework?

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;
}
}

Confused using DQL with Doctrine2 entities and Zend framework

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');
}