Which design pattern should I use to wrap common method to entities? - php

I'm a PHP Developer, and I'm working with Symfony2 at the moment.
I would like to present my issue as follow:
I have 4 entities: User, Account, Customer, Merchant. All of them have status.
I want to build a common method named 'isValid' for them, but don't want to modify their code.
The method logic is very simple
<!-- language: php -->
public function isValid()
{
return self::STATUS_ACTIVE == $this->status;
}
By separate them and apply a HAS-A relation between it with entities, I think it will more flexible and maintainable. I don't have to duplicate my code to any entity need it, even in the future.
If you have experience. Could you please help me to pick a suitable pattern for this situation?

Creating a has-a relation between these entities makes no sense, since they are not related.
However, code duplication is almost never justifiable. I would solve it by creating a common interface (User is-a Validatable entity, Customer is-a Validatable entity) and make a trait to encapsulate the common behavior.
Create the common interface:
interface Validatable
{
public function isValid(): bool;
}
Create a trait to implement the common behaviour:
trait HasStatus
{
/**
* #var int
* #ORM\Column(type="integer")
*/
private $status;
public function isValid(): bool
{
return $this->status === EntityStatus::STATUS_ACTIVE;
}
}
Make your entities implement the new interface and put the trait to use to avoid duplication:
class User implements Validatable {
use HasStatus;
}
And use it:
/** #var Validatable[] $validatables */
$validatables = [new User(), new Merchant(), new Customer()];
foreach ($validatables as $validatable) {
var_dump($validatable->isValid());
}
Why do we need the interface? Well technically we do not need it, but I like to include it because it allows to refer to User, Customer, Merchant with a common "Validatable" typehint and it conveys your intention in code.

Messing with this it's not a good idea, the entity has status value, and setters/getters should be in entity file declaration.
I understand the DRY principle but doing it on this level... it's IMHO not a good idea.
But if you are sure that all of them have status, then use a trait in a separate file:
trait CheckStatusTrait{
return $this->status;
}
And you just add the trait to your classes:
class User {
use CheckStatusTrait
}

For that simple kind of code, it would be okay do leave it duplicated in each entity, you can add an interface with "isValid" to treat them like the same from outside if necessary.
Maybe your code to check Validation would become more complex and it makes sense to have a single class which is responsible.
Then you could make a StatusValidator class which checks if the status of a given object ist valid. It would make sense to add an interface to that kind of objects, which has a "getStatus" method, let's say the "getStatusInterface". Afterwords you can inject the StatusValidator and use it in your isValid method. Because your objects are entities, you need to use doctrine's postLoad event to inject the StatusValidator.
You also can do the same i little bit less complex by not inject the StatusValidator but ask the StatusValidator if the obejct with the getStatusInterface is valid.

Thank all for the supports. I'm also using trait to solve code duplication. However, I see that trait seem to be not a perfect one. I had to fact to disadvantages below:
Hiding the field in trait makes entity enigmatic. In real, not only will status field is available on many entities but also updatedDate, createdDate, type... It also looks mess when a class use many traits.
After a development period, the trait collects more and more method, for ex. StatusTrait can have isValid, hasStatus, setStatusDefault. But not all of entities use them. I mean some entities use isValid, some use setStatusDefault.., so we will have more mixed methods in traits. In this issue, I think that if I can implement a HAS-A relationship class, I can easily setup them at the runtime when an entity need.
By using trait, the entity class is modified, not extension. It isn't a good practice in OOP design. The entity class isn't consistent to reference with database table. Honestly, I prefer to build logic method outside the entity class.
Aboves are my vision. I only try to find a better way to implement this issue. I hope it's also useful for everyone. I had hear about ValueObject but not really understand it obviously. I will try to figure it out!

Related

How to avoid implicit dependencies between Service class and Model class in PHP

