Multiple Level Discriminator Mapping Doctrine - php

I've got a 3 level table inheritance, and when I attempt to insert into the database, Doctrine is sensible enough to insert at the lowest level, and the highest level - but not at the middle level.
I'm unsure whether what we're attempting to do is properly supported by Doctrine - the lack of examples on the docs and Google suggest that it might not be. If it is supported, what could I be doing wrong?
EDIT:
A slightly better explanation:
I have 3 tables (A, B and C). I've got a discriminator map such that C extends B, and B extends A. When I try an insert into Table A then Doctrine is clever enough to insert into C and A, but not B.

Related

Access field of entity included in hidden join

Two entities, A and B, Bextends A. I'm interested in the field B.isOk.
I have this query that joins A with other entities(and because B extends A, if I look at the pure sql, a join is done between A and B even though it is not specified in the query builder-because of the inheritance, great-).
How can I then access that B.isOk if I only have A my query builder? I tried using INSTANCE OF but to no success.
In my yml for A there's specified :
inheritanceType: joined
discriminatorColumn:
name: type
type: text
discriminatorMap:
internal-b: \C\BBundle\Entity\B
Any other suggestions on how could I use that property? I could add an extra join but what's the point since the join I need is already happening behind the curtains.
One alternative to this would be to give up DQL and write my own SQL query.
since this can not be done because OOP principles, it means something might be wrong with my model so another solution would be to refactor the model and design a correct one that fits the current needs.

construct foreign classes from database in PHP

Firstly, it's not a problem to construct classes from a database, i.e. mysql, it's more a question about performance.
If I have a Class A which depends on class B.
class A
{
protected $depend;
public function __construct($id == null)
{
// construct from mysql/postgresql/...
}
}
And in the database has class A (say table "tbl_A") a foreign key to the table of class B (say "tbl_B"). Of course this classes are depending on much more than one table but i will simplify things here...
At the moment i construct class A from it's table:
select * from tbl_A where ID = $id
If they are successful, the statement of class A gives me something like that:
ID | Name | B_ID
1 | "test" | 3
After that i had to construct class B in it's constructor. Is there any possibility to only make one statement with a join in constructor of class A and construct class B from there? I thought this will increase the performance of my application. Badly i don't found any functionality like friend classes (c++, etc) and i want to let my properties of class B stay protected or private.
What is the largest performance overhead: MySQL/PostGre SQL or the PHP side?
If i understood correctly, for one instance of A, you have to do 2 queries (1 for A, one for the depended B). So for 1000 single instances of A, it makes 2000 queries total.
You can optimize your app to use "batch loading" of some kind. i.e. loading 1000 instances of A at once will be 1 query for A (1000 rows) + 1 query for B (1000 rows). So optimized from 2000 queries to just 2.
Your suggestion about joining tables is off course possible (join table A and table B on the correct keys and select all (needed) fields), but this would optimize from 2000 queries to 1000 queries plus your object-relation-mapping code would get more complicated.
It's really going to depend on how deep down the rabbit hole you want to go, but if you want to catch all 2 steppers, you can do this:
select tA1.* from tbl_A tA1 where tA1.ID = $id
UNION
select tA3.* from tbl_A tA3
LEFT JOIN tbl_A tA2 ON tA3.ID = tA2.B_ID
WHERE tA2.B_ID = $id
but then there's an issue if you need to go deep... this method becomes increasingly complex and less efficient than doing multiple queries (especially since a union is just making MySQL do it in that way).
Also once you've got them, you should loop through the list of ids you got and keep that in an array so you don't need to reload them.

Doctrine DQL, class table inheritance and access to subclass fields

