Put business logic in entity
Asked Answered
F

1

13

I've read the Fowler's article about "Anemic Domain Model" (link: http://www.martinfowler.com/bliki/AnemicDomainModel.html), and I agree with his point of view.

I've tried to create an application where Entities are simple POPO, but in this way, I have a fat service layer, whereas put some logic into entities would be the simplest solution.

So I would have an architecture like this:

^
| Twig
| Controller | API
| Service
| Model
| Entity

Where:

Entity: would be simple POPO, just a bag of setter and getter

Model: would be Entity Object decorated with business logic

Service: contains all business logic which involve more than one Entity (here I would place also validation task), and acts like a converter entity -> model

Controller | API: just matches Request with Service, ParamConvert and check autorization

Twig: presentation layer

My problem is how to hide entity layer to controllers and works only with model. In order to decorate my entities with business logic, I thought build a service that uses repository and decorates results (I can't find another way to achieve that).

So, a stupid example:

namespace ...\Entity\Article;
class Article {
    private $id;
    private $description;

    // getter and setter
}


namespace ...\Model\Article;
class Article {
    private $article; // all methods will be exposed in some way
    private $storeService; // all required services will be injected

    public function __construct($article, $storeService) {
       $this->article = $article;
       $this->storeService = $storeService;
    }

    public function getEntity() {
       return $this->article;
    }

    public function isAvailable() {
       return $storeService->checkAvailability($this->article);
    }

    ...
}


class ArticleService {
    private $storeService; // DI
    private $em; // DI
    private $repository; // Repository of entity class Article

    public function findById($id) {
       $article = $this->repository->findById($id);
       return new \Model\Article($article, $storeService);
    }

    public function save(\Model\Article $article) {
       $this->em->persist($article->getEntity());
    }
    ...
}

And upper layers are made in the usual way. I know it's not a good solution, but I can't find a better way to have a Model layer. And I really don't like to have something like:

$articleService->isAvailable($article);

instead of a more OO:

$article->isAvailable();
Fayum answered 16/11, 2013 at 12:18 Comment(3)
I'm very interested about the answer too. In order to perform their business logic, are your models container aware (able to call services) ? Or just scoped to themselves ?Revels
How did you solve this problem ?Heng
Have a look to GenieLamp software factory that generates layers. The most important element is the entity-relations model, a Python generator module can be written in 1 day.Richerson
H
1

I have the DoctrineEntity object Extend the DomainModel object. And while the controllers may actually receive DoctrineEntities, they only operate on the DomainModelInterface.

... namespace DomainModel;
interface ArticleDomainModelInterface ...
interface ArticleDomainModelRepositoryInterface ... // create, find, save, commit
class ArticleDomainModel implements ArticleDomainModelInterface

... namespace Doctrine;
class ArticleDoctrineEntity extends ArticleDomainModel
class ArticleDoctrineRepository implements ArticleDomainModelRepositoryInterface

... namespace Memory;
// Usually dont need a memory article object
class ArticleMemoryRepository implements ArticleDomainModelRepositoryInterface

All model creation and persistence are done through a repository. The controllers and other related services are only aware of the ArticleDomainModel methods. This gives you a nice separation and allows using different repositories for testing or for supporting different persistence mechanisms. It also allows using value objects in your domain model while still persisting them with Doctrine 2.

However, in php, I do struggle with the notion of what sort of useful business logic can actually be put in the domain model objects themselves. I tend to end up with most of the logic in services. And that is because most of my php applications are heavily crud oriented.

There is also the question: should controllers themselves have access to domain model objects?

One of the main developers of Doctrine 2, Benjamin Eberlei, has a number of blog posts on this subject. All of his articles are worth reading in detail. Here are some:

http://www.whitewashing.de/2013/07/24/doctrine_and_domainevents.html http://www.whitewashing.de/2012/08/22/building_an_object_model__no_setters_allowed.html http://www.whitewashing.de/2012/08/18/oop_business_applications__command_query_responsibility_seggregation.html

Howlend answered 16/11, 2013 at 18:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.