Laravel Repositories and multiple related models - php

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.

Related

MVC (Laravel) where to add logic

Let's say whenever I do a CRUD operation or modify a relationship in a specific way I also want to do something else. E.g., whenever someone publishes a post I also want to save something to a table for analytics. Maybe not the best example but in general there's a lot of this "grouped" functionality.
Normally I see this type of logic put into controllers. That's all fine an dandy until you want to reproduce this functionality in lots of places. When you start getting into partials, creating an API and generating dummy content it becomes an issue with keeping things DRY.
The ways I've seen to manage this are events, repositories, libraries, and adding to models. Here are my understandings of each:
Services: This is where most people would probably put this code. My main issue with services is that sometimes it's hard to find specific functionality in them and I feel like they get forgotten about when people are focused on using Eloquent. How would I know I need to call a method publishPost() in a library when I can just do $post->is_published = 1?
The only condition I see this working well in is if you ONLY use services (and ideally make Eloquent inaccessible somehow from controllers all together).
Ultimately it seems like this would just create a bunch of extra unnecessary files if your requests generally follow your model structure.
Repositories: From what I understand this is basically like a service but there's an interface so you can switch between ORMs, which I don't need.
Events: I see this as the most elegant system in a sense because you know your model events are always going to be called on Eloquent methods, so you can write your controllers like you normally would. I can see these getting messy though and if anyone has examples of large projects using events for critical coupling I'd like to see it.
Models: Traditionally I'd have classes that performed CRUD and also handled critical coupling. This actually made things easy because you knew all functionality around CRUD + whatever had to be done with it was there.
Simple, but in MVC architecture this isn't normally what I see done. In a sense though I prefer this over services since it's a bit easier to find, and there are less files to keep track of. It can get a bit disorganized though. I'd like to hear downfalls to this method and why most people don't seem to do it.
What are the advantages / disadvantages of each method? Am I missing something?
I think all patterns / architectures that you present are very useful as long as you follow the SOLID principles.
For the where to add logic I think that it's important to refer to the Single Responsibility Principle. Also, my answer considers that you are working on a medium / large project. If it's a throw-something-on-a-page project, forget this answer and add it all to controllers or models.
The short answer is: Where it makes sense to you (with services).
The long answer:
Controllers: What is the responsibility of Controllers? Sure, you can put all your logic in a controller, but is that the controller's responsibility? I don't think so.
For me, the controller must receive a request and return data and this is not the place to put validations, call db methods, etc..
Models: Is this a good place to add logic like sending an welcome email when a user registers or update the vote count of a post? What if you need to send the same email from another place in your code? Do you create a static method? What if that emails needs information from another model?
I think the model should represent an entity. With Laravel, I only use the model class to add things like fillable, guarded, table and the relations (this is because I use the Repository Pattern, otherwise the model would also have the save, update, find, etc methods).
Repositories (Repository Pattern): At the beginning I was very confused by this. And, like you, I thought "well, I use MySQL and thats that.".
However, I have balanced the pros vs cons of using the Repository Pattern and now I use it. I think that now, at this very moment, I will only need to use MySQL. But, if three years from now I need to change to something like MongoDB most of the work is done. All at the expense of one extra interface and a $app->bind(«interface», «repository»).
Events (Observer Pattern): Events are useful for things that can be thrown at any class any given time. Think, for instance, of sending notifications to a user.
When you need, you fire the event to send a notification at any class of your application. Then, you can have a class like UserNotificationEvents that handles all of your fired events for user notifications.
Services: Until now, you have the choice to add logic to controllers or models. For me, it makes all sense to add the logic within Services. Let's face it, Services is a fancy name for classes. And you can have as many classes as it makes sense to you within your aplication.
Take this example: A short while ago, I developed something like the Google Forms. I started with a CustomFormService and ended up with CustomFormService, CustomFormRender, CustomFieldService, CustomFieldRender, CustomAnswerService and CustomAnswerRender. Why? Because it made sense to me. If you work with a team, you should put your logic where it makes sense to the team.
The advantage of using Services vs Controllers / Models is that you are not constrained by a single Controller or a single Model. You can create as many services as needed based on the design and needs of your application. Add to that the advantage of calling a Service within any class of your application.
This goes long, but I would like to show you how I have structured my application:
app/
controllers/
MyCompany/
Composers/
Exceptions/
Models/
Observers/
Sanitizers/
ServiceProviders/
Services/
Validators/
views
(...)
I use each folder for a specific function. For example the Validators directory contains a BaseValidator class responsible for processing the validation, based on the $rules and $messages of specific validators (usually one for each model). I could as easily put this code within a Service, but it makes sense to me to have a specific folder for this even if it is only used within the service (for now).
I recommend you to read the following articles, as they might explain things a little better to you:
Breaking the Mold by Dayle Rees (author of CodeBright): This is where I put it all together, even though I changed a few things to fit my needs.
Decoupling your code in Laravel using Repositories and Services by Chris Goosey: This post explains well what is a Service and the Repository Pattern and how they fit together.
Laracasts also have the Repositories Simplified and Single Responsibility which are good resources with practical examples (even though you have to pay).
I wanted to post a response to my own question. I could talk about this for days, but I'm going to try to get this posted fast to make sure I get it up.
I ended up utilizing the existing structure that Laravel provides, meaning that I kept my files primarily as Model, View, and Controller. I also have a Libraries folder for reusable components that aren't really models.
I DID NOT WRAP MY MODELS IN SERVICES/LIBRARIES. All of the reasons provided didn't 100% convince me of the benefit of using services. While I may be wrong, as far as I can see they just result in tons of extra nearly empty files I need to create and switch between when working with models and also really reduce the benefit of using eloquent (especially when it comes to RETRIEVING models, e.g., using pagination, scopes, etc).
I put the business logic IN THE MODELS and access eloquent directly from my controllers. I use a number of approaches to make sure that the business logic doesn't get bypassed:
Accessors and mutators: Laravel has great accessors and mutators. If I want to perform an action whenever a post is moved from draft to published I can call this by creating function setIsPublishedAttribute and including the logic in there
Overriding Create/Update etc: You can always override Eloquent methods in your models to include custom functionality. That way you can call functionality on any CRUD operation. Edit: I think there's a bug with overriding create in newer Laravel versions (so I use events now registered in boot)
Validation: I hook my validation in the same way, e.g., I'll run validation by overriding CRUD functions and also accessors/mutators if needed. See Esensi or dwightwatson/validating for more information.
Magic Methods: I use the __get and __set methods of my models to hook into functionality where appropriate
Extending Eloquent: If there's an action you'd like to take on all update/create you can even extend eloquent and apply it to multiple models.
Events: This is a straight forward and generally agreed upon place to do this as well. Biggest drawback with events I think is that exceptions are hard to trace (might not be the new case with Laravel's new events system). I also like to group my events by what they do instead of when they are called...e.g., have a MailSender subscriber which listens for events that send mail.
Adding Pivot/BelongsToMany Events: One of the things I struggled with the longest was how to attach behavior to the modification of belongsToMany relationships. E.g., performing an action whenever a user joins a group. I'm almost done polishing up a custom library for this. I haven't published it yet but it is functional! Will try to post a link soon. EDIT I ended up making all my pivots into normal models and my life has been so much easier...
Addressing people's concerns with using models:
Organization: Yes if you include more logic in models, they can be longer, but in general I've found 75% of my models are still pretty small. If I chose to organize the larger ones I can do it using traits (e.g., create a folder for the model with some more files like PostScopes, PostAccessors, PostValidation, etc as needed). I know this is not necessarily what traits are for but this system works without issue.
Additional Note: I feel like wrapping your models in services is like having a swiss army knife, with lots of tools, and building another knife around it that basically does the same thing? Yeah, sometimes you might want to tape a blade off or make sure two blades are used together...but there are typically other ways to do it...
WHEN TO USE SERVICES: This article articulates very well GREAT examples for when to use services (hint: it's not very often). He says basically when your object uses multiple models or models at strange parts of their lifecycle it makes sense. http://www.justinweiss.com/articles/where-do-you-put-your-code/
What I use to do to create the logic between controllers and models is to create a service layer. Basically, this is my flow for any action within my app:
Controller get user's requested action and sent parameters and delegates everything to a service class.
Service class do all the logic related to the operation: input validation, event logging, database operations, etc...
Model holds information of fields, data transformation, and definitions of attributes validations.
This is how I do it:
This the method of a controller to create something:
public function processCreateCongregation()
{
// Get input data.
$congregation = new Congregation;
$congregation->name = Input::get('name');
$congregation->address = Input::get('address');
$congregation->pm_day_of_week = Input::get('pm_day_of_week');
$pmHours = Input::get('pm_datetime_hours');
$pmMinutes = Input::get('pm_datetime_minutes');
$congregation->pm_datetime = Carbon::createFromTime($pmHours, $pmMinutes, 0);
// Delegates actual operation to service.
try
{
CongregationService::createCongregation($congregation);
$this->success(trans('messages.congregationCreated'));
return Redirect::route('congregations.list');
}
catch (ValidationException $e)
{
// Catch validation errors thrown by service operation.
return Redirect::route('congregations.create')
->withInput(Input::all())
->withErrors($e->getValidator());
}
catch (Exception $e)
{
// Catch any unexpected exception.
return $this->unexpected($e);
}
}
This is the service class that does the logic related to the operation:
public static function createCongregation(Congregation $congregation)
{
// Log the operation.
Log::info('Create congregation.', compact('congregation'));
// Validate data.
$validator = $congregation->getValidator();
if ($validator->fails())
{
throw new ValidationException($validator);
}
// Save to the database.
$congregation->created_by = Auth::user()->id;
$congregation->updated_by = Auth::user()->id;
$congregation->save();
}
And this is my model:
class Congregation extends Eloquent
{
protected $table = 'congregations';
public function getValidator()
{
$data = array(
'name' => $this->name,
'address' => $this->address,
'pm_day_of_week' => $this->pm_day_of_week,
'pm_datetime' => $this->pm_datetime,
);
$rules = array(
'name' => ['required', 'unique:congregations'],
'address' => ['required'],
'pm_day_of_week' => ['required', 'integer', 'between:0,6'],
'pm_datetime' => ['required', 'regex:/([01]?[0-9]|2[0-3]):[0-5]?[0-9]:[0-5][0-9]/'],
);
return Validator::make($data, $rules);
}
public function getDates()
{
return array_merge_recursive(parent::getDates(), array(
'pm_datetime',
'cbs_datetime',
));
}
}
For more information about this way I use to organize my code for a Laravel app: https://github.com/rmariuzzo/Pitimi
In my opinion, Laravel already has many options for you to store your business logic.
Short answer:
Use Laravel's Request objects to automatically validate your input, and then persist the data in the request (create the model). Since all of the users input is directly available in the request, I believe it makes sense to perform this here.
Use Laravel's Job objects to perform tasks that require individual components, then simply dispatch them. I think Job's encompass service classes. They perform a task, such as business logic.
Long(er) answer:
Use Respositories When Required:
Repositories are bound to be over-bloated, and most of the time, are simply used as an accessor to the model. I feel like they definitely have some use, but unless you're developing a massive application that requires that amount of flexibility for you to be able to ditch Laravel entirely, stay away from repositories. You'll thank yourself later and your code will be much more straight forward.
Ask yourself if there's a possibility that you're going to be changing PHP frameworks or to a database type that Laravel doesn't support.
If your answer is "Probably not", then don't implement the repository pattern.
In addition to above, please don't slap a pattern on top of a superb ORM like Eloquent. You're just adding complexity that isn't required and it won't benefit you at all.
Utilize Services sparingly:
Service classes to me, are just a place to store business logic to perform a specific task with its given dependencies. Laravel has these out of the box, called 'Jobs', and they have much more flexibility than a custom Service class.
I feel like Laravel has a well-rounded solution for the MVC logic problem. It's just a matter or organization.
Example:
Request:
namespace App\Http\Requests;
use App\Post;
use App\Jobs\PostNotifier;
use App\Events\PostWasCreated;
use App\Http\Requests\Request;
class PostRequest extends Request
{
public function rules()
{
return [
'title' => 'required',
'description' => 'required'
];
}
public function persist(Post $post)
{
if (! $post->exists) {
// If the post doesn't exist, we'll assign the
// post as created by the current user.
$post->user_id = auth()->id();
}
$post->title = $this->title;
$post->description = $this->description;
$post->save();
// Maybe we'll fire an event here that we can catch somewhere
// else that needs to know when a post was created.
event(new PostWasCreated($post));
// Maybe we'll notify some users of the new post as well.
dispatch(new PostNotifier($post));
return $post;
}
}
Controller:
namespace App\Http\Controllers;
use App\Post;
use App\Http\Requests\PostRequest;
class PostController extends Controller
{
public function store(PostRequest $request)
{
$request->persist(new Post());
flash()->success('Successfully created new post!');
return redirect()->back();
}
public function update(PostRequest $request, Post $post)
{
$request->persist($post);
flash()->success('Successfully updated post!');
return redirect()->back();
}
}
In the example above, the request input is automatically validated, and all we need to do is call the persist method and pass in a new Post. I think readability and maintainability should always trump complex and unneeded design patterns.
You can then utilize the exact same persist method for updating posts as well, since we can check whether or not the post already exists and perform alternating logic when needed.

MVC - How to pass data to service

I'm a bit confused on how to perform insert and update statements using MVC.
Is it ok to create an instance of an object in your controller and pass it to your service to save it or do you pass data to your service and handle everything else in there?
Insert
In my controller something like:
$userservice->insert("myname","mypassword");
In my UserService:
function insert($username,$password){
$user = ORM::for_table('user')->create();
$user->username= $username;
$user->password= $password;
$user->save();
}
Update
In my controller something like:
$userservice->update("myname","mypassword",1);
In my UserService:
function insert($username,$password,$id){
$user = ORM::for_table('user')->find($id);
$user->username= $username;
$user->password= $password;
$user->save();
}
Is this good practice?
Because I see a lot of these answers where for example a user is being created in the controller and passed to a repository to save it:
Proper Repository Pattern Design in PHP?
But I don't like the idea of creating a user in the controller...
Controllers belongs to application layer and controlls only activity. In your example the activities are Create- and Update for an existing or for a new User. These operations belongs to the Domain Layer, which contains services. Thus services encapsulate the domain as a gatekeeper and provides operations for resolving domain like a facade.
Is it ok to create an instance of an object in your controller and pass it to your service to save it or do you pass data to your service and handle everything else in there?
The service should provide a method to pass a ValueObject. ValueObjects are better to encapsulate lot of data (Property values for User). Inside the service, the ValueObject should be delegated to Filter and Validator. If validation didn't fail the ValueObject will be delegated to a DataMapper. The DataMapper will map the properties of ValueObject to a data-model for the UserRepository (ORM). Repositories often need another model of data, e.g. Objects versus storage mediums based on RDBMS like MySQL.
This approach should be strict to seperate the concerns between layers to improve maintainabilty and interchangeabilty. Services should be thin and acts as a delegator to Domain Objects (Filter, Validator, etc.), for example see Service Layer Pattern.
So, where should be a value object created?
I would prefer that the service provides a method for this: getEntityPrototype() by using the prototype pattern.
Be careful with naming. ValueObject is an object which have no identity. Entity is an object with identity (here id of User). For an existing User you will have have a method like getUserById($id), which should return an UserEntity. If User does not exist for given id, it should return a NullObject. To create a new User getEntityPrototype() will return an UserEntity which have no identity yet, so you will call it ValueObject or better Prototype of Entity. After setting properties (e.g. by a FormObject) and persisting this object is a real entity. In a Factory for this service you can set the EntityPrototype.
What you should think about in this case is if the classes have only one responsibility.
Controller decides about the flow of the action. If there's a need for registering a user then it registers him, but it should not define how to do it, but ask a service to complete this task and get the result.
On the other hand you should have some kind of UserManager which updates, creates and fetches users - is this single responsibility? Kinda, yes - it's managing them in a broad sense.
There's a slight problem you have with your methods' names though. You should have registerUser not insert since it's way easier to tell what it actually does.
You should Pass Data to Model. MVC is all about dividing tasks Controller - Handles Application Flow, Model - Contains all the business login Database etc and View - here you decide how to show. Basically the UI part is stored here
So the Controller should send data to Model and model decides what to do with the data. The advantage of coding this way is that in future if you want to change something in the code you know where to look, or if you ask a designer to redesign your website you only have to give him the VIEW part of code . If the designer does something that caused an error , correcting that wont take that much time. If you follow MVC properly Adding,Updating or Maintaining functionality wont be a problem

Doctrine Entities and business logic in a Symfony application

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.
...
}
}

