Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Put business logic in entity

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();
like image 451
marka.thore Avatar asked Nov 16 '13 12:11

marka.thore


People also ask

Can entities have business logic?

Entity objects encapsulate business logic The best place to write your business logic is in entity objects, because they consistently enforce business logic for all views of data, accessed through any type of client interface.

Where do you put your business logic typically?

The business logic should be placed in the model, and we should be aiming for fat models and skinny controllers. As a start point, we should start from the controller logic. For example: on update, your controller should direct your code to the method/service that delivers your changes to the model.

Should you put business logic in the database?

Two good reasons for putting the business logic in the database are: It secures your logic and data against additional applications that may access the database that don't implement similar logic.

Where does business logic go in DDD?

All invariant to use-cases logic (business entities, business workflow components, e.g. Domain model, Domain services) goes to the Domain layer (Domain logic). This layer is responsible for concepts of the business domain and business rules.


1 Answers

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

like image 133
Cerad Avatar answered Oct 29 '22 00:10

Cerad