How would I convert this 'annotations' code into Yaml?
/**
* #Entity
* #InheritanceType("SINGLE_TABLE")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
*/
The manual doesn't give it in Yaml and I after Googling for hours just can't find a way to do it.
type: entity
inheritanceType: SINGLE_TABLE
discriminatorColumn:
name: discr
type: string
discriminatorMap:
person: Person
employee: Employee
Related
I am using CodeIgniter 4.x for my project. In my approach, I am using Module system for my project. My Module system is like below structure:
- App
- Modules
- ListMaster
- User
- Models
- Doctrine
- Entities
- User.php
- UserApp.php
- UserGroup
- Models
- Doctrine
- Entities
- Usergroup.php
- Budget
- Models
- Doctrine
- Entities
- Budget.php
In a simple word, I have designed to have my Modules under App/Modules folder. This Folder could consist a Module folder or a folder which will hold Modules. As I created two Modules App/Modules/ListMaster/User and App/Modules/ListMaster/Usergroup. My Entity Class Files will be located under ...Models/Doctrine/Entities folders.
I have downloaded Doctrine using Composer. My Composer is as follow:
{
"require": {
"doctrine/orm": "^2.3.3",
"doctrine/dbal": "^3.2",
"doctrine/annotations": "^1.14",
"symfony/yaml": "^5.4",
"symfony/cache": "^5.4"
},
"autoload": {
"psr-0": {"": "src/"}
},
}
I have created a Library file under App/Libraries which is as follow:
<?php
namespace App\Libraries;
//WE INCLUDING THE AUTOLOAD VENDOR
include_once dirname(__DIR__, 2) . '/vendor/autoload.php';
use Doctrine\Common\ClassLoader;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
// TO OBTAIN THE ENTITY MANAGER
class Doctrine
{
public $em;
public function __construct()
{
// Retrieving all paths leading to entities classes
$modulePath = APPPATH."Models/Doctrine/Entities";
$entitiesPath = glob($modulePath, GLOB_ONLYDIR);
$modulePath = APPPATH."Modules/*/Models/Doctrine/Entities";
$entitiesPath = array_merge($entitiesPath, glob($modulePath, GLOB_ONLYDIR));
$modulePath = APPPATH."Modules/*/*/Models/Doctrine/Entities";
$entitiesPath = array_merge($entitiesPath, glob($modulePath, GLOB_ONLYDIR));
$isDevMode = true;
$cache = null;
$useSimpleAnnotationReader = false;
// CONNECTION SETUP
$config = config("Database");
$connection_options = array(
'driver' => strtolower($config->doctrine['DBDriver']),
'user' => $config->doctrine['username'],
'password' => $config->doctrine['password'],
'dbname' => $config->doctrine['database'],
'host' => $config->doctrine['hostname']
);
$proxies_dir = APPPATH . 'Models/Doctrine/Proxies';
$config = Setup::createAnnotationMetadataConfiguration($entitiesPath, $isDevMode, $proxies_dir, $cache, $useSimpleAnnotationReader);
if (ENVIRONMENT === 'development') {
$config->setAutoGenerateProxyClasses(true);
} else {
$config->setAutoGenerateProxyClasses(false);
}
try {
$this->em = EntityManager::create($connection_options, $config);
} catch (\Doctrine\ORM\ORMException $e) {
log_message("Doctrine Exception : ", $e);
}
}
}
As you can see from this, My Entities files will be at Models/Doctrine/Entities, Modules/{any folder}/Models/Doctrine/Entities, Modules/{any folder}/{any folder}/Models/Doctrine/Entities folders.
Now here is my sample Entities Class:
<?php
namespace entities;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* #ORM\Table(name="user")
* #ORM\Entity
*/
class User
{
/**
* #var smallint $id
*
* #ORM\Column(name="id", type="smallint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string $userName
*
* #ORM\Column(name="user_name", type="string", length=150, nullable=true)
*/
protected $userName;
/**
* Constructor
*/
public function __construct()
{
}
/**
* Get id
*
* #return boolean
*/
public function getId()
{
return $this->id;
}
/**
* Set userName
*
* #param string $userName
*/
public function setUserName($userName)
{
$this->userName = $userName;
}
/**
* Get userName
*
* #return string
*/
public function getUserName()
{
return $this->userName;
}
}
Now from my Controller I am executing this Line of code which produces entities\User class not found error. Though this structure can create and update Schema in Database successfully.
$users = $this->em->getRepository('entities\User')->findAll();
Please be noted that I have successfully Generate Proxy, Generate Entities, Crate Schema, Update Schema from this installation.
Thanks in Advance. Please let me know if I missed something to inform you.
So my question is, How to fix the class not found error and got result from Database from any table?
I'm having trouble making Sonata Admin Bundle working with Ramsey's Uuid as the entity's Id.
This is the error I get when I try to show the Country list (/admins/app/country/list)
An exception has been thrown during the rendering of a template ("Unknown database type uuid requested, Doctrine\DBAL\Platforms\MySQL57Platform may not support it.").
doctrine.yaml
doctrine:
dbal:
types:
uuid: Ramsey\Uuid\Doctrine\UuidType
services.yaml
sonata.admin.country:
class: App\Admin\CountryAdmin
arguments: [~, App\Entity\Country, ~]
tags:
- { name: sonata.admin, manager_type: orm, group: Entities, label: Country }
App\Entity\Country
class Country
{
/**
* #ORM\Id
* #ORM\Column(type="uuid", unique=true)
* #ORM\GeneratedValue(strategy="CUSTOM")
* #ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
*/
protected $id;
App\Admin\Country
final class CountryAdmin extends Sonata\AdminBundle\Admin\AbstractAdmin
{
protected function configureRoutes(RouteCollection $collection)
{
$collection
->add('show_country', sprintf('%s/show_country', $this->getRouterIdParameter()));
}
}
App\Controller\Admin\CountryController
class CountryController extends Sonata\AdminBundle\Controller\CRUDController
{
public function showCityAction(Request $request): Response
{
/** #var Country $country */
$country = $this->admin->getSubject();
if (!$country) {
$id = $request->get($this->admin->getIdParameter());
throw $this->createNotFoundException(sprintf(
'Unable to find the object with id : %s',
$id
));
}
return $this->renderWithExtraParams('admin/city/show_country.html.twig', [
'show_country' => $country,
]);
}
}
composer.json
"sonata-project/admin-bundle": "^3.53",
"sonata-project/doctrine-orm-admin-bundle": "^3.10",
"sonata-project/translation-bundle": "^2.4",
"sonata-project/user-bundle": "^4.4",
"stof/doctrine-extensions-bundle": "^1.3",
"sonata-project/easy-extends-bundle": "^2.5",
"ramsey/uuid-doctrine": "^1.5"
It seems that the Uuid type is not loaded, although it's in the doctrine.yaml config file. I tried to include it manually in bootstrap.php:
\Doctrine\DBAL\Types\Type::addType('uuid', 'Ramsey\Uuid\Doctrine\UuidType');
but I just get an error message saying the type is already included.
I realised that vendor/sonata-project/doctrine-extensions/src/Types only contains JsonType.php. Could it be that Uuid.php is missing ? Or am I missing something else ? Thank you for your help !
I finally found the answer to this. All I had to do is add the 2 lines to the doctrine.yaml file:
doctrine:
dbal:
types:
uuid: Ramsey\Uuid\Doctrine\UuidType
mapping_types: <---
uuid: uuid <---
I hope it can help someone because personally I couldn't find the information anywhere on the internets !
I need cross database relations, i've read about this buti can't get what i want due to a mapping issue.
This is my situation
namespace App\Entity\Utility;
use Doctrine\ORM\Mapping as ORM;
use App\Entity\Crm\User;
/**
* Description of Test
*
* #ORM\Table(name="fgel_utility.fgel_test")
* #ORM\Entity(repositoryClass="App\Repository\Utility\TestRepository")
*/
class Test
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #var User
*
* #ORM\ManyToOne(targetEntity="App\Entity\Crm\User")
* #ORM\JoinColumn(name="user_cod", referencedColumnName="AUCUT")
*/
protected $user = null;
public function getId()
{
return $this->id;
}
public function getUser(): User
{
return $this->user;
}
public function setId($id)
{
$this->id = $id;
return $this;
}
public function setUser(User $user)
{
$this->user = $utente;
return $this;
}
}
namespace App\Entity\Crm;
use Doctrine\ORM\Mapping as ORM;
/**
*
* #ORM\Table(name="crm.USER")
* #ORM\Entity(repositoryClass="App\Repository\FintelGasDati\AnuteRepository")
*/
class User
{
/**
*
* #ORM\Id
* #ORM\Column(name="AUCUT", type="integer", nullable=false)
*/
protected $codiceCliente;
# SOME CODE
}
My doctrine.yaml
doctrine:
orm:
default_entity_manager: default
entity_managers:
#################################
# Update schema only with this em
#################################
default:
connection: mssql_1
mappings:
Utility:
type: "annotation"
# The directory for entity (relative to bundle path)
dir: '%kernel.project_dir%/src/Entity/Utility'
prefix: 'App\Entity\Utility'
alias: Utility
mssql_crm:
connection: mssql_1
mappings:
Crm:
type: "annotation"
# The directory for entity (relative to bundle path)
dir: '%kernel.project_dir%/src/Entity/Crm'
prefix: 'App\Entity\Crm'
alias: Crm
So they are sharing the same connection (but a different em). The user of the connections has the privileges to read/write both databases (but only to alter schema to the fgel_utility DB. Both DB are stored in a SQL Server 2008.
When i'm tryin' to execute
php bin/console doctrine:schema:update --dump-sql
I get this error
The class 'App\Entity\Crm\User' was not found in the chain configured
namespaces App\Entity\Utility, FOS\UserBundle\Model
You can actually trick Doctrine to do cross-database join queries to MySQL/MariaDB, simply by prefixing the database name in the ORM\Table annotation of your entites :
// src/Entity/User.php
#ORM\Table(name="dbname.users")
This will be used by Doctrine in all the SELECT, JOIN statements.
That beeing said, using this solution, the DB_NAME from DATABASE_URL or any other values of your env files won't be used, which can lead to confusions (as the database name should be coupled to the connection, not the entity).
As you cannot resolve dynamic value in your ORM mappings, such as "#ORM\Table(name=%env(DBNAME)%.users"), but here is an exemple of how you can use the LoadClassMetadata event from Doctrine to do that job dynamically.
The class constructor takes the Entities namespace as a first argument, and the database name as the second argument.
When Doctrine runs the metadata loading, it will fire the callback method with the metadata class for each entity, onto which you can process and set the table name dynamically from theses values.
// src/DatabasePrefixer.php
class DatabasePrefixer implements EventSubscriber
{
private $namespace;
private $tablePrefix;
/**
* #param $namespace string The fully qualified entity namespace to add the prefix
* #param $tablePrefix string The prefix
*/
public function __construct($namespace, $tablePrefix)
{
$this->namespace = $namespace;
$this->tablePrefix = $tablePrefix;
}
public function getSubscribedEvents()
{
return ['loadClassMetadata'];
}
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$classMetadata = $eventArgs->getClassMetadata();
if ($this->namespace == $classMetadata->namespace) {
$classMetadata->setTableName(sprintf('%s.%s', $this->tablePrefix, $classMetadata->table['name']));
}
}
}
Supposing that you have a DB_NAME env variable, configure the class as a service in your config/services.yml, using the yaml resolving features of Symfony, and the event tagging to listen to the correct Doctrine event :
// config/services.yaml
services:
[...]
dbname.prefixer:
class: App\DatabasePrefixer
arguments:
$namespace: 'App\Entity'
$tablePrefix: '%env(DB_NAME)%'
tags:
- { name: doctrine.event_listener, event: loadClassMetadata, lazy: true }
According to this https://github.com/doctrine/doctrine2/issues/6350 cross database joins between different entity managers (same connections) isn't supported.
I installed FOSUserbundle and HWI Oauth bundle.
My problem is: I want to access data from my user entity that is stored in a relation. I'd like to access the data from the fields social_network_slug and social_identifier from UserInSocialNetworks within the FOSUserProvider.
The idea was, that one user can have more that one social network logins. (1:n)- When I log in with my google/facebook etc login, I want to check the table user_in_social_networks if the Id with the social network already exists.
/*
* This is the User class, depending on fos_userBundle
*/
namespace AppBundle\Entity\Registration;
use Doctrine\Common\Collections\ArrayCollection as ArrayCollection;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* One User can have many social networks
* #ORM\OneToMany(targetEntity="UserInSocialNetworks", mappedBy="user", cascade={"remove"})
*/
private $socialnetworks; ....
the Entity Class to store all User's social media logins:
<?php
namespace AppBundle\Entity\Registration;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* UserInSocialNetworks
*
* #ORM\Table(name="user_in_social_networks")
* #ORM\Entity(repositoryClass="AppBundle\Repository\Registration\UserInSocialNetworksRepository")
*/
class UserInSocialNetworks
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* Many Socialnetwork Logins have one User
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Registration\User", inversedBy="socialnetworks")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*
*/
private $user;
/**
* #var int
*
* #ORM\Column(name="social_network_slug", type="string", length=255, nullable=true)
*/
private $socialNetworkSlug;
/**
* #var string
*
* #ORM\Column(name="social_identifier", type="string", length=255, nullable=true)
*/
private $socialIdentifier;
The extended FOSUBUserProvider class:
<?php
namespace AppBundle\Entity\Registration;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseClass;
use Symfony\Component\Security\Core\User\UserInterface;
class FOSUBUserProvider extends BaseClass
{
/**
* {#inheritDoc}
*/
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
// get user_id and socialnetworkname from response
$userIdInSocialNetwork = $response->getUsername();
$socialnetwork = $response->getResourceOwner()->getName();
// Here I'd like to search for an existing $userIdInSocialNetwork
What I checked since now: I can't access the entitymanager in FOSUBUserProvider class, and I can't search that way:
$user = $this->userManager->findUserBy(array(
'socialIdentifier' => $userIdInSocialNetwork,
'social_network_slug' => $socialnetwork)
because it's a relation.
Thanks for any idea!
As you mentioned that you have extended FOSUBUserProvider i assume you have defined a new service for this, If so then you can pass doctrine's entity manager to your class #doctrine.orm.entity_manager. Following HWIOAuthBundle documentation for FOSUserBundle you can pass entity manager as
services:
my.custom.user_provider:
class: MyBundle\Security\Core\User\MyFOSUBUserProvider
arguments: ['#fos_user.user_manager', { facebook: facebook_id }, #doctrine.orm.entity_manager]
And then in your class you can use this service as
use Doctrine\ORM\EntityManager;
use FOS\UserBundle\Model\UserManagerInterface;
//.... other use statements
class FOSUBUserProvider extends BaseClass
{
private $em;
public function __construct(UserManagerInterface $userManager, array $properties, EntityManager $em)
{
$this->em = $em;
parent::__construct($userManager, $properties); /* pass dependencies to parent */
}
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$this->em->getRepository('AppBundle\Entity\Registration\UserInSocialNetworks')->findBy(....);
/* Do your stuff here */
}
}
Get error on my implementation but resolve this by adding quote to the third argument like bellow:
services:
my.custom.user_provider:
class: MyBundle\Security\Core\User\MyFOSUBUserProvider
arguments: ['#fos_user.user_manager', { facebook: facebook_id }, '#doctrine.orm.entity_manager']
I'm using Doctrine 2.2.0 together with Codeigniter. I'm new to Doctrine (or to ORM in general).
I'm setting up entity and proxy classes based on YAML files which works fine. I do have problems in reflecting a polymorphic association in my DB in my Doctrine classes. I'm looking for a concrete example on how to implement the following polymorphic association in Doctrine.
In my DB I have a table called products. Depending on the value of field object_type and object_id I want to relate either to a record in the table videos or the table cars (I simplified it here). I want to keep both product types in 2 separate table because one has nothing to do with the other and both tables relate to other tables.
I took a look at the Doctrine Inheritance documentation and other examples, but it doesn't seem to help me. If possible I want to avoid adding the columns description and price to the tables videos and cars.
Many thanks!
|Table: products |
|-----------------------------------------------------|
| ID | description | price | object_type | object_id |
|-----------------------------------------------------|
| 1 | A video | 20.00 | video | 12 |
| 2 | A car | 159.00 | car | 5 |
|Table: videos |
|--------------------------------------------|
| ID | filename | artist_id | date |
|--------------------------------------------|
| 12 | somename.mp4 | 189 | 2011-02-15 |
|Table: cars |
|------------------------------|
| ID | brand_id | model | year |
|------------------------------|
| 5 | 17 | astra | 2010 |
Found the solution myself. I've listed below the different steps I've done. This answer is very big, but I tried to be as complete as possible.
The most important things are in the Product YAML files inheritanceType: JOINED, discriminatorColumn:, discriminatorMap: and the Video and Car entity classes class Video extends Product, class Car extends Product.
1) DB Schema
CREATE TABLE IF NOT EXISTS `artists` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `brands` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `cars` (
`id` int(11) NOT NULL,
`model` varchar(255) NOT NULL,
`release_date` date NOT NULL,
`brand_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`description` varchar(255) NOT NULL,
`price` double NOT NULL,
`object_type` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `videos` (
`id` int(11) NOT NULL,
`file_name` varchar(255) NOT NULL,
`release_date` date NOT NULL,
`artist_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
2) Doctrine YAML files (from which you need to create the Entity and proxy classes)
Entities.Artist.dcm.yml
Entities\Artist:
type: entity
table: artists
id:
id:
type: integer
primary: true
notnull: true
generator:
strategy: AUTO
fields:
name:
type: string(255)
notnull: true
oneToMany:
videos:
targetEntity: Video
mappedBy: artist
options:
charset: utf8
type: InnoDB
Entities.Brand.dcm.yml
Entities\Brand:
type: entity
table: brands
id:
id:
type: integer
primary: true
notnull: true
generator:
strategy: AUTO
fields:
name:
type: string(255)
notnull: true
oneToMany:
cars:
targetEntity: Car
mappedBy: brand
options:
charset: utf8
type: InnoDB
Entities.Car.dcm.yml
Entities\Car:
type: entity
table: cars
fields:
model:
type: string
notnull: true
release_date:
type: date
notnull: true
oneToOne: #unidirectional
brand:
targetEntity: Brand
joinColumns:
brand_id:
referencedColumnName: id
options:
charset: utf8
type: InnoDB
Entities.Product.dcm.yml
Entities\Product:
type: entity
table: products
id:
id:
type: string
primary: true
notnull: true
generator:
strategy: AUTO
fields:
description:
type: string(255)
notnull: true
price:
type: decimal
notnull: true
inheritanceType: JOINED
discriminatorColumn:
name: object_type
type: string
length: 255
discriminatorMap:
video: Video
car: Car
options:
charset: utf8
type: InnoDB
Entities.Video.dcm.yml
Entities\Video:
type: entity
table: videos
fields:
file_name:
type: string
notnull: true
release_date:
type: date
notnull: true
oneToOne: #unidirectional
artist:
targetEntity: Artist
joinColumns:
artist_id:
referencedColumnName: id
options:
charset: utf8
type: InnoDB
3) Create Entity and Proxy classes
I use CodeIgniter. I've used Joel Verhagen's excellent guide
!! It's important you extend Video and Car with Product - See below !!
This results in the following Entity classes
Artist.php
namespace Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Entities\Artist
*
* #ORM\Table(name="artists")
* #ORM\Entity
*/
class Artist
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(targetEntity="Entities\Video", mappedBy="artist")
*/
private $videos;
public function __construct()
{
$this->videos = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Artist
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add videos
*
* #param Entities\Video $videos
*/
public function addVideo(\Entities\Video $videos)
{
$this->videos[] = $videos;
}
/**
* Get videos
*
* #return Doctrine\Common\Collections\Collection
*/
public function getVideos()
{
return $this->videos;
}
}
Brand.php
namespace Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Entities\Brand
*
* #ORM\Table(name="brands")
* #ORM\Entity
*/
class Brand
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(targetEntity="Entities\Car", mappedBy="brand")
*/
private $cars;
public function __construct()
{
$this->cars = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Brand
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add cars
*
* #param Entities\Car $cars
*/
public function addCar(\Entities\Car $cars)
{
$this->cars[] = $cars;
}
/**
* Get cars
*
* #return Doctrine\Common\Collections\Collection
*/
public function getCars()
{
return $this->cars;
}
}
Car.php
namespace Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Entities\Car
*
* #ORM\Table(name="cars")
* #ORM\Entity
*/
class Car extends Product //Important that Car extends Product
{
/**
* #var string $model
*
* #ORM\Column(name="model", type="string")
*/
private $model;
/**
* #var date $release_date
*
* #ORM\Column(name="release_date", type="date")
*/
private $release_date;
/**
* #var Entities\Brand
*
* #ORM\OneToOne(targetEntity="Entities\Brand")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="brand_id", referencedColumnName="id", unique=true)
* })
*/
private $brand;
/**
* Set model
*
* #param string $model
* #return Car
*/
public function setModel($model)
{
$this->model = $model;
return $this;
}
/**
* Get model
*
* #return string
*/
public function getModel()
{
return $this->model;
}
/**
* Set release_date
*
* #param date $releaseDate
* #return Car
*/
public function setReleaseDate($releaseDate)
{
$this->release_date = $releaseDate;
return $this;
}
/**
* Get release_date
*
* #return date
*/
public function getReleaseDate()
{
return $this->release_date;
}
/**
* Set brand
*
* #param Entities\Brand $brand
* #return Car
*/
public function setBrand(\Entities\Brand $brand = null)
{
$this->brand = $brand;
return $this;
}
/**
* Get brand
*
* #return Entities\Brand
*/
public function getBrand()
{
return $this->brand;
}
}
Product.php
namespace Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Entities\Product
*
* #ORM\Table(name="products")
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="", type="", length=)
* #ORM\DiscriminatorMap({"video" = "Entities\Video", "car" = "Entities\Car"})
* #ORM\Entity
*/
class Product
{
/**
* #var string $id
*
* #ORM\Column(name="id", type="string")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string $description
*
* #ORM\Column(name="description", type="string", length=255)
*/
private $description;
/**
* #var decimal $price
*
* #ORM\Column(name="price", type="decimal")
*/
private $price;
/**
* Get id
*
* #return string
*/
public function getId()
{
return $this->id;
}
/**
* Set description
*
* #param string $description
* #return Product
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set price
*
* #param decimal $price
* #return Product
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* #return decimal
*/
public function getPrice()
{
return $this->price;
}
}
Video.php
namespace Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* Entities\Video
*
* #ORM\Table(name="videos")
* #ORM\Entity
*/
class Video extends Product //Important that Video extends Product
{
/**
* #var string $file_name
*
* #ORM\Column(name="file_name", type="string")
*/
private $file_name;
/**
* #var date $release_date
*
* #ORM\Column(name="release_date", type="date")
*/
private $release_date;
/**
* #var Entities\Artist
*
* #ORM\OneToOne(targetEntity="Entities\Artist")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="artist_id", referencedColumnName="id", unique=true)
* })
*/
private $artist;
/**
* Set file_name
*
* #param string $fileName
* #return Video
*/
public function setFileName($fileName)
{
$this->file_name = $fileName;
return $this;
}
/**
* Get file_name
*
* #return string
*/
public function getFileName()
{
return $this->file_name;
}
/**
* Set release_date
*
* #param date $releaseDate
* #return Video
*/
public function setReleaseDate($releaseDate)
{
$this->release_date = $releaseDate;
return $this;
}
/**
* Get release_date
*
* #return date
*/
public function getReleaseDate()
{
return $this->release_date;
}
/**
* Set artist
*
* #param Entities\Artist $artist
* #return Video
*/
public function setArtist(\Entities\Artist $artist = null)
{
$this->artist = $artist;
return $this;
}
/**
* Get artist
*
* #return Entities\Artist
*/
public function getArtist()
{
return $this->artist;
}
}
3) Creating a new Car and a new Video
This is what goes in my CodeIgniter controller. The code presumes you've created an artist with the name Metallica and a brand with the name Ford.
public function createVideo()
{
//Instantiate new Entities\Video object
$video = new Entities\Video;
//Since it extends Entities\Product you can set the common Product properties
$video->setDescription('This is a Metallica clip');
$video->setPrice(19.95);
//Setting the custom Video properties
$artist = $this->doctrine->em->getRepository('Entities\Artist')->findOneBy(array('name' => 'Metallica'));
$video->setArtist($artist);
$video->setReleaseDate(new DateTime());
$video->setFileName('metallica.mp4');
//Save
$this->doctrine->em->persist($video);
$this->doctrine->em->flush();
}
public function createCar()
{
//Instantiate new Entities\Car object
$car = new Entities\Car;
//Since it extends Entities\Product you can set the common Product properties
$car->setDescription('This is Ford Mondeo of 2011');
$car->setPrice(19.95);
//Setting the custom Car properties
$brand = $this->doctrine->em->getRepository('Entities\Brand')->findOneBy(array('name' => 'Ford'));
$car->setBrand($brand);
$car->setReleaseDate(DateTime::createFromFormat('Y-m-d', '2011-11-15'));
$car->setModel('Mondeo');
//Save
$this->doctrine->em->persist($car);
$this->doctrine->em->flush();
}
4) Extracting all products
An example on how to extract all Products
public function extractAllProducts()
{
$products = $this->doctrine->em->getRepository('Entities\Product')->findAll();
foreach($products as $product)
{
printf('%s for € %s<br />', $product->getDescription(), $product->getPrice());
}
}
This results into
This is a Metallica clip for € 19.95
This is Ford Mondeo of 2011 for € 19.95
An example onn how to extract all Videos
public function extractAllVideos()
{
$videos = $this->doctrine->em->getRepository('Entities\Video')->findAll();
foreach($videos as $video)
{
printf('%s, released %s for € %s<br />', $video->getDescription(), $video->getReleaseDate()->format('Y'), $video->getPrice());
}
}
This results into
This is a Metallica clip, released 2012 for € 19.95
You were looking in the right place, inheritance mapping is certainly what you need to achieve this. From what I can tell this is a perfect example of "class table inheritance".
Check out the manual for some example / explanation on how to implement this.
http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/inheritance-mapping.html#class-table-inheritance