doctrine/collections — pull request #28 by erik-am (2014-05-30 15:02:59+00:00)
Title: Expressions over Embeddables

Doctrine 2.5 will bring support for Embeddables. Embeddables are almost perfect for implementing [Value Objects](http://martinfowler.com/bliki/ValueObject.html) for doing Domain-Driven Development, but strict comparisons in Doctrine make this difficult. With Value Objects one can build rich and expressive domain models. It would be great if there was support for this in Collections.

The `ExpressionBuilder` currently contains the following notice: "You have to use scalar values only for comparisons". My proposal violates that. So it is the question if there should be proper support for Value Objects or not.

### Example of desired behaviour
```php
/** Embeddable **/
class Address {
private $street;
private $nr;

public function __construct($street, $nr) {
/* optionally validating input and setting variables */
}

/* getters, if required */
}

/** Entity **/
class User {
private $address;

public function getAddress() {
return $this->address;
}

public function setAddress(Address $address) {
$this->address = $address;
}
}
```
```php
$criteria = Criteria::create()->where(
Criteria::expr()->eq('address', new Address('High Street', 1))
);
$usersInTheSameHouse = $users->matching($criteria);
```
This will not work, because the equality operator will do a strict comparison. In other languages, one can override equals() and getHashcode() inside the Value Object itself to get the desired behaviour, but we cannot do that in PHP.

### Solutions

Currently, I think there are three solutions:

1. We can check if the argument that is passed to `eq()` is really an object with `is_object()`. If it's not an object, we do a strict comparison as before (`===`), otherwise we do a loose comparison (`==`).
However, _this could potentially break client code_! I don't think it should, because comparisons currently only allow scalar types, but you never know how clients use the code.

This option has one advantage. The same solution (loose/strict comparison based on object/scalar type) can be applied to methods of ArrayCollection ike `contains()` and `removeElement()`. Those methods currently do not provide the correct behaviour for Value Objects. But this is risky to change, because sometimes clients might want to only check the references. Perhaps it is an idea to introduce an optional boolean `$strict` as an argument for those functions?

2. Let comparing Value Objects remain impossible. Instead, let the client code compare the scalar properties of a Value Object. This feature is already discussed in #27.
However, this forces anyone using Value Objects to make the properties accessible through getters. It should not be neccessary for Value Objects that they expose their inner value. So I do not consider this a satisfiable solution.

3. My proposed solution is to introduce another operator that performs a loose comparison. I introduced a method `sim()` (i.e., similarity) with operator `~`.
This is the safest option, because it cannot break any client code.

I included 4 unit tests:

* 2 tests that cover the current behaviour of `eq()` and `neg()` for objects (reference checking). There was no test for that behaviour yet and I think it's important to make it explicit.
* 2 tests for the new expressions `sim()` and `nsim()`.

Of course support to DQL should be added for sim() and nsim(). I think the DQL implementation should transform sim() to an AND of eq()s for each property of the Value Object. (This looks like the second solution listed above. For DQL this is possible, because when querying, it is always possible to compare the inner properties of a Value Object. In fact, the Embeddable does not even exist in the database.)

I look forward to hearing your thoughts on this matter. Do you think this can work? Or is there a better solution?