If I have a site design which follows a dependency flow of:
Handler Class <-> Service Class <-> Mapper Class <-> Model Class
Handler receives the request, Service contains the logic, Mapper performs the DB queries and uses the Model to work on the data, while the Model represents a single record in the DB.
Ideally, you would have explicitly defined dependencies on/from the neighboring layers. So if I change a particular layer, only the two immediately neighboring layers might be affected.
However, I realized I may be using some bad practices. In particular, I have the Service class call a method on the Mapper class. The Mapper class would return an instance of the Model class. But if I then call a method of the Model class, from within the Service class, there is now a direct and implicit dependency between the Service class and the Model class.
I have a few thoughts on how to address this, which I'll outline below. But I feel there has got to be a better way. So I'm curious what the general consensus is on avoid these implicit dependency situations while avoiding unnecessary processing.
Inject an empty instance of the Model into the Service class to make the dependency explicit. But this seems clunky and doesn't account for multi-record result sets.
Specify the Model interface as the return type in the Mapper Interface for that method. To me, this seems like the preferred method. However, it gets complicated when you have to return multi-record result sets. I would rather not unnecessarily iterate through the entire result set within the Mapper class, before I even begin to use the results for the actual application logic. At a minimum, that would be O(2n) time complexity for nearly every query. So I've just been returning an object which is an \Iterable and iterating over that within the Service class (so O(n) is the floor instead of O(2n)). But this is the same situation where there is an implicit dependency on the Model class.
I've been trying to find out if it's possible to specify the type of object the \Iterable will iterate over, like you can with arrays (IE: int[] is an array of integers). The best I could come up with was to create a custom Iterator class specific to the Model class. Is this the preferred method of eliminating these implicit dependencies, while avoiding unnecessary loops?
Much appreciation!
Edit based on feedback:
I don't have any code which fails, and this question isn't meant to be specific to any real code. This question is solely about an abstract problem. That is why no code was originally included. But based on feedback I've drafted up the following to help make the purposed situation more clear.
Just ignore the Handler class, it's not needed to illustrate the concept, I was just trying to describe the overall structure with it to make it easier to identify the design pattern.
The Service class:
namespace App\Service;
class Service implements ServiceInterface
{
protected mapperInterface $mapper;
public function __construct(mapperInterface $mapper){
$this->mapper = $mapper;
}
public getAllRows() {
$iterator = $this->mapper->getAllRows();
while($iterator->valid()){
$current = $iterator->current();
// This line creates an implicit dependency on the Model class
$name = $current->getName();
$iterator->next();
}
}
}
The Mapper Class:
namespace App\Mapper;
class Mapper implements MapperInterface
{
protected modelInterface $modelPrototype;
public function __construct(modelInterface $model){
$this->modelPrototype = $model;
}
public getAllRows() : Iterator {
// Execute SQL then hydrate into an iterator over multiple "Model" objects into a variable ($resultSet in this case)
return $resultSet; // This is an Iterator instance of which each iteration contains a "Model" object.
}
}
The Model class:
class Model implements ModelInterface
{
protected string $name;
public function getName() : string {
return $this->name;
}
public function setName(string $name) : void {
$this->name = $name;
}
}
It is specifically this line in the Service class which creates an implicit dependency between the Service class and the Model class (bypassing the transitive dependency through the Mapper class):
$name = $current->getName();
There are two ways to correct this, either make the dependency explicit, or eliminate the dependency in the first place. I've listed my ideas on how to achieve those two options. But I am curious what the most common solution to this situation is. Is there some other option or method of addressing this which I have not thought of? Or is one of my proposed ideas the generally preferred method.
Technically i also don't see a dependency. The Service ask it's neighbour Mapper for a collection of Model and it provides one. The Mapper uses the Model and hydrates the data from whereever. So communication-wise everything is fine.
If you would access data in your Service with
$this->mapper->model->someModelMethod();
instead of
$this->mapper->getAllRows();
only then you would violate something at least in the sense of the law of demeter.
The dependency on the level you might think having an issue is probably some kind of tight coupling inside your layers, which is generally okay for this use case.
If you wanna decouple it between layers/modules/units consider introducing another kind of data container to pass around.
For example using some kind of Transfer Object and map/hydrate the data from your model to it. This transfer object can be used to pass around e.g. on the communication layer like Controllers, Services etc. You only rely on the transfer objects properties but not on the model itself. Only your mapper has to be adapted if something changed on both the Model and the Transfer Object

