Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weaknesses and forces of Doctrine 2 and Propel 1.6 [closed]

I would like to know what are the forces and weaknesses of Doctrine 2 and Propel 1.6. For instance, Doctrine 2 is really user friendly but limits you if you want to go beyond conformism. Doctrine 2 documentation lack of updates ...

If possible you can share your experience on where Doctrine2 was doing good or where Propel was perfect.

Thanks in advance.

like image 799
Geoffrey Brier Avatar asked Aug 19 '12 11:08

Geoffrey Brier


1 Answers

EDITED

I've just joined the chat to get some insights on this question. Let's make a resume:

Single Responsibility Principle

  • only Doctrine 2.x uses some of the DataMapper ideas
  • Developers still think that ActiveRecord is the ambrosia from gods
  • The inability to test separately from DB
  • Dependency Injection enemy

See: https://softwareengineering.stackexchange.com/questions/119352/does-the-activerecord-pattern-follow-encourage-the-solid-design-principles

Description

Propel is based on the ActiveRecord Pattern, and Doctrine, instead make use of Data Mappers and Virtual Proxies.

When I first learned about OOP with PHP, ActiveRecord was being widely used, most due the Ruby On Rails influence. Then the developers started realizing that ActiveRecord is a limited concept, specially for larger applications.

Why?

Think by yourself, is the responsibility of a domain model object to know how to save itself? Or even convert its data to the JSON format?

The answer is no, because it violates the Single Responsibility Principle (SRP) and the domain cohesion.

Martin defines a responsibility as a reason to change, and concludes that a class or module should have one, and only one, reason to change.

Let's say you have an Author entity. For which reasons would you change it? Well, if implemented using ActiveRecord, besides the need to change the object properties itself, you'll also need to change it if you implement a new type of persistence specific to that object, as we do when implementing cache strategies.

Also, let's say the Propel library changes the method of the model's base class (just a naive example). Now you have a reason to change other parts of your application that doesn't have nothing with persistence, since your entities are tight coupled with the ORM base class. In other words, your domain model objects should not depend on the specifics of each ORM Framework. You should be able to change your ORM letting your domain model objects untouched.

So active record requires your domain model to knows about the existence of a persistence layer. There are two responsibilities.

The worst thing when using Active Record, is that you "screw up" your domain model inheritance hierarchy. If you have a Human entity extending a base class for persistence purposes, and then a Man entity extending the Human entity, if for some reason you have another Woman entity extending the Human Entity without the ability to be persisted, then you will break the contract established by the base class which states that each entity needs to know how to save itself. You'll not be able to do $woman->save().

Strictly saying, it also leds to violations of the Liskov Substitution Principle

Finally, the ultimate reason to stop using ActiveRecord. Looking at the following code you'll be able to see that the ORM's responsibility of mapping objects to the storage during a transaction was delegated to a domain model entity:

class Book extends BaseBook
{
  public function postSave(PropelPDO $con)
  {
    $this->updateNbBooks($con);
  }

  public function postDelete(PropelPDO $con)
  {
    $this->updateNbBooks($con);
  }

  public function updateNbBooks(PropelPDO $con)
  {
    $author = $this->getAuthor();
    $nbBooks = $author->countBooks($con);
    $author->setNbBooks($nbBooks);
    $author->save($con);
  }
}

http://www.propelorm.org/documentation/06-transactions.html You must update this new column every time you save or delete a Book object; this will make write queries a little slower, but read queries much faster. Fortunately, Propel model objects support pre- and post- hooks for the save() and delete() methods, so this is quite easy to implement

So, in a single model entity you have:

  1. Persistence
  2. Intercepting Filter Pattern for pre and post saving/deleting
  3. Validation (http://www.propelorm.org/documentation/05-validators.html)
  4. Cache
  5. And there you go...
like image 109
Keyne Viana Avatar answered Oct 25 '22 06:10

Keyne Viana