Foreign key on composite primary key not working - php

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

You should be able to reference multiple columns using the #ORM\JoinColumns annotation. Inside you can define one or more #ORM\JoinColumn annotations.
For example
/**
* #ORM\ManyToOne(targetEntity="Application\Entity\Company", inversedBy="trade")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="symbol", referencedColumnName="symbol"),
* #ORM\JoinColumn(name="exchange", referencedColumnName="exchangeKey")
* });
*/
protected $company;
I was going to link to the documentation, however all I can find is this.
An array of #JoinColumn annotations for a #ManyToOne or #OneToOne relation with an entity that has multiple identifiers.

Related

Symfony 2 Entity Repository find() returns empty array

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

Symfony 3.3 Schema Validation Error

I have two entities as follows:
<?php
// src/coreBundle/Entity/model.php
namespace coreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use coreBundle\Entity\brand;
/**
*#ORM\Entity
*#ORM\Table(name="model")
*/
class model
{
/**
* #ORM\ManyToOne(targetEntity="coreBundle\Entity\brand", inversedBy="models")
* #ORM\JoinColumn(name="brand_id", referencedColumnName="id")
*/
private $brands;
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
*#ORM\Column(type="integer")
*/
public $brand_id;
/**
*#ORM\Column(type="string", length=100)
*/
private $name;
/**
*#ORM\Column(type="string", length=100)
*/
private $image_url;
/**
*#ORM\Column(type="string", length=200)
*/
private $comment;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set brandId
*
* #param integer $brandId
*
* #return model
*/
public function setBrandId($brandId)
{
$this->brand_id = $brandId;
return $this;
}
/**
* Get brandId
*
* #return integer
*/
public function getBrandId()
{
return $this->brand_id;
}
/**
* Set name
*
* #param string $name
*
* #return model
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set imageUrl
*
* #param string $imageUrl
*
* #return model
*/
public function setImageUrl($imageUrl)
{
$this->image_url = $imageUrl;
return $this;
}
/**
* Get imageUrl
*
* #return string
*/
public function getImageUrl()
{
return $this->image_url;
}
/**
* Set comment
*
* #param string $comment
*
* #return model
*/
public function setComment($comment)
{
$this->comment = $comment;
return $this;
}
/**
* Get comment
*
* #return string
*/
public function getComment()
{
return $this->comment;
}
/**
* Set brands
*
* #param \coreBundle\Entity\brand $brands
*
* #return model
*/
public function setBrands(\coreBundle\Entity\brand $brands = null)
{
$this->brands = $brands;
return $this;
}
/**
* Get brands
*
* #return \coreBundle\Entity\brand
*/
public function getBrands()
{
return $this->brands;
}
}
And Second one is as follows:
<?php
// src/coreBundle/Entity/brand.php
namespace coreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use coreBundle\Entity\model;
use Doctrine\Common\Collections\ArrayCollection;
/**
*#ORM\Entity
*#ORM\Table(name="brand")
*/
class brand
{
/**
* ORM\OneToMany(targetEntity="coreBundle\Entity\model", mappedBy="brands")
*/
private $models;
public function __construct()
{
$this->models = new ArrayCollection();
}
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
*#ORM\Column(type="string", length=100)
*/
private $name;
/**
* 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;
}
}
"model" has a ManyToOne relationship with "brand"
I am having issues of schema validation,
*The association coreBundle\Entity\model#brands refers to the inverse side field coreBundle\Entity\brand#models which does not exist
Can you tell what am I doing wrong, Thanks in advance.
In case your still wondering after 3 hours of agony, your missing the # in #ORM\OneToMany (brand.php).

What should be tested (TDD) in simple entities?

I am learning code testing (TDD) and wondering what should be tested for simple entities in Symfony?
From official documentation:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* #ORM\Table(name="category")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
*/
class Category
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
private $products;
/**
* Constructor
*/
public function __construct()
{
$this->products = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add product
*
* #param \AppBundle\Entity\Product $product
*
* #return Category
*/
public function addProduct(\AppBundle\Entity\Product $product)
{
$this->products[] = $product;
return $this;
}
/**
* Remove product
*
* #param \AppBundle\Entity\Product $product
*/
public function removeProduct(\AppBundle\Entity\Product $product)
{
$this->products->removeElement($product);
}
/**
* Get products
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProducts()
{
return $this->products;
}
}
Second:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="product")
*/
class Product
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=100)
*/
private $name;
/**
* #ORM\Column(type="decimal", scale=2)
*/
private $price;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Product
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set price
*
* #param string $price
*
* #return Product
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* #return string
*/
public function getPrice()
{
return $this->price;
}
/**
* 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 category
*
* #param \AppBundle\Entity\Category $category
*
* #return Product
*/
public function setCategory(\AppBundle\Entity\Category $category = null)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* #return \AppBundle\Entity\Category
*/
public function getCategory()
{
return $this->category;
}
}
I thought I had to create an Entity folder and within CategoryTest file:
namespace Tests\AppBundle\Entity;
use AppBundle\Entity\Tag;
use AppBundle\Form\DataTransformer\TagArrayToStringTransformer;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\EntityRepository;
class CategoryTest extends \PHPUnit\Framework\TestCase
{
public function testGetName()
{
$category = new \AppBundle\Entity\Category();
$category->setName('test');
$this->assertSame('test', $category->getName());
}
}
So... In TDD I should testing all fields? For Product entity I should testing name, price and description?
If yes, how to deal with refactoring? In these cases I must use in all methods "$product = new Product();";
For a name field I might need to do another test? What?
Should I also test relationships or do it in functional tests?
It is a good practice to Entities have no (complex) logic inside. In fact it should be just representing your model. And since there is no logic, there is not much to test actually. When you check Symfony Demo app you will find no tests for entities and I believe it is done this way intentionally.
In case your application is not the only one using database I would consider writing functional tests for entities which will ensure you that someone else did not change database structure (for example by dropping column in table) without letting you know. One of possible ways to achieve that is running a simple query on table (entity) you are testing:
public function checkEntityDefinition($entityName)
{ $this->em->getRepository($entityName)
->createQueryBuilder('t')
->setMaxResults(1)
->getQuery()
->getArrayResult();
}
There are no assertion here but this will throw an exception when Entity definition does not match database