What is the purpose of using traits to define functions for an interface

Sorry if this is a duplicate question or a common design principle, I have searched around but was unable to find any answers to this question. I'm probably just searching with the wrong keywords.
I have been looking at a popular library Sabre/Event (https://sabre.io/event/) and in the code there is a simple class/inheritance model that I am trying to understand:
The class EventEmitter implements EventEmitterInterface and uses EventEmitterTrait (see below for code).
There is a comment in EventEmitterTrait above the class which says:
* Using the trait + interface allows you to add EventEmitter capabilities
* without having to change your base-class.
I am trying to understand why this comment says this, and why it allows adding capabilities without changing the base class, and how that is different from just putting the routines into EventEmitter itself.
Couldn't you just extend EventEmitter and add capabilities in the derived class?
Simplified code:
// EventEmitter.php
class EventEmitter implements EventEmitterInterface {
use EventEmitterTrait;
}
// EventEmitterInterface.php
interface EventEmitterInterface {
// ... declares several function prototypes
}
// EventEmitterTrait.php
trait EventEmitterTrait {
// ... implements the routines declared in EventEmitterInterface
}
You're basically asking two questions here.
What are interfaces and why are they useful?
What are traits and why are they useful?
To understand why interfaces are useful you have to know a little about inheritance and OOP in general. If you've ever heard the term spaghetti code before (it's when you tend to write imperative code that's so tangled together you can hardly make sense of it) then you should liken that to the term lasagna code for OOP (that's when you extend a class to so many layers that it becomes difficult to understand which layer is doing what).
1. Interfaces
Interfaces diffuse some of this confusion by allow a class to implement a common set of methods without having to restrict the hierarchy of that class. we do not derive interfaces from a base class. We merely implement them into a given class.
A very clear and obvious example of that in PHP is DateTimeInterface. It provides a common set of methods which both DateTime and DateTimeImmutable will implement. It does not, however, tell those classes what the implementation is. A class is an implementation. An interface is just methods of a class sans implementation. However, since both things implement the same interface it's easy to test any class that implements that interface, since you know they will always have the same methods. So I know that both DateTime and DateTimeImmutable will implement the method format, which will accept a String as input and return a String, regardless of which class is implementing it. I could even write my own implementation of DateTime that implements DateTimeInterface and it is guaranteed to have that method with that same signature.
So imagine I wrote a method that accepts a DateTime object, and the method expects to run the format method on that object. If it doesn't care which class, specifically, is given to it, then that method could simply typehint its prototype as DateTimeInterface instead. Now anyone is free to implement DateTimeInterface in their own class, without having to extend from some base class, and provide my method with an object that's guaranteed to work the same way.
So in relation to your EventEmitter example, you can add the same capabilities of a class (like DateTime) to any class that might not even extend from DateTime, but as long as we know it implements the same interface, we know for sure it has the same methods with the same signatures. This would mean the same thing for EventEmitter.
2. Traits
Traits, unlike interfaces, actually can provide an implementation. They are also a form of horizontal inheritance, unlike the vertical inheritance of extending classes. Because two completely different class that do not derive from the same base class can use the same Trait. This is possible, because in PHP traits are basically just compiler-assisted copy and paste. Imagine, you literally copied the code inside of a trait and just pasted it into each class that uses it right before compile time. You'd get the same result. You're just injecting code into unrelated classes.
This is useful, because sometimes you have a method or set of methods that prove reusable in two distinct classes even though the rest of those classes have nothing else in common.
For example, imagine you are writing a CMS, where there is a Document class and a User class. Neither of these two classes are related in any meaningful way. They do very different things and it makes no sense for one of them to extend the other. However, they both share a particular behavior in common: flag() method that indicates the object has been flagged by a user for purposes of violating the Terms of Service.
trait FlagContent {
public function flag(Int $userId, String $reason): bool {
$this->flagged = true;
$this->byUserId = $userId;
$this->flagReason = $reason;
return $this->updateDatabase();
}
}
Now consider that perhaps your CMS has other content that's subject to being flagged, like a Image class, or a Video class, or even a Comment class. These classes are all typically unrelated. It probably wouldn't make much sense just to have a specific class for flagging content, especially if the properties of the relevant objects have to be passed around to this class to update the database, for example. It also doesn't make sense for them to derive from a base class (they're all completely unrelated to each other). It also doesn't make sense to rewrite this same code in every class, since it would easier to change it in one place instead of many.
So what seems to be most sensible here is to use a Trait.
So again, in relation to your EventEmitter example, they're giving you some traits you can reuse in your implementing class to basically make it easier to reuse the code without having to extend from a base class (horizontal inheritance).
Per Sabre's Event Emitter's docs on "Integration into other objects":
To add Emitter capabilities to any class, you can simply extend it.
If you cannot extend, because the class is already part of an existing
class hierarchy you can use the supplied trait.
So in this case, the idea is if you're using your own objects that already are part of a class hierarchy, you may simply implement the interface + use the trait, instead of extending the Emitter class (which you won't be able to).
The Integration into other objects documentation says:
If you cannot extend, because the class is already part of an existing class hierarchy you can use the supplied trait".
I understand it's a workaround when you already have an OOP design you don't want to alter and you want to add event capabilities. For example:
Model -> AppModel -> Customer
PHP doesn't have multiple inheritance so Customer can extend AppModel or Emitter but not both. If you implement the interface in Customer the code is not reusable elsewhere; if you implement in e.g. AppModel it's available everywhere, which might not be desirable.
With traits, you can write custom event code and cherry-pick where you reuse it.
This is an interesting question and I will try to give my take on it. As you asked,
What is the purpose of using traits to define functions for an interface ?
Traits basically gives you the ability to create some reusable code or functionality which can then be used any where in your code base. Now as it stands, PHP doesn't support multiple inheritance therefore traits and interfaces are there to solve that issue. The question here is why traits though ?? Well imagine a scenario like below,
class User
{
public function hasRatings()
{
// some how we want users to have ratings
}
public function hasBeenFavorited()
{
// other users can follow
}
public function name(){}
public function friends(){}
// and a few other methods
}
Now lets say that we have a post class which has the same logic as user and that can be achieved by having hasRatings() and hasBeenFavorited() methods. Now, one way would be to simply inherit from User Class.
class Post extends User
{
// Now we have access to the mentioned methods but we have inherited
// methods and properties which is not really needed here
}
Therefore, to solve this issue we can use traits.
trait UserActions
{
public function hasRatings()
{
// some how we want users to have ratings
}
public function hasBeenFavorited()
{
// other users can follow
}
}
Having that bit of logic we can now just use it any where in the code where ever it is required.
class User
{
use UserActions;
}
class Post
{
use UserActions;
}
Now lets say we have a report class where we want to generate certain report on the basis of user actions.
class Report
{
protected $user;
public function __construct(User $user)
{
$this->user = $user
}
public function generate()
{
return $this->user->hasRatings();
}
}
Now, what happens if i want to generate report for Post. The only way to achieve that would be to new up another report class i.e. maybe PostReport.. Can you see where I am getting at. Surely there could be another way, where i dont have to repeat myself. Thats where, interfaces or contracts come to place. Keeping that in mind, lets redefine our reports class and make it to accept a contract rather than concrete class which will always ensure that we have access to UserActions.
interface UserActionable
{
public function hasRatings();
public function hasBeenFavorited();
}
class Report
{
protected $actionable;
public function __construct(UserActionable $actionable)
{
$this->actionable = $actionable;
}
public function generate()
{
return $this->actionable->hasRatings();
}
}
//lets make our post and user implement the contract so we can pass them
// to report
class User implements UserActionable
{
uses UserActions;
}
class Post implements UserActionable
{
uses UserActions;
}
// Great now we can switch between user and post during run time to generate
// reports without changing the code base
$userReport = (new Report(new User))->generate();
$postReport = (new Report(new Post))->generate();
So in nutshell, interfaces and traits helps us to achieve design based on SOLID principles, much decoupled code and better composition. Hope that helps

