I am building an online shop for plastic model makers (hence the 'model').
I have a Product mapped superclass because I want all products (models, tools, paints etc. to have name, price and description):
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\MappedSuperclass;
use Gedmo\Mapping\Annotation as Gedmo; // gedmo annotations
/** #MappedSuperclass */
abstract class Product
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #ORM\Column(type="string", length=100, nullable=false)
*/
protected $name;
/**
* #var int
* #ORM\Column(type="decimal", scale=2, nullable=false)
*/
protected $price;
/**
* #var string
* #ORM\Column(type="text", nullable=true)
*/
protected $description;
/**
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="update")
*/
private $updatedAt;
//getters and setters...
}
Then, there's a Model class, for plastic models, this extends the Product class but also has a Category for being able to search from cars, aircraft, ships etc:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="model")
*/
class Model extends Product
{
/**
* #var Category
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="models")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=true)
*/
private $category;
/**
* #return Category
*/
public function getCategory()
{
return $this->category;
}
/**
* #param Category $category
*/
public function setCategory($category)
{
$this->category = $category;
}
}
There will of course be more classes extending Product mapped superclass. Now I want to select the 10 most recently added products, regardless of their kind (models, tools, paints).
How can I tell Doctrine to give me the last 10 added products? Of course I tried something like:
$this->getDoctrine()->getManager()->getRepository("AppBundle:Product");
but of course it throws an exception saying that
SQLSTATE[42S02]: Base table or view not found: 1146 Table
'modeller_app.product' doesn't exist
which obviously is true, because Product is an abstract class and not actually an entity. How can I solve this problem?
You need to use class table inheritance.
Here is a example:
/**
* #ORM\Entity
* #ORM\Table(name="product")
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"product" = "Product", "model" = "Model"})
*/
class Product
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #ORM\Column(type="string", length=100, nullable=false)
*/
protected $name;
...
}
/**
* #ORM\Entity
* #ORM\Table(name="product")
*/
class Model extends Product
{
// Custom properties
...
}
Now you can query the Product entity and it will return the result from all entities that inherits it.
Related
I'm trying to implement a doctrine relation for a symphony 3 app.
I have two different classes, one extending from the other, which are related to the same entity with a many to one relation.
Here are my classes.
Country.php
class Country
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #Groups({"exposed"})
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Link", mappedBy="country")
*/
private $link;
/**
* #ORM\OneToMany(targetEntity="LinkChild", mappedBy="country")
*/
private $linkChild;
public function __construct()
{
$this->link = new ArrayCollection();
$this->linkChild = new ArrayCollection();
}
}
Link.php
/**
* Link
*
* #ORM\Table(name="link")
* #ORM\Entity(repositoryClass="Decathlon\AppCollaboratorBundle\Reposito\LinkRepository")
* #Vich\Uploadable
* #ORM\HasLifecycleCallbacks()
*/
class Link
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #Serializer\Groups({"link_list", "link_info"})
* #Serializer\Expose()
*/
protected $id;
/**
* #var Country
*
* #ORM\ManyToOne(targetEntity="Country", inversedBy="link", cascade={"persist"})
* #JoinColumn(name="country_id", referencedColumnName="id")
*/
protected $country;
}
LinkChild.php
/**
* #ORM\Entity(repositoryClass="Decathlon\AppCollaboratorBundle\Repository\LinkChildRepository")
*/
class LinkChild extends Link
{
/**
* #var Country
*
* #ORM\ManyToOne(targetEntity="Country", inversedBy="linkChild", cascade={"persist"})
* #JoinColumn(name="country_id", referencedColumnName="id")
*/
protected $country;
}
I need to create a relation between both Link and LinkChild to Country but no country column is created in LinkChild table.
I've told not to use recursive classes so I must create Link and LinkChild.
Is there a way to acomplish what I'm tryng to do.
Thank you in advance.
I think what you are looking for is single table inheritance?
<?php
namespace MyProject\Model;
/**
* #Entity
* #InheritanceType("SINGLE_TABLE")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
*/
class Person
{
// ...
}
/**
* #Entity
*/
class Employee extends Person
{
// ...
}
Take a look here:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html#single-table-inheritance
Try renaming your protected $country; variable to something like private $childCountry; to make it a variable that belongs specifically to LinkChild.
Your protected $country; override in LinkChild is ignored because it is exactly the same as the one in Link.
I'm trying to get a legacy database into the doctrine mappings.
All the tables have a combined primary key. One ID and one "optios id".
The problem is that Optios ID always has to be set but the OneToOne relation with the same columns causes the column "Optios ID" to be set to null. I'm not sure what I'm doing wrong or is there a way around it?
PS: The 'Pack' relation is optional.
<?php
namespace CalendarBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="CalendarBundle\Repository\CategoryRepository")
* #ORM\Table(name="Categories")
*/
class Category
{
/**
* #ORM\Id
* #ORM\Column(type="integer", name="Category_id")
*/
private $id;
/**
* #ORM\Column(type="integer", name="Optios_id")
* #ORM\Id
*/
private $optiosId;
/**
* #ORM\Column(type="string", name="Name")
*/
private $name;
/**
* #ORM\Column(type="boolean", name="AvailableOnline")
*/
private $online;
/**
* #ORM\Column(type="integer", name="SequenceNumber", nullable=true)
*/
private $order;
/**
* #ORM\Column(type="integer", name="Parent_id")
*/
private $parentId;
/**
* One Category has Many Packs.
*
* #var Pack
*
* #ORM\OneToOne(targetEntity="Pack", inversedBy="category")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="Pack_id", referencedColumnName="Pack_id"),
* #ORM\JoinColumn(name="Optios_id", referencedColumnName="Optios_id"),
* )
*/
private $pack;
/**
* #ORM\Column(type="boolean", name="Deleted")
*/
private $deleted;
I am using Doctrine 2.5.0 and I am fairly new to it.
I would like to know why the position of the properties and associations affects the saving of the entity.
I have an entity with some properties and some associations. I recently noticed this on at least 3 different entities that if a property is placed after an association, it would not be updated in the database (using merge and flush).
So, in the below entity, the name and other properties do not get updated.
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="products")
*/
class Product
{
/**
* #ORM\Id
* #ORM\Column(type="integer", length=8)
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToOne(targetEntity="Shop")
* #ORM\JoinColumn(name="shopId", referencedColumnName="id")
*/
protected $shop;
/**
* #ORM\Column(type="string", length=255)
*/
protected $name;
/*Some other properties*/
/*Getters and Setters*/
}
But this gets updated. Notice the position of the $name (and all the other properties) and $shop.
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(
* name="products"
* )
*/
class Product
{
/**
* #ORM\Id
* #ORM\Column(type="integer", length=8)
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255)
*/
protected $name;
/*ALL other properties*/
/**
* #ORM\OneToOne(targetEntity="Shop")
* #ORM\JoinColumn(name="shopId", referencedColumnName="id")
*/
protected $shop;
/*Getters and Setters*/
}
I thought of changing the positions because in one of my entities I noticed that only the properties placed after the associations were not getting updated in the database.
I am trying to create a demo project where there are 3 tables: category, model, type.
There may be different categories, such as cellphone, tablets, computer, etc. For each category there are different types, such as for cellphone there could be asus, iphone, nokia, etc. Likewise, for each type there are different models: for nokia there might be nokia, lumia, nokia n97, etc. How do I create this database in symfony2 using annotations?
The code is not that complicated:
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class Category
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="Model", mappedBy="category")
*/
private $models;
}
/**
* #ORM\Entity()
*/
class Model
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ManyToOne(targetEntity="Category", inversedBy="models")
* #JoinColumn(name="category_id", referencedColumnName="id")
**/
private $category;
/**
* #ORM\OneToMany(targetEntity="Type", mappedBy="model")
*/
private $types;
}
/**
* #ORM\Entity()
*/
class Type
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="type", type="string", length=255)
*/
private $name;
/**
* #ManyToOne(targetEntity="Model", inversedBy="types")
* #JoinColumn(name="model_id", referencedColumnName="id")
**/
private $model;
}
After adding your code each one in it's file run the command:
php app/console doctrine:generate:entities
and it will generate setters and getters and constructors
I have Three entities:
FeatureValue.php
<?php
namespace Webmuch\ProductBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class FeatureValue
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length="100")
*/
protected $name;
/**
* #ORM\OneToMany(targetEntity="FeatureType", mappedBy="name")
*/
private $featuretype;
public function __construct()
{
$this->featuretype = new \Doctrine\Common\Collections\ArrayCollection();
}
FeatureType.php
<?php
namespace Webmuch\ProductBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Webmuch\ProductBundle\Entity\FeatureValue;
/**
* #ORM\Entity
*/
class FeatureType
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
protected $title;
/**
* #ORM\ManyToOne(targetEntity="FeatureValue", inversedBy="featuretype",cascade={"persist"})
* #ORM\JoinColumn(name="feature_value_id", referencedColumnName="id")
*/
protected $name;
public function __construct()
{
$this->name = new \Doctrine\Common\Collections\ArrayCollection();
}
Product.php
<?php
namespace Webmuch\ProductBundle\Entity;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection as ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table()
* #ORM\HasLifecycleCallbacks
*/
class Product
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Store")
*/
protected $store;
/**
* #ORM\ManyToMany(targetEntity="Webmuch\CategoryBundle\Entity\Category")
*/
protected $category;
/**
* #Gedmo\Sluggable
* #ORM\Column(type="string", length=255)
*/
protected $title;
/**
* #Gedmo\Slug(updatable=false, unique=true)
* #ORM\Column(type="string", length=255)
*/
protected $slug;
/**
* #ORM\Column(type="integer")
*/
protected $quantity;
/**
* #ORM\Column(type="boolean")
*/
protected $active;
/**
* #ORM\Column(type="text", length="4000", nullable="true")
*/
protected $preview;
/**
* #ORM\ManyToMany(targetEntity="FeatureType")
* #ORM\JoinColumn(name="feature_type_id", referencedColumnName="id")
*/
protected $features;
public function __toString()
{
return $this->getTitle();
}
}
My problem is that when i add FeatureValue in FeatureType then show me error Class "Doctrine\Common\Collections\ArrayCollection is not a valid entity or mapped super class."
In my project i want FeatureType along with FeatureValue in my Product entity.
suppose in FeatureType two property Size and Colour.Now in FeatureType Size- Three FeatueValue Small,Medium,Large have been given and also suppose in FeatureType Colour- Three FeatureValue Red,Green,Yello have been given.
Now i want to show both the FeatureType along with their FeatureValue in my Product Entity.
So any one tell me how it can be done.I have tried a lot of but not succeed.
In Webmuch\ProductBundle\Entity\FeatureType::__construct you assign an ArrayCollection to $this->name, this is wrong, as this is a ToOne and not a ToMany.
Just remove this line.