select entities of multiple subclasses extending from one superclass using doctrine 2 - php

Given this setup for my Doctrine 2 Entities:
App\Bundle\LorumBundle\Entity\Node:
type: entity
table: node
fields:
id:
id: true
type: integer
unsigned: false
nullable: false
generator:
strategy: IDENTITY
created:
type: datetime
inheritanceType: SINGLE_TABLE
discriminatorColumn:
name: type
type: string
length: 255
discriminatorMap:
a: a
b: b
c: c
App\Bundle\LorumBundle\Entity\A:
type: entity
fields:
status:
type: boolean
App\Bundle\LorumBundle\Entity\B:
type: entity
fields:
status:
type: boolean
App\Bundle\LorumBundle\Entity\C:
type: entity
fields:
title:
type: string
Now what I want to get is basically a mixed list of Entities of the type A & B (not C) with the status == true.
I could write a Query like this - using the instance ofoperator to limit the result to the subclasses i want of course but i will get an Error because the property I want to match against (status) is not mapped in the Superclass even tough all the Entities i want to match against have it:
$queryBuilder->select('Node');
$queryBuilder->from('App\Bundle\LorumBundle\Entity\Node','Node');
$queryBuilder->add('where',$queryBuilder->expr()->orx(
'Offer INSTANCE OF AppLorumBundle:A',
'Offer INSTANCE OF AppLorumBundle:B'
));
$queryBuilder->where($queryBuilder->expr()->eq('Node.status', '?1'));
$queryBuilder->setParameter(1, true);
$queryBuilder->orderBy('Node.created', 'asc');
$queryBuilder->setFirstResult( 0 );
$queryBuilder->setMaxResults( 200 );
Is there any way to do this, short of writing your own persister and hack it into Doctrine2?
Unfortunately its not an Option for me to just add the Information to the Superclass (in my real scenario this situation mostly applies to relations which i don't want to be loaded eagerly with every subclass)

You can use UNION and work with queries for entities A and B
build query for entity A
build query for entity B
build query for limit and order using UNION for queries A and B
no need to do any hacks for Doctrine library

Related

Symfony2/Doctrine can't find mapping file for custom Repository class

I love doctrine but I have some problems with mapping/annotations. At start I used mapping files. Then I converted in into annotations. Now I want o create custom repository class so I did as I read here: http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes.
Unfortunately now I have an error:
No mapping file found named '\src\Vendor\ProductBundle\Resources\config\doctrine/SynchronizationSettingRepository.orm.yml' for class 'Vendor\ProductBundle\Entity\SynchronizationSettingRepository'.
Of course I don't have this file becouse I don't use mapping anymore.
I've added:
* #ORM\Entity(repositoryClass="Vendor\ProductBundle\Entity\SynchronizationSettingRepository")
to parent and regenerated entities. I have regenerate Entites by command php app/console doctrine:generate:entities VendorProductBundle and still nothing. Regural and doctrine meadata cache is clear.
Here is a YML which from I want to generate custom Repository one more time:
Vendor\ProductBundle\Entity\SynchronizationSetting:
type: entity
table: synchronization_setting
repositoryClass: Vendor\SynchronizationSetting\Entity\SynchronizationSettingRepository
indexes:
id_product:
columns:
- id_product
id:
id:
type: integer
nullable: false
unsigned: true
comment: ''
id: true
generator:
strategy: IDENTITY
fields:
open:
type: string
nullable: true
length: 1
fixed: true
comment: ''
default: '0'
internet:
type: string
nullable: true
length: 1
fixed: true
comment: ''
default: '0'
manyToOne:
idProduct:
targetEntity: Product
cascade: { }
mappedBy: null
inversedBy: null
joinColumns:
id_product:
referencedColumnName: id
orphanRemoval: false
lifecycleCallbacks: { }
And here is a repository class:
<?php
// src/Acme/StoreBundle/Entity/ProductRepository.php
namespace Vendor\ProductBundle\Entity;
use Doctrine\ORM\EntityRepository;
class SynchronizationSettingRepository extends EntityRepository
{
public function findAllOrderedByName()
{
return $this->getEntityManager()
->createQuery(
'SELECT p FROM AcmeStoreBundle:Product p ORDER BY p.name ASC'
)
->getResult();
}
}
I think that adding #ORM\Entity did very little good as complete .php class file gets overwritten as soon as you run the doctrine:generate:entities. You need to add repositotyClass to your YML file instead.
If you switched to annotations for good, those .yml files (actually whole doctrine directory within config) are useless, apart as being intermediate files for generating annotaion-based entities.
Another thing: It seams that Doctrine thinks you have a entity with name ending with "Repository".
Can you show us the content of YML file? If you don't have it (as you said), generating entities will not be possible. You can always generate annotaion-based entities directly (no need for YML intermediates)

Doctrine Yaml Mapping Shared Columns

Is it possible using Yaml orm files to specify a base Entity that all of the Entities will share, I can compare this to C# ADO.NET where you can specify a class that holds all of the data that will be common among all of your tables
For example, say I have the below YAML mapping for Doctrine:
src\SITEBUNDLE\Entity\User:
REALTYBLOG\Entity\User:
type: entity
table: users
id:
id:
type:integer
generator: { strategy: AUTO }
fields:
firstName:
type: string
length: 255
lastName:
type: string
length: 255
middleInital:
type: string
length: 1
username:
type:
length: 26
passwordHash:
type: string
length: 255
createdOn:
type: dateTime
createdBy:
type: string
length: 26
modifiedOn:
type: dateTime
modifiedBy:
type: string
deletedOn:
type: dateTime
Now lets say that I have created multiple other YAML configs and all of them share the createdOn, createdBy, modifiedOn, modifiedBy, deletedOn columns. Can I specify an overlaying orm file that I can include in all of my orm files so I don't have to redundantly add them to every orm file?
Yes you can. It's quite simple.
TextItem:
columns:
topic: string(255)
Comment:
inheritance:
extends: TextItem
type: concrete
columns:
content: string(300)
More information: http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/yaml-schema-files.html -> inheritance / simple inheritance

Cascaded persist not working (Doctrine ORM + Symfony 2)

I started working with symfony several months ago and there is one thing keeps bothering me all the time. It is when I have a one-to-many relationship in Doctrine and I try to insert something into the database. Here's an example:
Broker.orm.yml
Acme\DemoBundle\Entity\Broker:
type: entity
table: brokers
repositoryClass: BrokerRepository
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
name:
type: string
length: 255
slug:
type: string
length: 64
oneToMany:
accountTypes:
targetEntity: Acme\DemoBundle\Entity\AccountType
mappedBy: broker
cascade: ["persist"]
AccountType.orm.yml
Acme\DemoBundle\Entity\AccountType:
type: entity
table: account_types
repositoryClass: AccountTypeRepository
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
name:
type: string
length: 255
slug:
type: string
length: 64
manyToOne:
broker:
targetEntity: Acme\DemoBundle\Entity\Broker
inversedBy: accountTypes
joinColumn:
name: broker_id
referencedColumn: id
Then is try to save it to the database like this.
$accountType = new AccountType();
$accountType->setName("blabla");
// additional data to accountType
$broker->addAccountType($accountType);
$em->persist($broker);
$em->flush();
The strange thing is that it works prefrectly with only one tiny problem. Broker is updated, and AccountType is inserted into the database but the accountType doesn't have any relations with the Broker. In other words, when I check in the database the broker_id fields reamains untouched and contains NULL.
If I add $accountType->setBroker($broker) manually, it works. But I started to use Sonata Admin Bundle where there is much more complicated to do this and I don't really need a complex admin system. So I just want a fast development on it and without this "feature" it's nearly impossible.
And anyways, if I add something to a collection of an Object, it should know which object is its parent, right? :)
Thanks for your help in advance!
class Broker
{
public function addAccountType($accountType)
{
$this->accountTypes[] = $accountType;
// *** This is what you are missing ***
$accountType->setBroker($this);

Use of "Container" as model name in Symfony

I have a entity called Container in a Symfony application, which I have included in the schema.yml file:
Container:
columns:
id: { type: integer, primary: true, autoincrement: true }
name: { type: string(127), notnull: true }
Strain:
columns:
id: { type: integer, primary: true, autoincrement: true }
...
container_id: { type: integer }
...
relations:
Container: { foreignAlias: Strains }
Then I have regenerated the models, forms and filters using the symfony doctrine:build --all-classes task.
Now when I try to use $strain->getContainer(), e.g. in a showSuccess action, it returns no object at all. I have double-checked that container_id has a reference to a record in container table.
Moreover, when I try to edit a Strain object and unlink the relationship with Container, the form is saved correctly, but the container_id column keeps the old value.
Do you know if Container is a reserved word or something like that in Symfony or Doctrine? What can be happening?
Thanks!
No, it isn't a reserved word.
(In fact, I have a model in my project with a Container relation).
Have you tried setting the local property on Container relation to container_id?

Doctrine : many to many with a date of assignation in the refclass

residentSector:
columns:
id_resident_sector:
type: integer
primary: true
autoincrement: true
id_resident:
type: integer(8)
id:
type: integer(8)
date:
type: timestamp
residents:
columns:
id_resident:
type: integer(8)
primary: true
autoincrement: true
firstname:
type: string(50)
lastname:
type: string(50)
relations:
Sectors:
class: Sectors
local: id_resident
foreign: id
refClass: residentSector
Sectors:
columns:
id:
type: integer(4)
primary: true
autoincrement: true
sector_name:
type: string(50)
id_resp:
type: integer(4)
visibility:
type: integer(1)
I want to select all the "residents" of a given "sector" at à given date (the lastest date as example).
My problem is the date field is in the refclass (because it's the date of assignation) so
->where('residents.Sectors.date =max(residents.Sectors.date) ')
won't work obviously because the refclass is not part of the collection ..
what is the good way to define the doctrine relation so i can get the latest sector in date of a resident ?
Thanks in advance !
Unfortunately Doctrine doesn't provide any built-in way to achieve what you're trying to do. However many-to-many relationship in fact uses double one-to-many relationship.
So what you need is to is:
Make correct DQL query:
Doctrine_Query::create()
->from('Residents r')
->innerJoin('r.XXX rs WITH rs.date = ?', '08-04-2010')
->innerJoin('r.Sector s');
Where XXX is the name of ResidentSector table. I'm not quite sure whether its name will be same as table name, but you can get its name from table definition generated by Doctrine.
After you execute the query you will have to do all the mapping by your own, using Doctrine_Record::mapValue.
I dont know how to use doctrine but having many to many relationships results in an abundance of duplicate data.
You should maybe have 3 tables (residents, sectors, residentsToSectors) have date assigned in the residentToSectors table and then grab the information for either resident or sector based on whatever data you insert in the WHERE clause?

Categories