MVC: Having static method in models

Concise: How I can avoid using static methods in a model?
Loquacious: Suppose I have a user class. Having userID I can get user name by (new user($userID))->getUserName(). Fine, what if I want to lookup a user? (new user())->lookup($uname, $pass). Still fine, but the latter case could be done via a simple static method user::lookup($uname, $pass)!
Some thoughts:
It's OK! Use (new object())->method() whenever you want. So should I create a hollow object to call a function?
Move this function out of your model. If it needs a DB lookup, where is better than Model context?
Define it as a static method. So isn't it lame to have a mixture of public and static methods in a class?
Side note: I've searched this question, no avail!
Move this function out of your model. If it needs a DB lookup, where is better than Model context?
Yes, indeed, this is the best way to solve the problem.
Currently your User class violates single responsibility principle which basically, says "one task - one class".
Right now your User describes user entity/state and handles persistence (in your case - retrieval from database). See, two things.
I suggest you create another class that is going to handle persistence tasks, like add/update/delete user. The simplest solution is to create a primitive repostitory, like this:
<?php
class UserRepository
{
public function addUser(User $user);
public function updateUser(User $user);
public function deleteUser(User $user);
public function getUserById($id);
}
Then retrieval of user can be done in the following manner:
// get an instance of this repository class
$userRepository = new UserRepository;
// ask it to find and return user from the database by ID
$user = $userRepository->getUserById($_GET['id']);
Easy to read, easy to handle, right?
This UserRepository class is actually a primitive implementation of Repository Pattern. UserRepository emulates an in-memory collection of all of your users, hiding implementation inside. It hides actual persistence mechanism from you as user: imagine, your coleague would write this class and you're just using its methods, like UserRepository::getById(1) - you don't even know/care if it grabs data from files/db/API. That's neat. )
This particular implementation is described very clearly in Kristopher Wilson's book "The Clean Architecture in PHP", which I highly recommed for you to read: it will take you two-three evenings, and push you to the next level.
You can extend the list of methods, of course, add lookups, etc.
class UserRepository
{
public function getByCompany(Company $company);
public function getByEmail($email);
public function countTotal();
}
In fact, every time you need to grab/add/update user in the database, you should do it via this repository.
I would like to emphasize that this is a simple implementation of the pattern, particularly, if you compare it to what Martin Fowler describes as Repository. However, in most cases it's totally fine.
It's OK! Use (new object())->method() whenever you want. So should I create a hollow object to call a function?
depends on how much creating an instance will cost
Move this function out of your model
Factory Pattern comes in mind here.
notes here:
What happens when $userID in the first call do not exists?
Isnt your lookup() method not creating 2 instances at one call, first for lookup, second the found one that is returned?
A FactoryPattern for example can have findByID() or findByName() and return an UserObject. And all that should not depend on this syntax at all: (new object())->method(), that is nice, but not always best practise.

