DDC-2727: "Expression" or "Update" API, similar to the Criteria API #3469

Open
doctrinebot opened this Issue Oct 7, 2013 · 2 comments

2 participants

@doctrinebot

Jira issue originally created by user mnapoli:

I created a discussion in the mailing list (https://groups.google.com/forum/#!topic/doctrine-dev/7HfEqOwhkDk) but no answer, so I'm moving the discussion here.


The Criteria API provides an abstraction to filter collections/repositories, may they be in memory (filtering in PHP) or in a database (filtering using a SQL query).

I was thinking about an "Expression" API which would work like array_map to apply changes in bulk to entities.

For example, if you have a collection where entities have a $position field, if I insert an item in the list, I have to increment the position of all the following items. For this, I have 2 options:

  • PHP: loading the entities in memory, iterate over them and increment $position
  • SQL: run a UPDATE position=position 1 WHERE …

The second option is much more efficient, but it breaks the abstraction of the model because I have some behavior written explicitely in SQL. Furthermore, the objects loaded in memory will note be updated with the SQL query.

So the "Expression" API would work like the Criteria API:

interface Updatable {
    public function apply(Expression $e);
}

$expression = new Expression();

// For each item after position "10"
$expression->criteria->where(Criteria::expr()->gt('position', 10));
// Increment the position
$expression->set('position', 'position </ins> 1');

$collection->map($expression);

The expression here would be applied:

  • in memory if the collection is already loaded
  • else in database using SQL

The expression could be applied to a Collection and to a Repository (like the Criteria).


About the API offered by the Expression class, there are several options:

// Option 1
// More powerful, but needs to parse and evaluate the string
class Expression
{
    public $criteria;
    public function set($field, $value);
}

$expression->set('position', 'position + 1');

// Option 2
// Easier to implement, more limited
class Expression
{
    public $criteria;
    public function setValue($field, $value);
    public function setValueFromField($targetField, $sourceField);
    public function add($field, $number);
    public function multiply($field, $number);
    public function divide($field, $number);
}

// Option 3
// Like option 2 but more extensible
class Expression
{
    public $criteria;
    public function set($field, Operation $operation);
}

I think I like the third one better because we have full control over the supported operations, and adding support to new kinds of operation is easy. The first one would require defining a whole language of allowed expressions...


What do you think of all that?

@doctrinebot

Comment created by mnapoli:

Added option 3 after trying to write a POC

@doctrinebot

Comment created by mnapoli:

Here is a POC on the doctrine/collections side: mnapoli/collections@master...feature;Updatable works with ArrayCollection

I'm looking at the ORM side.

Feedback welcome, especially with the class/namespace/method names.

@beberlei beberlei was assigned by doctrinebot Dec 6, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment