8

I'm trying to practice a good design and extending Doctrine entity. My extended class, the model basically, will have extra business logic + access to the entity basic data.

I am using Doctrine 2.2.1 & Zend Framework 1.11.4 & php 5.3.8

When I use DQL, doctrine return successfully the Model entity. When I use Doctrine native find() function, it returns nothing :(.

HELP...

This is how it rolls:

Bootstrap.php:

    $classLoader = new \Doctrine\Common\ClassLoader('Entities', APPLICATION_PATH.'/doctrine');
    $classLoader->register();
    $classLoader = new \Doctrine\Common\ClassLoader('Models', APPLICATION_PATH);
    $classLoader->register();

Model in APPLICATION_PATH\models\User.php:

namespace Models;
use Doctrine\ORM\Query;

/**
 * Models\User
 *
 * @Table(name="user")
 * @Entity
 */
class User extends \Entities\User {

public function __wakeup() {
    $this->tools = new Application_App_Tools();
}

Entity retrieval functions:

DOESN'T WORK:

$userEntity = $registry->entityManager->find('Models\User', $userEntity);

WORKS:

$qry = $qb
        ->select('u')
        ->from('Models\User','u'); 
ohadwkn
  • 151
  • 1
  • 6

3 Answers3

4

You shouldn't add the business logic to the entities, you should use models for that instead. One way of doing it would be:

  1. Use models for business logic.
  2. Create custom Doctrine 2 repositories for your all your database queries (DQL or otherwise) [1].
  3. Leave your entities alone.

In practise this means that models are plain PHP classes (or maybe framework extended depending on what your're using) but your models have no relation to your database. Your models do however, instantiate your custom Doctrine 2 repositories. E.g. a UserRepository might contain a method called getUserById. Within your repositories is where your run your actual queries and return entity instances for the models to work with.

[1] http://docs.doctrine-project.org/en/latest/reference/working-with-objects.html#custom-repositories

Luke
  • 20,878
  • 35
  • 119
  • 178
1

As I understand Doctrine, entityManager is responsible only for persistent entities, and extending Entities\User entity with Model\User will create another entity (stored in same table as stated in docblock), but not managed by entityManager or in collision with it because you probably didn't mention @InheritanceType("SINGLE_TABLE") in Entities\User docblocks:

Read this docs for more info http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html

Ivan Hušnjak
  • 3,493
  • 3
  • 20
  • 30
  • The MappedSuperclassBase should be the basis of any other entity, defines their common properties and methods, children classes are concrete entities... Example: GeneralUser is superclass with common fields, Editor and Supervisor extend it with their specific fields like Editor.assignedTopics or Supervisor.topicsToCheckout... hope it helps – Ivan Hušnjak Aug 29 '12 at 14:54
  • Thanks for the comment. Relating to my specific need: the MappedSuperclassBase should hold business logic? Basically, The main purpose is to have an entity class that the Doctrine CLI can rewrite & update according to the YAML defenitions. And I want to be able to add business functions with Zend abilities to an extending class without worry about the synchronization and merge. If I may, how would you tackle this issue? – ohadwkn Aug 29 '12 at 14:54
  • I deleted & edited the first comment, but I didn't see you answer. sorry. anyways, I do not need this functionality. I want to add specific function to a specific entity. relating to my example, that the User class would have functions that'll be performed on the User. such as sendPushNotifications, etc. – ohadwkn Aug 29 '12 at 14:55
  • 2
    So you want to have all the storage/crud logic in your Entities\User and all the business logic in Models\User? In that case there is no reason to keep your model handled by Doctrine entityManager since it obviously is not an entity. Have your model rather use the entity instead of extending it like: $model = new Models\User($entity); $model->doSomeBusinessLogic(); – Ivan Hušnjak Aug 29 '12 at 16:50
  • yeah, that's the solution I went for. I just wanted to save the `$model = new Models\User($entity);` and make the code much more elegant.. appreciate the help! – ohadwkn Aug 29 '12 at 18:05
  • @ohadwkn It would be great if you would share your solution code example in here (just edit your question), so others having same/similar problems and concerns may find it useful – Ivan Hušnjak Sep 02 '12 at 20:06
  • @IvanHušnjak Only problem with your approach is that it tightly couples the business logic and database storage. I'm Still trying to find a solution for this myself... – alvinc Feb 20 '14 at 21:08
0

What I tried to do was a bad practice. I coupled my DB entity and tools from zend as @Ivan Hušnjak mentioned.

What should be done is de-coupling.

Business logic should be in services\controller and these should address the entity and it's methods. you can\should add helper functions to the doctrine entity that only relates to the entity properties.

Regarding my main purpose (to have an entity class that the Doctrine CLI can rewrite & update): doctrine only searches from changes in the native fields\methods, updates them accordingly and discard all other functions (helpers). so there is no problem when letting doctrine update the php entity!

p.s. move to symfony2.

ohadwkn
  • 151
  • 1
  • 6
  • «Business logic should be in services\controller» – very bad idea. Business logic should be in your models as much as it possible. Can't figure out what was your reason to separate models and entities. Why not just to put your business logic into doctrine entities that (to be honestly) are your models exactly. – zelibobla Aug 01 '13 at 15:33
  • @zeliboba I agree putting business logic in controllers is a bad idea, It's just messy. As for separating entities and business logic, every resource I've come across states that you should NOT add business logic to entities. It apparently is bad for your entities especially as they grow but I don't understand why this is the case TBH. – alvinc Feb 20 '14 at 21:23
  • OK, I see multiple suggestions - trying to do something similar. In my case, a good example would be I have a User entity mapped one-to-many with an Address entity. Some fields are similar across both but they aren't really extensions of each other - i.e. they share 'name' fields, phone number, email address. I would like a function to create a new address for a given user that will pre-populate those similar fields (possibly to be changed later). I see examples adding functions like this to the entity, to models, to mappers. What is the best-practices? – Scott Dec 18 '14 at 20:40