Trait inheritance checking PHP

So ive finally gotten round to playing with traits and they are very handy, the problem that i have been having is that i want to have some traits to add functionality to my data objects.
In of itself this is simple except that in doing so im using methods that are defined in my base data object
abstract class Base_Object {
protected function _addToUpdate($field, $value) {
...
}
...
}
trait Extended_Object {
public function doSomeStuff() {
...
$this->_addToUpdate($someVar, $someOtherVar);
}
...
}
class User extends Base_Object {
use Extended_Object;
...
}
My problem is then if someone else in my team decides to use the Extended_Object trait on an object that doesnt extend Base_Object. I had thought about putting a check in the _addToUpdate method but ideally i would like an error to be shown when creating the instance.
I have come up with a solution that works but makes me feel a bit dirty and is far from ideal
abstract class Base_Object {
protected function _addToUpdate($field, $value) {
...
}
...
}
trait Extended_Object {
abstract protected function _addToUpdate($field, $value);
public function doSomeStuff() {
...
$this->_addToUpdate($someVar, $someOtherVar);
}
...
}
class User extends Base_Object {
use Extended_Object;
...
}
By adding an abstract method to the Extended_Object i then can at least be sure that an error will be show if the method i need in Base_Object isnt present but i am not guaranteed that the method in question will actually do what i want it to do.
Ideally i would like to be able to run something like the code below when an object is instantiated using the Extended_Object trait
if (!($this instanceof Base_Object)) {
throw new Inheritance_Exception("Base_Object");
}
Im hoping that someone has found a way to do this or at least a better solution than mine.
Note: i know that i could do this with a constructor but that would only be viable when using a single trait if i decided at a later date to create anther few object extension traits its going to get very messy very quickly
Edit: i do realize that traits arnt really designed for what im trying to do but they do at least in part allow me to get around the problem of single inheritance and i know im not the only dev planning to use them in this way
Well (IMHO) the problem exists with the way you are using traits which is technically anti-pattern.
First, What are traits and why should I use them:
To quote from one of the comments in php.net
The best way to understand what traits are and how to use them is to
look at them for what they essentially are: language assisted copy
and paste.
If you can copy and paste the code from one class to another (and
we've all done this, even though we try not to because its code
duplication) then you have a candidate for a trait.
Now even that traits lets you use members of the class which is using them, that does not mean you should do that. back to SRP, this is a real violation.
PHP lets you do echo $_POST['XSS data'] but that does not mean you should do it. So, regardless to the way you want to strict your trait usage, what you are actually doing is that you are introducing the issue and you are trying to solve it
so to answer your question, simply redesign your code in order for you not to use class methods and members based on an assumption that each class which will use the trait should have these methods and members.
I think your solution with an abstract function is precisely what that facility is intended for. I agree with your gut feeling:
i am not guaranteed that the method in question will actually do what i want it to do
However, this is the same assumption you make whenever you use an interface: the only thing that is asserted is that a method exists with the correct signature (which in PHP amounts mostly to its name and number of parameters). There is no way to know that the function actually behaves in a particularly useful way when given those parameters.
In the case of a trait, an abstract method is effectively the same kind of contract as an interface: "in order to use this trait, you must provide these pre-requisites".
I would also note that common description of traits is "automated copy and paste", so it should generally be thought of as separate from object hierarchies. More technically, it represents "horizontal code reuse", not "multiple inheritance". For example, you can define a trait that allows a class to implement an interface, but to the outside code, it is the interface that is important, not the trait.
I am faced with a similar problem, however with multiple subclasses inheriting from the base class.
It would make sense at this point to put trait abstract declarations into some sort of include file and as a trait itself, e.g.:
abstract class Base_Object {
use BaseObjectTrait;
...
}
trait BaseObjectTrait {
protected function _addToUpdate($field, $value) {
...
}
}
trait BaseObjectTraitPrototypes {
abstract protected function _addToUpdate($field, $value);
}
trait Extended_Object {
use BaseObjectTraitPrototypes;
public function doSomeStuff() {
...
$this->_addToUpdate($someVar, $someOtherVar);
}
...
}
class User extends Base_Object {
use Extended_Object;
...
}
Can anyone think of a more elegant solution than this? I'm using the term 'prototype' very loosely here from a C programming sense. 'Header' files are likewise from a C programming context but still not ideal. Can anyone think of a more concise concept for the problem domain, something php-fig acceptable perhaps?
My problem is then if someone else in my team decides to use the Extended_Object trait on an object that doesnt extend Base_Object.
:
Ideally i would like to be able to run something like the code below when an object is instantiated using the Extended_Object trait
if (!($this instanceof Base_Object)) {
throw new Inheritance_Exception("Base_Object");
}
Maybe I'm missing something, but if this trait should only ever be applied to instances of Base_Object, then it sounds as if this "trait" should be a subclass of the Base_Object and not a trait at all?
The User class then extends this Extended_Object (a subclass), rather than useing the Extended_Object (a trait).
From: http://php.net/manual/en/language.oop5.traits.php
A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies.