I have a problem with a DQL query and entity specialization.
I have an Entity called Auction, which is OneToOne relation with Item. Item is a mappedSuperclass for Film and Book. I need a query that could back a search engine, allowing the user to look for auctions with different properties AND selling items with different properties (it is the AND part that makes it challenging).
The problem is that even though Auction has an association pointing to Item as such, I need to have access to Film- and Book-specific fields. The users will specify the Item type they're looking for, but I don't see any way of using this information other than using INSTANCE OF in my DQL query.
So far, I have tried using a query like:
SELECT a FROM Entities\Auction a
INNER JOIN a.item i
INNER JOIN i.bookTypes b
WHERE i INSTANCE OF Entities\Book
AND b.type = 'Fantasy'
AND ...".
Such a query results in an error saying that:
Class Entities\Item has no field or association named bookTypes
which is false for Book, yet true for Item.
I have also tried
SELECT a FROM Entities\Book i
INNER JOIN i.auction a ...
but I reckon Doctrine requires that I refer to the same Entity in SELECT and FROM statements.
If that's of importance, I am using class table inheritance. Still, I don't think switching to single table inheritance would do the trick.
Any ideas?
As Matt stated, this is an old issue that Doctrine Project won't fix (DDC-16).
The problem is that doctrine's DQL is a statically typed language that comes with a certain amount of complexity in its internals.
We thought about allowing upcasting a couple of times, but the effort to get that working is simply not worth it, and people would simply abuse the syntax doing very dangerous things.
As stated on DDC-16, it is also indeed not possible to understand which class the property belongs to without incurring in nasty problems such as multiple subclasses defining same properties with different column names.
If you want to filter data in subclasses in a CTI or JTI, you may use the technique that I've described at https://stackoverflow.com/a/14854067/347063 . That couples your DQL with all involved subclasses.
The DQL you would need in your case is most probably (assuming that Entities\Book is a subclass of Entities\Item):
SELECT
a
FROM
Entities\Auction a
INNER JOIN
a.item i
INNER JOIN
i.bookTypes b
WHERE
i.id IN (
SELECT
b.id
FROM
Entities\Book b
WHERE
b.type = 'Fantasy'
)
That is the pseudo-code for your problem. It is not nice, but keep in mind that SQL and DQL are very different and follow different rules.
Updated:
I've discovered a solution for this. See my answer for this related question:
Doctrine2: Polymorphic Queries: Searching on properties of subclasses
You can easily solve this by left-joining your base entity with your inheritance class using the id:
SELECT a FROM Entities\Auction a
INNER JOIN a.item i
INNER JOIN Entities\Book b WITH b.id = i.id
INNER JOIN b.bookTypes bt
WHERE bt.type = 'Fantasy'
AND...
or with a queryBuilder:
$queryBuilderb->select('a')
->from('Entities\Auction', 'a')
->innerJoin('a.item', 'i')
->innerJoin('Entities\Book', 'b', 'WITH', 'b.id = i.id')
->innerJoin('b.bookTypes', 'bt')
->where('bt.type = :type')
->andWhere(...
->setParameter('type', 'Fantasy');
This is based on the answer given by Ian Philips in the question here
The Doctrine team has stated that they're not going to add support for this:
https://github.com/doctrine/orm/issues/2237
Pertinent comments from that page:
Thats indeed tricky. That syntax alone can, however, never work,
because there might be several subclasses that have a field named "d",
so Doctrine would not know which field you mean.
I am closing this one.
The requirement of this issue is basically violating OO principles.
If you really need to filter across multiple child-entities in your
inheritance, then try something as following instead:
SELECT
r FROM
Root r WHERE
r.id IN (
SELECT
c.id
FROM
Child c
WHERE
c.field = :value
)
I had the same issue, and didn't find a solution without using separate queries for each subclass and merging them later on the application level.
One thing I'm sure, single table inheritance will not solve this, completely the same thing.
There is another alternative, although being logically dirty.
Define all the fields (the ones you need) in the superclass. If the record logically doesn't have that field it will be empty. Not a pretty sight, but hey, more optimized than 2-3-4-... queries. Also in this scenario single table inheritance is definitely the better way to go

doctrine query for chained one-to-many relationships

I have three tables A, B, C. A and B have a one-to-many relationship. B and C have another one -to-many relationship. In another word, each A can have multiple Bs, while each B can have multiple Cs.
Now I want to do a query for a given record of A, to get all the related Bs which have related Cs. In another word, for a given a, which is a record in table A, I want to get all of the related Bs from table B, providing that each of the Bs also has more than zero related Cs in table C.
How to write the statement in PHP doctrine? I have some code which doesn't work:
Doctrine_Query::create()->from('B b')->leftJoin('C c')
->andWhere('b.A_id = ?', a.id)->andWhere('c.b_id = b.id');
Why don't you just use an innerJoin ?
With Foo, Bar and Baz (respectively A, B and C) :
Doctrine_Query::create()
->from('Bar bar')
->where('bar.foo_id = ?', $foo->id)
->innerJoin('bar.Baz baz');
This way you'll only get Bar which belongs to Foo, and which have one or many Baz.
From my workings with Doctrine, this is not possible (Doctrine 1 is what I am speaking to).
The work around, which I know sucks, is to do multiple queries. IE take all of the B id's and use them in the whereIN clause and pull them up in a separate query. If someone else has a better method I would be interested in it :)
As premiso noted you need to write at least 2 queries. I would also do it the way he suggested (take all of B id's and use an IN).
To make it more Doctrine-line, look at DQL Subqueries. They already show an example that uses IN in connection with selecting ID`s.
edit: Reading DuoSRX's answer, I think you may have meant what he shows with Inner Joins but not quite sure if I understood the question correct.

PHP doctrine 1.2 ORM - polymorphic queries with class table inheritance

I'm experimenting with the Doctrine ORM (v1.2) for PHP. I have defined a class "liquor", with two child classes "gin" and "whiskey". I am using concrete inheritance (class table inheritance in most literature) to map the classes to three seperate database tables.
I am attempting to execute the following:
$liquor_table = Doctrine_Core::getTable('liquor');
$liquors = $liquor_table->findAll();
Initially, I expected $liquors to be a Doctrine_Collection containing all liquors, whether they be whiskey or gin. But when I execute the code, I get a empty collection, despite having several rows in the whiskey and gin database tables. Based on the generated SQL, I understand why: the ORM is querying the "liquor" table, and not the whiskey/gin tables where the actual data is stored.
Note that the code works perfectly when I switch the inheritance type to column aggregation (simple table inheritance).
What's the best way to obtain a Doctrine_Collection containing all liquors?
Update
After some more research, it looks like I'm expecting Doctrine to be performing a SQL UNION operation behind the scenes to combine the result sets from the "whiskey" and "gin" tables.
This is known as a polymorphic query.
According to this ticket, this functionality is not available in Doctrine 1.x. It is destined for the 2.0 release. (also see Doctrine 2.0 docs for CTI).
So in light of this information, what would be the cleanest, most efficient way to work around this deficiency? Switch to single table inheritance? Perform two DQL queries and manually merge the resulting Doctrine_Collections?
the only stable and useful inheritence mode of Doctrine for the moment is column_aggregation. I have tried the others in different projects. With column_aggregation you can imitate polymorphic queries.
Inheritance in general is something that is a bit buggy in Doctrine (1.x). With 2.x this will change, so we may have better options in the future.
I wrote the (not production ready) beginnings of an ORM that would do exactly what you're looking for a while back. Just so that I could have a proof of concept. All my studies did yield that you're in some way mixing code and data (subclass information in the liquor table).
So what you might do is write a method on your liquor class/table class that queries it's own table. The best way to get away with not having to hard-code all the subclasses in your liquor class is to have a column which contains the class name of the subclass in it.
How you spread the details around is entirely up to you. I think the most normalized (and anyone can correct me if I'm wrong here) way to do it is to store all fields that appear in your liquor class in the liquor table. Then, for each subclass, have a table that stores the specific data that pertains to the subclass type.
Which is the point at which you are mixing code and data because your code is reading the liquor table to get the name of the subclass to perform a join.
I'll use cars & bikes and some minimal, yet trivial differences between them for my example:
Ride
----
id
name
type
(1, 'Sebring', 'Car')
(2, 'My Bike', 'Bicycle')
Bicycle
-------
id
bike_chain_length
(2, '2 feet')
Car
---
id
engine_size
(1, '6 cylinders')
There's all kinds of variations from here forward like storing all liquor class data in the subclass table and only storing references and subclass names in the liquor table. I like this the least though because if you are aggregating the common data, it saves you from having to query every subclass table for the common fields.
Hope this helps!

Categories