Search code examples
doctrine-ormentitydql

Doctrine 2 edit DQL in entity


I have several database tables with 2 primary keys, id and date. I do not update the records but instead insert a new record with the updated information. This new record has the same id and the date field is NOW(). I will use a product table to explain my question.

I want to be able to request the product details at a specific date. I therefore use the following subquery in DQL, which works fine:

WHERE p.date = (
    SELECT MAX(pp.date)
    FROM Entity\Product pp
    WHERE pp.id = p.id
    AND pp.date < :date
)

This product table has some referenced tables, like category. This category table has the same id and date primary key combination. I want to be able to request the product details and the category details at a specific date. I therefore expanded the DQL as shown above to the following, which also works fine:

JOIN p.category c
WHERE p.date = (
    SELECT MAX(pp.date)
    FROM Entity\Product pp
    WHERE pp.id = p.id
    AND pp.date < :date
)
AND c.date = (
    SELECT MAX(cc.date)
    FROM Entity\ProductCategory cc
    WHERE cc.id = c.id
    AND cc.date < :date
)

However, as you can see, if I have multiple referenced tables I will have to copy the same piece of DQL. I want to somehow add these subqueries to the entities so that every time an entity is called it adds this subquery.

I have thought of adding this in a __construct($date) or some kind of setUp($date) method, but I'm kind of stuck here. Also, would it help to add @Id to Entity\Product::date?

I hope someone can help me. I do not expect a complete solution, one step in a good direction would be very much appreciated.


Solution

  • I think I've found my solution. The trick was (first, to update to Doctrine 2.2 and) using a filter:

    namespace Filter;
    
    use Doctrine\ORM\Mapping\ClassMetaData,
        Doctrine\ORM\Query\Filter\SQLFilter;
    
    class VersionFilter extends SQLFilter {
        public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) {
            $return = $targetTableAlias . '.date = (
                SELECT MAX(sub.date)
                FROM ' . $targetEntity->table['name'] . ' sub
                WHERE sub.id = ' . $targetTableAlias . '.id
                AND sub.date < ' . $this->getParameter('date') . '
            )';
    
            return $return;
        }
    }
    

    Add the filter to the configuration:

    $configuration->addFilter("version", Filter\VersionFilter");
    

    And enable it in my repository:

    $this->_em->getFilters()->enable("version")->setParameter('date', $date);