Custom Collection in Doctrine2

Just starting to work with Doctrine2, and am wondering how/if I can use a custom collection class. Searches point me to this part of the documentation:
Collection-valued persistent fields and properties must be defined in terms of the Doctrine\Common\Collections\Collection interface. The collection implementation type may be used by the application to initialize fields or properties before the entity is made persistent. Once the entity becomes managed (or detached), subsequent access must be through the interface type.
While I'm sure that's crystal clear to someone, I'm a little fuzzy on it.
If I setup my Entity to initialize (say in __construct()) the collection variable to a class that implements the correct interface - will Doctrine2 continue to use that class as the collection? Am I understanding that correctly?
Update: Also, I gather from various threads that the placeholder object used in lazy loading may influence how a custom collection can be used.
Let me try to clarify what is possible, not possible and planned with examples.
The quote from the manual basically means you could have the following custom implementation type:
use Doctrine\Common\Collections\Collection;
// MyCollection is the "implementation type"
class MyCollection implements Collection {
// ... interface implementation
// This is not on the Collection interface
public function myCustomMethod() { ... }
}
Now you could use it as follows:
class MyEntity {
private $items;
public function __construct() {
$this->items = new MyCollection;
}
// ... accessors/mutators ...
}
$e = new MyEntity;
$e->getItems()->add(new Item);
$e->getItems()->add(new Item);
$e->getItems()->myCustomMethod(); // calling method on implementation type
// $em instanceof EntityManager
$em->persist($e);
// from now on $e->getItems() may only be used through the interface type
In other words, as long as an entity is NEW (not MANAGED, DETACHED or REMOVED) you are free to use the concrete implementation type of collections, even if its not pretty. If it is not NEW, you must access only the interface type (and ideally type-hint on it). That means the implementation type does not really matter. When a persistent MyEntity instance is retrieved from the database, it will not use a MyCollection (constructors are not invoked by Doctrine, ever, since Doctrine only reconstitutes already existing/persistent objects, it never creates "new" ones). And since such an entity is MANAGED, access must happen through the interface type anyways.
Now to what is planned. The more beautiful way to have custom collections is to also have a custom interface type, say IMyCollection and MyCollection as the implementation type. Then, to make it work perfectly with the Doctrine 2 persistence services you would need to implement a custom PersistentCollection implementation, say, MyPersistentCollection which looks like this:
class MyPersistentCollection implements IMyCollection {
// ...
}
Then you would tell Doctrine in the mapping to use the MyPersistentCollection wrapper for that collection (remember, a PersistentCollection wraps a collection implementation type, implementing the same interface, so that it can do all the persistence work before/after delegating to the underlying collection implementation type).
So a custom collection implementation would consist of 3 parts:
Interface type
Implementation type (implements interface type)
Persistent wrapper type (implements interface type)
This will not only make it possible to write custom collections that work seemlessly with the Doctrine 2 ORM but also to write only a custom persistent wrapper type, for example to optimise the lazy-loading/initialization behavior of a particular collection to specific application needs.
It is not yet possible to do this but it will be. This is the only really elegant and fully functional way to write and use completely custom collections that integrate flawlessly in the transparent persistence scheme provided by Doctrine 2.
No, whenever Doctrine gives you back an implementation of the Doctrine\Common\Collections\Collection interface, it will be a Doctrine\ORM\PersistentCollection instance. You cannot put more custom logic on the collection. However that is not even necessary.
Say you have an entity (Order has many OrderItems), then a method to calculate the total sum of the order should not be located on the collection, but on the Order item. Since that is the location where the sum has meaning in your domain model:
class Order
{
private $items;
public function getTotalSum()
{
$total = 0;
foreach ($this->items AS $item) {
$total += $item->getSum();
}
return $total;
}
}
Collections however are only technical parts of the ORM, they help to implement and manage references between objects, nothing more.
Same question here, with a reference to the official doctrine Jira issue page with the details and status of this 'feature'... You can keep track of the development there!

Categories