Doctrine Entities and business logic in a Symfony application - php

Any ideas / feedback are welcome :)
I run into a problem in how to handle business logic around my Doctrine2 entities in a big Symfony2 application. (Sorry for the post length)
After reading many blogs, cookbook and others ressources, I find that :
Entities might be used only for data mapping persistence ("anemic model"),
Controllers must be the more slim possible,
Domain models must be decoupled from persistence layer (entity do not know entity manager)
Ok, I'm totally agree with it, but :
where and how handle complex bussiness rules on domain models ?
A simple example
OUR DOMAIN MODELS :
a Group can use Roles
a Role can be used by different Groups
a User can belong to many Groups with many Roles,
In a SQL persistence layer, we could modelize these relations as :
OUR SPECIFIC BUSINESS RULES :
User can have Roles in Groups only if Roles is attached to the Group.
If we detach a Role R1 from a Group G1, all UserRoleAffectation with the Group G1 and Role R1 must be deleted
This is a very simple example, but i'd like to kown the best way(s) to manage these business rules.
Solutions found
1- Implementation in Service Layer
Use a specific Service class as :
class GroupRoleAffectionService {
function linkRoleToGroup ($role, $group)
{
//...
}
function unlinkRoleToGroup ($role, $group)
{
//business logic to find all invalid UserRoleAffectation with these role and group
...
// BL to remove all found UserRoleAffectation OR to throw exception.
...
// detach role
$group->removeRole($role)
//save all handled entities;
$em->flush();
}
(+) one service per class / per business rule
(-) API entities is not representating to domain : it's possible to call $group->removeRole($role) out from this service.
(-) Too many service classes in a big application ?
2 - Implementation in Domain entity Managers
Encapsulate these Business Logic in specific "domain entities manager", also call Model Providers :
class GroupManager {
function create($name){...}
function remove($group) {...}
function store($group){...}
// ...
function linkRole($group, $role) {...}
function unlinkRoleToGroup ($group, $role)
{
// ... (as in previous service code)
}
function otherBusinessRule($params) {...}
}
(+) all businness rules are centralized
(-) API entities is not representating to domain : it's possible to call $group->removeRole($role) out from service...
(-) Domain Managers becomes FAT managers ?
3 - Use Listeners when possible
Use symfony and/or Doctrine event listeners :
class CheckUserRoleAffectationEventSubscriber implements EventSubscriber
{
// listen when a M2M relation between Group and Role is removed
public function getSubscribedEvents()
{
return array(
'preRemove'
);
}
public function preRemove(LifecycleEventArgs $event)
{
// BL here ...
}
4 - Implement Rich Models by extending entities
Use Entities as sub/parent class of Domain Models classes, which encapsulate lot of Domain logic. But this solutions seems more confused for me.
For you, what is the best way(s) to manage this business logic, focusing on the more clean, decoupled, testable code ? Your feedback and good practices ? Have you concrete examples ?
Main Ressources :
Symfony managing entities
Symfony2/Doctrine, having to put business logic in my controller? And duplicating controller?
Extending Doctrine Entity in order to add business logic
http://iamproblematic.com/2012/03/12/putting-your-symfony2-controllers-on-a-diet-part-2/
http://l3l0.eu/lang/en/2012/04/anemic-domain-model-problem-in-symfony2/
https://leanpub.com/a-year-with-symfony

See here: Sf2 : using a service inside an entity
Maybe my answer here helps. It just addresses that: How to "decouple" model vs persistance vs controller layers.
In your specific question, I would say that there is a "trick" here... what is a "group"? It "alone"? or it when it relates to somebody?
Initially your Model classes probably could look like this:
UserManager (service, entry point for all others)
Users
User
Groups
Group
Roles
Role
UserManager would have methods for getting the model objects (as said in that answer, you should never do a new). In a controller, you could do this:
$userManager = $this->get( 'myproject.user.manager' );
$user = $userManager->getUserById( 33 );
$user->whatever();
Then... User, as you say, can have roles, that can be assigned or not.
// Using metalanguage similar to C++ to show return datatypes.
User
{
// Role managing
Roles getAllRolesTheUserHasInAnyGroup();
void addRoleById( Id $roleId, Id $groupId );
void removeRoleById( Id $roleId );
// Group managing
Groups getGroups();
void addGroupById( Id $groupId );
void removeGroupById( Id $groupId );
}
I have simplified, of course you could add by Id, add by Object, etc.
But when you think this in "natural language"... let's see...
I know Alice belongs to a Photographers.
I get Alice object.
I query Alice about the groups. I get the group Photographers.
I query Photographers about the roles.
See more in detail:
I know Alice is user id=33 and she is in the Photographer's group.
I request Alice to the UserManager via $user = $manager->getUserById( 33 );
I acces the group Photographers thru Alice, maybe with `$group = $user->getGroupByName( 'Photographers' );
I then would like to see the group's roles... What should I do?
Option 1: $group->getRoles();
Option 2: $group->getRolesForUser( $userId );
The second is like redundant, as I got the group thru Alice. You can create a new class GroupSpecificToUser which inherits from Group.
Similar to a game... what is a game? The "game" as the "chess" in general? Or the specific "game" of "chess" that you and me started yesterday?
In this case $user->getGroups() would return a collection of GroupSpecificToUser objects.
GroupSpecificToUser extends Group
{
User getPointOfViewUser()
Roles getRoles()
}
This second approach will allow you to encapsulate there many other things that will appear sooner or later: Is this user allowed to do something here? you can just query the group subclass: $group->allowedToPost();, $group->allowedToChangeName();, $group->allowedToUploadImage();, etc.
In any case, you can avoid creating taht weird class and just ask the user about this information, like a $user->getRolesForGroup( $groupId ); approach.
Model is not persistance layer
I like to 'forget' about the peristance when designing. I usually sit with my team (or with myself, for personal projects) and spend 4 or 6 hours just thinking before writing any line of code. We write an API in a txt doc. Then iterate on it adding, removing methods, etc.
A possible "starting point" API for your example could contain queries of anything, like a triangle:
User
getId()
getName()
getAllGroups() // Returns all the groups to which the user belongs.
getAllRoles() // Returns the list of roles the user has in any possible group.
getRolesOfACertainGroup( $group ) // Returns the list of groups for which the user has that specific role.
getGroupsOfRole( $role ) // Returns all the roles the user has in a specific group.
addRoleToGroup( $group, $role )
removeRoleFromGroup( $group, $role )
removeFromGroup() // Probably you want to remove the user from a group without having to loop over all the roles.
// removeRole() ?? // Maybe you want (or not) remove all admin privileges to this user, no care of what groups.
Group
getId()
getName()
getAllUsers()
getAllRoles()
getAllUsersWithRole( $role )
getAllRolesOfUser( $user )
addUserWithRole( $user, $role )
removeUserWithRole( $user, $role )
removeUser( $user ) // Probably you want to be able to remove a user completely instead of doing it role by role.
// removeRole( $role ) ?? // Probably you don't want to be able to remove all the roles at a time (say, remove all admins, and leave the group without any admin)
Roles
getId()
getName()
getAllUsers() // All users that have this role in one or another group.
getAllGroups() // All groups for which any user has this role.
getAllUsersForGroup( $group ) // All users that have this role in the given group.
getAllGroupsForUser( $user ) // All groups for which the given user is granted that role
// Querying redundantly is natural, but maybe "adding this user to this group"
// from the role object is a bit weird, and we already have the add group
// to the user and its redundant add user to group.
// Adding it to here maybe is too much.
Events
As said in the pointed article, I would also throw events in the model,
For example, when removing a role from a user in a group, I could detect in a "listener" that if that was the last administrator, I can a) cancel the deletion of the role, b) allow it and leave the group without administrator, c) allow it but choose a new admin from with the users in the group, etc or whatever policy is suitable for you.
The same way, maybe a user can only belong to 50 groups (as in LinkedIn). You can then just throw a preAddUserToGroup event and any catcher could contain the ruleset of forbidding that when the user wants to join group 51.
That "rule" can clearly leave outside the User, Group and Role class and leave in a higher level class that contains the "rules" by which users can join or leave groups.
I strongly suggest to see the other answer.
Hope to help!
Xavi.

I find solution 1) as the easiest one to maintain from longer perspective. Solution 2 leads bloated "Manager" class which will eventually be broken down into smaller chunks.
http://c2.com/cgi/wiki?DontNameClassesObjectManagerHandlerOrData
"Too many service classes in a big application" is not a reason to avoid SRP.
In terms of Domain Language, I find the following code similar:
$groupRoleService->removeRoleFromGroup($role, $group);
and
$group->removeRole($role);
Also from what you described, removing/adding role from group requires many dependencies (dependency inversion principle) and that could be hard with a FAT/bloated manager.
Solution 3) looks very similar to 1) - each subscriber is actually service automatically triggered in background by Entity Manager and in simpler scenarios it can work, but troubles will arise as soon the action (adding/removing role) will require a lot of context eg. which user performed the action, from which page or any other type of complex validation.

I'm in favour of business-aware entities. Doctrine goes a long way not to pollute your model with infrastructure concerns; it uses reflection so you are free to modify accessors as you want.
The 2 "Doctrine" things that may remain in your entity classes are annotations (you can avoid them thanks to YML or XML mapping), and the ArrayCollection. This is a library outside of Doctrine ORM (̀Doctrine/Common), so no issues there.
So, sticking to the basics of DDD, entities are really the place to put your domain logic. Of course, sometimes this is not enough, then you are free to add domain services, services without infrastructure concerns.
Doctrine repositories are more middle-ground: I prefer to keep those as the only way to query for entities, event if they are not sticking to the initial repository pattern and I would rather remove the generated methods. Adding manager service to encapsulate all fetch/save operations of a given class was a common Symfony practice some years ago, I don't quite like it.
In my experience, you may come with far more issues with Symfony form component, I don't know if you use it. They will seriously limit your ability to customize the constructor; then you may rather use named constructors. Adding the PhpDoc #deprecated̀ annotation will give your pairs some visual feedback that they should not use the original constructor.
Last but not least, relying too much on Doctrine events will eventually bite you. They are too many technical limitations there, plus I find those hard to keep track of. When needed, I add domain events dispatched from the controller/command to Symfony event dispatcher.

I would consider using a service layer apart from the entities itself. Entities classes should describe the data structures and eventually some other simple calculations. Complex rules go to services.
As long you use services you can create more decoupled systems, services and so on. You can take the advantage of dependency injection and utilize events (dispatchers and listeners) to do the communication between the services keeping them weakly coupled.
I say that on basis of my own experience. In the beginning I used to put all the logic inside the entities classes (specially when I developed symfony 1.x/doctrine 1.x applications). As long the applications grew they got really hard to maintain.

As a personal preference, I like to start simple and grow as more business rules are applied. As such I tend to favour the listeners approach better.
You just
add more listeners as business rules evolve,
each having a single responsibility,
and you can test these listeners independently easier.
Something that would require lots of mocks/stubs if you have a single service class such as:
class SomeService
{
function someMethod($argA, $argB)
{
// some logic A.
...
// some logic B.
...
// feature you want to test.
...
// some logic C.
...
}
}

Related

DDD / CQRS / ES - How and where to implement guards

Good morning,
I've a model where a User AR has a specific UserRole (administrator, reseller or client). For that AR, there are some guards I would implement which are:
An administrator cannot have a manager other than himself
A reseller cannot have a manager other than an administrator
A client cannot have a manager other than a reseller or client (sub-account case)
Let's say that I want to register a new User. The flow would be as follows:
RegisterUser request handler -> RegisterUser Command -> RegisterUser command handler -> User->register(...) method ->UserWasRegistered Domain event
How and where I should implement the guards to validate my User AR exactly? Right now, I've something that look as follows:
namespace vendor\Domain\Model;
class User
{
public static function register(
UserId $userId,
User $manager,
UserName $name,
UserPassword $password,
UserEmail $email,
UserRole $role
): User
{
switch($role) {
case UserRole::ADMINISTRATOR():
if(!$userId->equals($manager->userId)) {
throw new \InvalidArgumentException('An administrator cannot have a manager other than himself');
}
break;
case UserRole::RESELLER():
if(!$manager->role->equals(UserRole::ADMINISTRATOR())) {
throw new \InvalidArgumentException('A reseller cannot have a manager other than an administrator');
}
break;
case UserRole::CLIENT():
// TODO: This is a bit more complicated as the outer client should have a reseller has manager
if(!$manager->role->equals(UserRole::RESELLER()) && !$manager->role->equals(UserRole::Client())) {
throw new \InvalidArgumentException('A client cannot have a manager other than a reseller or client');
}
}
$newUser = new static();
$newUser->recordThat(UserWasRegistered::withData($userId, $manager, $name, $password, $email, $role, UserStatus::REGISTERED()));
return $newUser;
}
}
As you can see here, guards are in the User AR, which I think is bad. I'm wondering if I should either put those guards in external validators or in the command handler. Another thing is that I should probably also access the read model to ensure uniqueness of user and existence of manager.
And the last thing is, I would prefer pass a UserId VO rather than a User AR for the manager property, hence my thinking that guards should not be put in the User AR.
Your advice would be much appreciated.
As you can see here, guards are in the model himself which I think is bad. I'm wondering if I should either put those guards in external validators or in the command handler.
With DDD, you strive to keep business logic within the domain layer and more specifically into the model (aggregates, entities and value objects) as much as possible to avoid ending up with an Anemic Domain Model. Some types of rules (e.g. access control, trivial data type validation, etc.) may not be considered business rules by nature and could therefore be delegated to the application layer, but the core domain rules should not leak outside the domain.
I would prefer pass a UserId value object rather than a User aggregat for the manager property
Aggregates should aim at relying on data within their boundary to enforce rules as it's the only way to ensure strong consistency. It is important to realize that any checks based off data external to the aggregate could have been made on stale data and therefore the rule might still get violated through concurrency. The rule can then only be made eventually consistent by detecting violations after they occurred and act accordingly. That doesn't mean the checks are worthless though, as it will still prevent most violations to occur in low-contention scenarios.
When it comes to providing external information to aggregates, there are two main strategies:
Lookup the data before calling upon the domain (e.g. in the application service)
Example (pseudo-code):
Application {
register(userId, managerId, ...) {
managerUser = userRepository.userOfId(userId);
//Manager is a value object
manager = new Manager(managerUser.id(), managerUser.role());
registeredUser = User.register(userId, manager, ...);
...
}
}
When to use? This is the most standard approach and the "purest" (aggregates never perform indirect IO). I would always consider this strategy first.
What to watch for? As in your own code sample, it may be tempting to pass an AR into another's method, but I would try to avoid it to prevent unexpected mutations of the passed AR instance and also to avoid creating dependencies on a larger-than-needed contract.
Pass a domain service to the domain which it can use to lookup data on it's own.
Example (pseudo-code):
interface RoleLookupService {
bool userInRole(userId, role);
}
Application {
register(userId, managerId, ...) {
var registeredUser = User.register(userId, managerId, roleLookupService, ...);
...
}
}
When to use? I would consider this approach when the lookup logic itself is complex enough to care about encapsulating it in the domain rather than leaking it into the application layer. However, if you want to maintain aggregates "purity" you could also extract the whole creation process in a factory (domain service) which the application layer would rely upon.
What to watch for? You should always keep the Interface Segregation Principle in mind here and avoid passing large contracts such as IUserRepository when the only thing looked up is whether or not a user has a role. Furthermore, this approach is not considered to be "pure", because the aggregates may be performing indirect IO. A service dependency could also need more work to mock than a data dependency for unit tests.
Refactoring the original example
Avoid passing another AR instance
Explicitly model the supervision policy policy as a first-class citizen, associated to a specific role. Note that you could use any modeling variants where the rule is associated to the role. I'm not necessarily satisfied with the language in the example, but you will get the idea.
interface SupervisionPolicy {
bool isSatisfiedBy(Manager manager);
}
enum Role {
private SupervisionPolicy supervisionPolicy;
public SupervisionPolicy supervisionPolicy() { return supervisionPolicy; }
...
}
class User {
public User(UserId userId, Manager manager, Role role, ...) {
//Could also have role.supervisionPolicy().assertSatisfiedBy(manager, 'message') which throws if not satsified
if (!role.supervisionPolicy().isSatisfiedBy(manager)) {
throw …;
}
}
}
Normally - Domain Driven Design calls for rich domain models, which normally means that the business logic is located in methods that represent parts of the domain.
That would normally mean that the command handler would be responsible for the plumbing (loading data from the database, storing changes in the database), and would delegate to the domain model the work of calculating the consequences of the user request.
So the "guards" would usually be implemented within the domain model.
And the last thing is, I would prefer pass a User Id rather than a User for the manager property, hence my thinking that guard should not be put in the User model.
That's fine - when a the domain model needs information that isn't local, you normally either lookup that information and pass it in, or pass in the capability to look up the information.
So in this case, you might be passing in a "domain service" that knows how to look up a UserRole given a UserId.
Are you telling me that it is perfectly valid to pass a domain service to an aggregate? At instantiation level or only to the method dealing with?
My strong preference is that services are passed as arguments to the methods that need them, and are not part of the instantiation. So the entities in the domain model hold data, and collaborators are provided on demand.
"Domain Service" is the third element of the domain model described by Evans in Chapter 5 of the blue book. In many cases, the domain service describes an interface (written in the language of the model), but the implementation of the interface is in the application or infrastructure "layer".
So I would never pass a repository to the domain model, but I would pass a domain service that delegates the actual work to a repository.

Laravel Repositories and multiple related models

I'm currently just starting on porting a large Yii2 application to Laravel and I'm considering using repositories to solve my current problem of messy controllers and bloated models.
I've looked at a ton of examples of repositories but most them only cover simple CRUD. For example in my current app a User can created in multiple places and must be created with like 5 related records in other tables, for example a User must be added to Groups and must have Permission records created based on their role.
Currently almost all of my models have a custom Create function that can reused anywhere. Here is a very basic Yii2 example of what I'm talking about.
Example User creation in User model:
public static function create(array $attributes, array $group_ids)
{
$user = new User;
$user->attributes = $attributes;
$user->save();
$role = $user->role;
foreach ($role->rolePermissions as $role_permission) {
UserPermission::create($user->id, $role_permission);
}
foreach ($group_ids as $group_id) {
GroupUser::create($user->id, $group_id)
}
if ($role->admin_mode) {
// send welcome email
}
return $user;
}
Is it good practice to simply inject the UserPermission and GroupUser Repositories into my UserRepository in this case? How do you handle saving related records in Repositories?
Does anyone have any more advanced examples of using Repositories with related models?
You need to understand that in Repository pattern, repository is not the place to store your business logic, that's why they are simple, doing CRUD only.
For what you need here is a business logic layer on top of the repositories. What I did to my recent projects is that I create a Services folder in my app root, and create all sort of services in it with my main business logic in it, like $userService->createUser(..), and in it will have checks on different roles, groups, emitting events, send emails.
So a typical calls could look like this:
calls UsersController->createUser
calls UserService->createUser
verifications, checks, throws errors
calls UserRepository->create
calls GroupUserRepository->create
emit UserCreated event
(disjointed: event listeners)
dedicated listeners listened UserCreated event
calls UserService->sendWelcomeEmail
send welcome emails
So services is almost identical to your fat models, but they are standalone php classes that understand your business logic, use whatever database it knows, and process requests and return results. It does not depend on anything to instantiate one, and so can be included by anyone to use it. They also can be instantiated as singleton or instances depending on your need.
Side note
I've wasted too much time on creating repositories when I could have just use Eloquent. They are not identical, but I could not foresee my project to change underlying DBMS so I would usually just use eloquent directly in my services layer.

Doctrine inheritance strategy when two different subclasses extend the same entity instance

I am developing an application for managing court interpreter services (using Doctrine and Zend Framework 2). There are a lot of people involved who have various specialized roles, hence a Person superclass, and subclasses. The class hierarchy is not complicated in a vertical sense -- one generation of inheritance is enough -- but the horizontal aspect is giving me trouble.
I don't think mapped superclasses fit my case. I also considered single-table inheritance but that would quickly get ugly because the subclasses have their own entity relationships, too much stuff to cram gracefully into a single table.
That leaves us with class table inheritance, which is a really nice fit in most respects, but... I will have plenty of cases where the subclass User (for authentication) and the subclass Interpreter will (or should) point to the same row in the parent data table, because they represent one and the same person in reality. But because of the discriminator column you have to choose one or the other, or else create two different rows holding the same data -- and the normalization police should get you for that.
I think maybe either the User or the Interpreter entity has to simply have a one-to-one relationship with the Person entity, and deal with that semi-manually. Another option I suppose would be to collapse User into Person -- but that's ugly because a lot of people will not be authenticating and will not have or need a password.
I have looked at
Doctrine inheritance, several entities extending the same super class and
How to change and entity type in Doctrine2 CTI Inheritance (inter alia) and neither one solves this.
So, I wonder if anyone has any suggestions. Thanks.
It sounds like you're managing a bunch of data about Persons, which identifies individual humans in the world. Since only some subset of the people in the system are Users, I'd argue that concerns about authentication, audit logging, notifications, etc are separate from the concerns of the Person class hierarchy.
I'd advise removing User from the Person class hierarchy. Perhaps rename it Account, to make it feel less person-y. An Account can have an owner property, which is a relation to Person. If you want to use the Person's email address as an identifier for authentication, that's fine. If you later wanted to add a username instead, that would be a property of Account, since it's only meaningful in that context.
Not sure about the underlying code (not a ZF developer), but I think you are confusing the behavior and the data.
To make the authentication working you do not need the inheritance really. Just found you code ontop of the interface dependencies.
To make the users able to auth (while generic person could not) - use the inheritance or, as #timdev suggested, the relation. In symfony world I'd better write this something like
class User extends Person implement UserInterface {
//... implementation
}
class Person {
//...
}
After that you can just be sure, that you have a UserInterface while any service stuff and authentication particularly.
In case if you have to dynamically switch the underlying class of User entity (i.e. you have Author extends Person and want allow some authors to sign in) I think the composition is the only suitable solution. Split the logic, split the entites, split the data. Be happy.

When to call ->flush() in a frontend/core approach in Symfony2?

We are having trouble in deciding where to put the ->flush() call in a Symfony2 application. Let's see if you can "inspire" us, please.
Our application is very big. It currently has about 30 bundles. We have 2 separate developer teams: one does frontend (controllers + twigs) and another does core (database + services + model, etc).
Frontend is one project (has its own bundles, which do not have any doctrine models nor logic nor services, but have twigs, public images and css and controllers), and lives in one repository.
Core is another project (has its own bundles, which offer services, model objects, etc, has doctrine objects in their inside and have no controllers nor twigs), and lives in another repo.
The goal of this approach is that our product is delivered with DIFFERENT FRONTENDS (Core+Frontend1 for the web, Core+Frontend2 for the mobiles, Core+Frontend3 for the support-team with a special web to admin the normal users). So all "logic" is "in the core" and either one or other frontend project is consuming the same services, so an improvement in the Core, improves all the deploys without having to re-test every piece of frontend.
So... we are trying that the controllers NEVER access the doctrine objects, but acces a "modelling layer", so if ever the persistance layer changes, the controllers and twigs (ie: all the frontend) remains without a single change so we only have to re-test the core but not the frontend.
We are trying to make a MODEL in such a way that all access to DB in "encapsulated" so the controllers do NOT access the doctrine but to "services" that in turn use doctrine. Suppose we treat the objects "cars" and "people", then a controller can access a "cars_manager" service or a "people_manager" service from which to do ALL necessary operations (create objects, retrieve them, etc).
Where would you put the flush call?
Example (in pseudo-code, to make it simpler to read):
controller AjaxJsonAddDriverToCar( $CarId, $DriverId )
{
try
{
$Cars = getService( "core.cars_manager" );
$Car = $Cars->getCarById( $CarId );
$Car->addDriver( $DriverId );
$Result = JSON_OK;
}
catch
{
$Result = JSON_FAIL;
}
return $Result;
}
Provided that the controller does NOT know how the core is implemented... it should NOT get the doctrine and perform a ->flush() on it.
Inspiration is welcome.
Thanks.
To avoid calling flush from the controller, I suggest encapsulating all the code that updates the database for a particular controller action into a service method which calls flush() at the end, in which case flush() won't be called if the service method throws an exception.
In the example you have given this can be accomplished by replacing:
$Cars = getService( "core.cars_manager" );
$Car = $Cars->getCarById( $CarId );
$Car->addDriver( $DriverId );
$Result = JSON_OK;
with:
$Cars = getService( "core.cars_manager" );
$Cars->addDriverToCar($CarId, $DriverId);
$Result = JSON_OK;
and CarsManager::addDriverToCar would be something like:
$Car = $this->getCarById( $CarId );
$Car->addDriver( $DriverId );
$this->getEntityManager()->flush();
However, this is a fairly simplistic example as it only updates a single Entity and the beauty of flush is that it saves changes to all the entities you have added/removed/updated, constituting the completion of a unit of work.
The approach you described mentions managers which are entity specific. Whilst there is no reason that the manager for a complex entity can't have methods that create/update/remove multiple entities of various types it is worth considering the responsibilities of your manager classes. It may be helpful to have a manager for each entity type that handles simple Find and CRUD type operations for that entity and then an additional layer of managers between the entity managers and the controllers that handle the processing for a particular feature or set of features.
My first thought was some kind of active record, where you would tell the car to save itself. As Car is only boilerplate code, it could be ok that it knows about the database implementation and accesses some services.
My second thought was that the cars manager should know about the saving, so it would be something very similar to the entity manager and you woudl tell him flush and he flushes. You would basically abstract the entity manager and make him a bit easier to use (as there is no repository which one uses directly).
My third thought was wtf. I understand that you want to seperate the frontend from the backend. I don't understand why the frontend cannot operate on models but needs to operate on boilerplate code. The funny thing is: If the models change, so do your layers in between. If you don't want to change the layer, you could also not change the model (it's the same either way). E.g. you want to remove a field from the database: Remvoe the annotation and ignore it. No harm done. If you rename it, you can always have the old getter and setter in place, operating on the new name. And so on.
Of course I don't see the whole picture, but you may want to think this through again ;)
And here is another thought: Maybe you want to just tell the abstraction layer if the whole thing was a success or failure and he does everything what needs to be done (flushing the database, writing logs, sending emails and so on). If you can narrow your use cases down to success and failure and the service knows what to do, then this might be the easiest solution.

DDD and MVC: Difference between 'Model' and 'Entity'

I'm seriously confused about the concept of the 'Model' in MVC. Most frameworks that exist today put the Model between the Controller and the database, and the Model almost acts like a database abstraction layer. The concept of 'Fat Model Skinny Controller' is lost as the Controller starts doing more and more logic.
In DDD, there is also the concept of a Domain Entity, which has a unique identity to it. As I understand it, a user is a good example of an Entity (unique userid, for instance). The Entity has a life-cycle -- it's values can change throughout the course of the action -- and then it's saved or discarded.
The Entity I describe above is what I thought Model was supposed to be in MVC? How off-base am I?
To clutter things more, you throw in other patterns, such as the Repository pattern (maybe putting a Service in there). It's pretty clear how the Repository would interact with an Entity -- how does it with a Model?
Controllers can have multiple Models, which makes it seem like a Model is less a "database table" than it is a unique Entity.
UPDATE: In this post the Model is described as something with knowledge, and it can be singular or a collection of objects. So it's sound more like an Entity and a Model are more or less the same. The Model is an all encompassing term, where an Entity is more specific. A Value Object would be a Model as well. At least in terms of MVC. Maybe???
So, in very rough terms, which is better?
No "Model" really ...
class MyController {
public function index() {
$repo = new PostRepository();
$posts = $repo->findAllByDateRange('within 30 days');
foreach($posts as $post) {
echo $post->Author;
}
}
}
Or this, which has a Model as the DAO?
class MyController {
public function index() {
$model = new PostModel();
// maybe this returns a PostRepository?
$posts = $model->findAllByDateRange('within 30 days');
while($posts->getNext()) {
echo $posts->Post->Author;
}
}
}
Both those examples didn't even do what I was describing above. I'm clearly lost. Any input?
Entity
Entity means an object that is a single item that the business logic works with, more specifically those which have an identity of some sort.
Thus, many people refer to ORM-mapped objects as entities.
Some refer to as "entity" to a class an instance of which represents a single row in a database.
Some other people prefer to call only those of these classes as "entity" which also contain business rules, validation, and general behaviour, and they call the others as "data transfer objects".
Model
A Model is something that is not directly related to the UI (=View) and control flow (=Controller) of an application, but rather about the way how data access and the main data abstraction of the application works.
Basically, anything can be a model that fits the above.
MVC
You can use entities as your models in MVC. They mean two different things, but the same classes can be called both.
Examples
A Customer class is very much an entity (usually), and you also use it as part of data access in your app. It is both an entity and a model in this case.
A Repository class may be part of the Model, but it is clearly not an entity.
If there is a class that you use in the middle of your business logic layer but don't expose to the rest of the application, it may be an entity, but it is clearly not a Model from the perspective of the MVC app.
Your example
As for your code examples, I would prefer the first one.
A Model is a class that is used as a means of data abstaction of an application, not a class which has a name suffixed with "Model". Many people consider the latter bloatware.
You can pretty much consider your Repository class as part of your model, even if its name isn't suffixed with "Model".
I would add to that the fact that it is also easier to work with the first one, and for other people who later may have to understand your code, it is easier to understand.
All answers are a heavy mashup of different things and simply wrong.
A model in DDD is much like a model in the real world:
A simplification and abstraction of something.
No less and no more.
It has nothing to do with data nor objects or anything else.
It's simply the concept of a domain part. And in also every complex domain
there is always more than one model, e.g. Trading, Invoicing, Logistics.
An entity is not a "model with identity" but simply an object with identity.
A repository is not just a 1st level cache but a part of the domain too.
It is giving an illusion of in-memory objects and responsible for fetching
Aggregates (not entities!) from anywhere and saving them
i.e. maintaining the life cycle of objects.
The "model" in your application is the bit which holds your data. The "entity" in domain-driven design is, if I remember correctly, a model with an identity. That is to say, an entity is a model which usually corresponds directly to a "physical" element in a database or file. I believe DDD defines two types of models, one being the entity, the other being the value, which is just a model without and identity.
The Repository pattern is just a type of indexed collection of models/entities. So for instance if your code wants order #13, it will first ask the repository for it, and if it can't get it from there, it will go and fetch it from wherever. It's basically a level 1 cache if you will. There is no difference in how it acts with a model, and how it acts with an entity, but since the idea of a repository is to be able to fetch models using their IDs, in terms of DDD, only entities would be allowed into the repository.
A simple solution using service and collection:
<?php
class MyController {
public function index() {
$postService = ServiceContainer::get('Post');
$postCollection = $postService->findAllByDateRange('within 30 days');
while($postCollection->getNext()) {
echo $postCollection->current()->getAuthor();
}
}
}
EDIT:
The model(class) is the simple representation of the entity scheme. The model(object) is a single entity. The service operates on models and provides concrete data to the controllers. No controller has any model. The models stand alone.
On the other "side", mappers map the models into persistance layers (e.g: databases, 3rd party backends, etc).
while this is specifically about Ruby on Rails, the same principles and information still apply since the discussion is around MVC and DDD.
http://blog.scottbellware.com/2010/06/no-domain-driven-design-in-rails.html

Categories