Symfony 3 Doctrine Composite Key: single id is not allowed on composite primary key in entity

I have an entity with an
integer column (compositeId)
and a
string column (asin)
I want both columns working as a composite key.
So I look here in the documentation:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html
But when I try to load my repository
$myEntity = $em->getRepository(MyEntity::class);
I got this error message:
single id is not allowed on composite primary key in entity
AppBundle\Entity\MyEntity
This is my Entity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #Entity(repositoryClass="AppBundle\Repository\MyEntityRepository")
* #Table(name="my_entity")
*/
class MyEntity {
/**
* #Column(type="integer")
* #GeneratedValue()
*/
protected $id;
/**
* #var integer
* #Id
* #Column(type="integer", name="composite_id")
*/
protected $compositeId;
/**
* #var string
* #Id
* #Column(type="string", name="asin")
*/
protected $asin;
/**
* #var string
* #Column(type="string", name="sku")
*/
protected $sku;
/**
* #var string
* #Column(type="string", name="ean")
*/
protected $ean;
/**
* #codeCoverageIgnore
* #return mixed
*/
public function getId() {
return $this->id;
}
/**
* #param mixed $id
*
* #return MyEntity;
*/
public function setId($id) {
$this->id = $id;
return $this;
}
/**
* #codeCoverageIgnore
* #return int
*/
public function getCompositeId() {
return $this->compositeId;
}
/**
* #param int $compositeId
*
* #return MyEntity;
*/
public function setCompositeId($compositeId) {
$this->compositeId = $compositeId;
return $this;
}
/**
* #codeCoverageIgnore
* #return string
*/
public function getAsin() {
return $this->asin;
}
/**
* #param string $asin
*
* #return MyEntity;
*/
public function setAsin($asin) {
$this->asin = $asin;
return $this;
}
/**
* #codeCoverageIgnore
* #return string
*/
public function getSku() {
return $this->sku;
}
/**
* #param string $sku
*
* #return MyEntity;
*/
public function setSku($sku) {
$this->sku = $sku;
return $this;
}
/**
* #codeCoverageIgnore
* #return string
*/
public function getEan() {
return $this->ean;
}
/**
* #param string $ean
*
* #return MyEntity;
*/
public function setEan($ean) {
$this->ean = $ean;
return $this;
}
}
What am I doing wrong?
When I remove #generatedValue at my ID table it works.
But I need auto generated values at my ID column.
I don't have any #Id annotation at my ID column, only #generatedValue, and on my both #Id columns I don't have any annotation with #generatedValue but I got this error ...
Doctrine only supports #GeneratedValue() on #Id fields.
This annotation is optional and only has meaning when used in conjunction with #Id.
https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#annref_generatedvalue
You may be able to use columnDefinition as a workaround, e.g.
#ORM\Column(type="integer", name="id", columnDefinition="INT AUTO_INCREMENT")
as suggested here: https://stackoverflow.com/a/34749619/380054
You need to remove all #Id in properties description except protected $id.

Setting up a manytomany relationship in Doctrine