Entity, Repository and composition - Dependency Injection

I'm trying to learn about DDD and there's a thing about the entities and repositories that I'm unable to understand.
From other questions here on SO I realized it is a bad habit to inject Repositories into Entities. But how to avoid injecting repository when I'm composing objects?
Let's have simple situation - events and events application. This seems simple.
$event->add($application);
$eventRepository->save($event);
I believe the $application is an Entity so I believe there should be some $applicationRepository.
Does it mean, that I should inject $applicationRepository to $eventRepository to save the Event entity? Like
class eventRepository {
...
public function save(Event $event) {
...
foreach ($event->applications as $app) {
$this->applicationRepository->save($app);
}
...
}
}
Another solution that came to my mind is this:
$eventService->addAplication($event, $application);
class $eventService {
...
public function addApplication(Event $event, Application $app) {
// simple example of validation, something like $event->isAplyable()
if ($event->capacity > count($event->applications)) {
$this->applicationRepository->save($app);
$event->addApplication($app);
}
}
}
Is one method better than the other? Or did I completely messed it up?
You should have a repository per aggregate root only, and they should work independently.
So there are two scenarios that I can see, and which you choose depends on how the business does things:
If the application and the event are two different aggregate roots (can one application be added to multiple events and should all the events then reference the same entity?), they should be tied together data-wise using references, so that when you save the event, it will not save the applications, but only references to the applications that it holds.
If the event is the aggregate root and the application is something that lives, dies and changes with it (and they share consistency boundaries) your event repository should be able to save the application as a part of the event. Now you don't say how you persist data, but an ORM can help you with that.
Hope that helps a little. And feel free to ask.
One way to avoid an explicit call to an application repository is for the event repository to persists application instances that are associated with a given event. This is essentially the first option you propose, however depending on the persistence framework you use, the code could look a little different. For instance, some ORMs support persistence by reachability which means that if you're persisting an event and the frameworks finds transient application instances reachable from the event, it will persist those too. In this case there is not need for an explicit application repository.
The idea at play here is that of aggregate roots. If an Event is an aggregate root and an Application is a constituent value object, then the event repository must be able to persist the entire object graph, including the associated application instances. DDD suggests one repository per aggregate root not necessarily per-entity.
It may be the case that both Event and Application are aggregate roots (ARs). In that case it is not advised to have direct object references between ARs, but to instead use identity references. In that case, your second example would apply, except in a slightly different form. The event service should be an application service which hosts specific use cases associated with events. One of those is adding an application. The difference is that the addApplication method should accept an event ID and application ID as arguments which it would then load from the respective repositories. It would also be able to explicitly persist both events and applications using their respective repositories.
Take a look at Effective Aggregate Design by Vaughn Vernon for ideas on how to determine ARs in your domain.

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.

Categories