I have a Property:
(Note: the legacy_id was not my doing and is now ingrained in the app so can't be changed at this time)
<?php
namespace Entity\Beaverusiv;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Entity\Beaverusiv\Property
*
* #ORM\Entity()
* #ORM\Table(name="properties", indexes={#ORM\Index(name="fk_properties_smoking_options1_idx", columns={"smoking_id"}), #ORM\Index(name="fk_properties_linen_options1_idx", columns={"linen_id"}), #ORM\Index(name="fk_properties_pets_options1_idx", columns={"pets_id"}), #ORM\Index(name="fk_properties_property_city1_idx", columns={"city_id"})})
*/
class Property
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\Column(type="integer")
*/
protected $legacy_id;
/**
* #ORM\ManyToMany(targetEntity="FeaturesOption", mappedBy="properties")
*/
protected $featuresOptions;
public function __construct()
{
$this->featuresOptions = new ArrayCollection();
}
/**
* Set the value of id.
*
* #param integer $id
* #return \Entity\Beaverusiv\Property
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* Get the value of id.
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set the value of legacy_id.
*
* #param integer $legacy_id
* #return \Entity\Beaverusiv\Property
*/
public function setLegacyId($legacy_id)
{
$this->legacy_id = $legacy_id;
return $this;
}
/**
* Get the value of legacy_id.
*
* #return integer
*/
public function getLegacyId()
{
return $this->legacy_id;
}
/**
* Add FeaturesOption entity to collection.
*
* #param \Entity\Beaverusiv\FeaturesOption $featuresOption
* #return \Entity\Beaverusiv\Property
*/
public function addFeaturesOption(FeaturesOption $featuresOption)
{
$this->featuresOptions[] = $featuresOption;
return $this;
}
/**
* Get FeaturesOption entity collection.
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getFeaturesOptions()
{
return $this->featuresOptions;
}
}
And FeaturesOption:
<?php
namespace Entity\Beaverusiv;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Entity\Beaverusiv\FeaturesOption
*
* #ORM\Entity()
* #ORM\Table(name="features_options")
*/
class FeaturesOption
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $display_order;
/**
* #ORM\Column(type="string", length=200, nullable=true)
*/
protected $text;
/**
* #ORM\Column(type="integer", nullable=true)
*/
protected $status;
/**
* #ORM\ManyToMany(targetEntity="Property", inversedBy="featuresOptions")
* #ORM\JoinTable(name="properties_features",
* joinColumns={#ORM\JoinColumn(name="feature_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="property_id", referencedColumnName="id")}
* )
*/
protected $properties;
public function __construct()
{
$this->properties = new ArrayCollection();
}
/**
* Set the value of id.
*
* #param integer $id
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* Get the value of id.
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set the value of display_order.
*
* #param integer $display_order
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function setDisplayOrder($display_order)
{
$this->display_order = $display_order;
return $this;
}
/**
* Get the value of display_order.
*
* #return integer
*/
public function getDisplayOrder()
{
return $this->display_order;
}
/**
* Set the value of text.
*
* #param string $text
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function setText($text)
{
$this->text = $text;
return $this;
}
/**
* Get the value of text.
*
* #return string
*/
public function getText()
{
return $this->text;
}
/**
* Set the value of status.
*
* #param integer $status
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* Get the value of status.
*
* #return integer
*/
public function getStatus()
{
return $this->status;
}
/**
* Add Property entity to collection.
*
* #param \Entity\Beaverusiv\Property $property
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function addProperty(Property $property)
{
$property->addFeaturesOption($this);
$this->properties[] = $property;
return $this;
}
/**
* Get Property entity collection.
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getProperties()
{
return $this->properties;
}
}
And the pivot:
<?php
namespace Entity\Beaverusiv;
use Doctrine\ORM\Mapping as ORM;
/**
* Entity\Beaverusiv\PropertiesFeature
*
* #ORM\Entity()
* #ORM\Table(name="properties_features", indexes={#ORM\Index(name="fk_properties_features_features_options1_idx", columns={"feature_id"}), #ORM\Index(name="fk_properties_features_properties1_idx", columns={"property_id"})})
*/
class PropertiesFeature
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
*/
protected $feature_id;
/**
* #ORM\Id
* #ORM\Column(type="integer")
*/
protected $property_id;
/**
* #ORM\ManyToOne(targetEntity="FeaturesOption", inversedBy="propertiesFeatures")
* #ORM\JoinColumn(name="feature_id", referencedColumnName="id", nullable=false)
*/
protected $featuresOption;
/**
* #ORM\ManyToOne(targetEntity="Property", inversedBy="propertiesFeatures")
* #ORM\JoinColumn(name="property_id", referencedColumnName="id", nullable=false)
*/
protected $property;
public function __construct()
{
}
/**
* Set the value of feature_id.
*
* #param integer $feature_id
* #return \Entity\Beaverusiv\PropertiesFeature
*/
public function setFeatureId($feature_id)
{
$this->feature_id = $feature_id;
return $this;
}
/**
* Get the value of feature_id.
*
* #return integer
*/
public function getFeatureId()
{
return $this->feature_id;
}
/**
* Set the value of property_id.
*
* #param integer $property_id
* #return \Entity\Beaverusiv\PropertiesFeature
*/
public function setPropertyId($property_id)
{
$this->property_id = $property_id;
return $this;
}
/**
* Get the value of property_id.
*
* #return integer
*/
public function getPropertyId()
{
return $this->property_id;
}
/**
* Set FeaturesOption entity (many to one).
*
* #param \Entity\Beaverusiv\FeaturesOption $featuresOption
* #return \Entity\Beaverusiv\PropertiesFeature
*/
public function setFeaturesOption(FeaturesOption $featuresOption = null)
{
$this->featuresOption = $featuresOption;
$this->feature_id = $featuresOption->getId();
return $this;
}
/**
* Get FeaturesOption entity (many to one).
*
* #return \Entity\Beaverusiv\FeaturesOption
*/
public function getFeaturesOption()
{
return $this->featuresOption;
}
/**
* Set Property entity (many to one).
*
* #param \Entity\Beaverusiv\Property $property
* #return \Entity\Beaverusiv\PropertiesFeature
*/
public function setProperty(Property $property = null)
{
$this->property = $property;
$this->property_id = $property->getLegacyId();
return $this;
}
/**
* Get Property entity (many to one).
*
* #return \Entity\Beaverusiv\Property
*/
public function getProperty()
{
return $this->property;
}
}
I am having to bring in data from an older DB, like this:
<?php
public function sync()
{
$persist_count = 0; // Keep track of home many properties are ready to be flushed
$flush_count = 20; // Persist and flush the properties in groups of...
$i = 0;
$CI =& get_instance();
$legacy_properties = null;
while ($legacy_properties !== false)
{
$legacy_properties = $this->doctrine->mssql
->getRepository('Entity\MSSQL\TblProperty')
->getProperties($i, $flush_count);
if (count($legacy_properties)===0)
{
break;
}
foreach ($legacy_properties as $legacy_property)
{
// Legacy ID
$legacy_id = $legacy_property['propertyID'];
// Lets see if this property already exists in the new database. If it does, we'll just use that.
$property = $this->doctrine->em
->getRepository('Entity\Beaverusiv\Property')
->findOneBy(array(
'legacy_id' => $legacy_id
));
// If the property from the legacy database does not exist in the new database, let's add it.
if (! $property)
{
$property = new Entity\Beaverusiv\Property; // create a new property instance
$property->setLegacyId($legacy_id);
}
// Update property details
// Set all the other Property fields
$legacy_features = $this->doctrine->mssql
->getRepository('Entity\MSSQL\TblProperty')
->findOneBy(array('propertyID' => $legacy_id))
->getTblPropertyFeaturesJoins();
foreach ($legacy_features as $legacy_feature) {
$feature_id = $legacy_feature->getTblPropertyFeature()->getFeatureID();
$feature = $this->doctrine->em
->getRepository('Entity\Beaverusiv\FeaturesOption')
->findOneBy(array(
'id' => $feature_id
));
$feature_pivot = new Entity\Beaverusiv\PropertiesFeature;
$feature_pivot->setFeaturesOption($feature);
$feature_pivot->setProperty($property);
$this->doctrine->em->merge($feature_pivot);
}
// Persist this property, ready forz flushing in groups of $persist_bunch
$this->doctrine->em->persist($property);
$persist_count++;
// If the number of properties ready to be flushed is the number set in $flush_count, lets flush these properties
if ($persist_count == $flush_count) {
$this->doctrine->em->flush();
$this->doctrine->em->clear();
$this->doctrine->mssql->clear();
}
}
// Flush any remaining properties
$this->doctrine->em->flush();
$i += $flush_count;
}
}
Obviously this is wrong, but I haven't been able to find anywhere to show me a proper example. At the moment it just runs out of memory for some reason and complains about duplicates in the pivot table. How do I get a proper relationship set up so I don't reference the pivot table and can instead directly add FeatureOptions to a Property?
Ok, managed to get it working by changing in Property this:
/**
* #ORM\ManyToMany(targetEntity="FeaturesOption", mappedBy="properties")
*/
protected $featuresOptions;
to this:
/**
* #ORM\ManyToMany(targetEntity="FeaturesOption")
* #ORM\JoinTable(name="properties_features",
* joinColumns={#ORM\JoinColumn(name="property_id", referencedColumnName="legacy_id")},
* inverseJoinColumns={#ORM\JoinColumn(name="feature_id", referencedColumnName="id")}
* )
*/
protected $featuresOptions;
Dropping the pivot table entity, and dropping the inverse reference stuff in the FeaturesOption entity.

Categories