Currently, I have a structure like this:
Domain Model <---> Data Mapper ---> Database
Say I add a child 'file' object to a 'project' object. I want to automatically create a child 'note' object for that project signifying the update. Right now, the creation of this note is handled by the 'project file mapper' -- within the 'uploadFile' method, a new note is instantiated and populated, and a call is made to the 'note mapper' to save that note. The project invokes the note mapper when asked for its children notes, and so on with files.
Or say I delete a 'project' object -- I want to delete the children notes and files as well, so within the 'projectMapper' method 'deleteProject', a call is made to both 'projectNoteMapper' and 'projectFileMapper' to handle deleting those files.
There are other instances I am beginning to encounter now, especially since implementing a private messaging system. I want users to be able to subscribe to projects and tickets and receive messages about updates. I also want to implement deep logging of user action (including storing of serialized objects for tab-keeping.)
I understand that the way I have been doing things does not conform to the 'single responsibility principle' -- after all, the purpose of a mapper should only be to map information between data sources and their respective objects, right? My question is this -- what is the next 'layer' I should be implementing, what am I missing? I have read about 'Repository' and 'Service'.
If I understood your problem, then i think might help t clear it up:
DataMappers are not representation of, nor corresponding to single table in database.
In you case with projects, it would make a lot of sense for $projectMapper->remove( $project ) to delete, not just the project itself, but the all the associated items in DB. There is nothing wrong with DataMapper making more then one query. You just need to implement the accompanying setup for error reporting, to know when/if something went wrong.
And yes, this too violates SRP in some aspects ( but only if you view each change in DB as a separate reason for modifying the DataMapper class ).
As for which is the next logical step for evolving Model layer : you will find this PoEEE entry relevant. Just keep in ming that Service layer is not just an API on top DataMappers and Domain Object. It also contains services, that are somewhat independent from rest of module. Like mail sender(s) and authentication.
Also, to clear this up:
Model is not a class, but a layer, which contains both Domain Objects [1] [2] and DataMappers.
Related
How are you meant to store the state of the model in MVC when the model is a layer, and accessed via services. Do you give the service class a state? How would that state be communicated to the View, when the View may or may not use that specific service?
I currently have a model entity to store different states, all my services log their issues, successes and state in this entity. I store this entity in the session, but the whole thing feels wrong...
I am considering that state is more than error/success.
If your views never know which service has been used by controller to alter the state of model layer, then your best approach would be instead implement classical MVC (or close to it) with current view observing the model. In that case each used service would inform the view, when it has been acted upon by controller. If that's the case, then content below does not apply.
The bad idea ..
The views and controllers should share the factory, which is responsible for initializing the services. this means that if you controller has used a particular service, then you can add an ability to query this factory about services that it has initialized already.
if ( $this->serviceFactory->hasCached('recongnition') )
But that should not be necessary and IMHO, that would be a really harmful thing to do. You would be forcing the factory to become a vital part of UI logic.
Note: the factory in this case enforces, that each service is create only once, without dependence on global state.
Different approach/perspective
For some reason, you start out with a premise, that every view has to be omniscient. That's what causing you current confusion.
Instead of knowing everything about everything the two fictional services:
Accounting: for dealing with invoices
Library: for managing documents
When you are looking at the page, which list the current document, why would the view care, that there is an error state in Accounting service? How would you actually achieve that error state?
Would an error state in any of those services affect how the "login page" looks like?
So. The bottom line here is this: even if controller does something, which causes an error state somewhere in the model layer, the view should only know about it, only if the view needs that particular service.
Note:Of course since in web applications the views and controllers tend to form pairs (if there is controller for handling "Document List", then there probably will also be a corresponding view), it will be and extremely rare occasion, when controller utilizes some service of which the current view is not aware of ... I actually cannot think of a use-case for such occurrence.
P.S.
Actually the state of model layer is not held in the services themselves, but in the domain objects which they manipulate.
If you use a shared factory, which can make sure that each service is initialized only once, then the service, that view uses, will be the same. It also means, that the domain objects, with which service worked, can still be there (depends on your implementation, of course).
For example, if you try to create user account, with an email that already exists, the domain object for representing the account details will acquire an error state, when storage abstraction gets an exception about violating UNIQUE constraint. To show a good "registration failed" page, the service will need that domain object with both its data and its error state.
I hope it helps
I started some time working with the Yii Framework and I saw some things "do not let me sleep." Here I talk about my doubts about how Yii users use the Active Record.
I saw many people add business rules of the application directly in Active Record, the same generated by Gii. I deeply believe that this is a misinterpretation of what is Active Record and a violation of SRP.
Early on, SRP is easier to apply. ActiveRecord classes handle persistence, associations and not much else. But bit-by-bit, they grow. Objects that are inherently responsible for persistence become the de facto owner of all business logic as well. And a year or two later you have a User class with over 500 lines of code, and hundreds of methods in it’s public interface. Callback hell ensues.
When I talked about it with some people and my view was criticized. But when asked:
And when you need to regenerate your Active Record full of business rules through Gii what do you do? Rewrite? Copy and Paste? That's great, congratulations!
Got an answer, only the silence.
So, I:
What I am currently doing in order to reach a little better architecture is to generate the Active Records in a folder /ar. And inside the /models folder add the Domain Model.
By the way, is the Domain Model who owns the business rules, and is the Domain Model that uses the Active Records to persist and retrieve data, and this is the Data Model.
What do you think of this approach?
If I'm wrong somewhere, please tell me why before criticizing harshly.
Some of the comments on this article are quite helpful:
http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
In particular, the idea that your models should grow out of a strictly 'fat model' setup as you need more seems quite wise.
Are you having issues now or mainly trying to plan ahead? This may be hard to plan ahead for and may just need refactoring as you go ...
Edit:
Regarding moveUserToGroup (in your comment below), I could see how having that might bother you. Found this as I was thinking about your question: https://gist.github.com/justinko/2838490 An equivalent setup that you might use for your moveUserToGroup would be a CFormModel subclass. It'll give you the ability to do validations, etc, but could then be more specific to what you're trying to handle (and use multiple AR objects to achieve your objectives instead of just one).
I often use CFormModel to handle forms that have multiple AR objects or forms where I want to do other things.
Sounds like that may be what you're after. More details available here:
http://www.yiiframework.com/doc/guide/1.1/en/form.overview
The definition of Active Record, according to Martin Fowler:
An object carries both data and behavior. Much of this data is persistent and needs to be stored in a database. Active Record uses the most obvious approach, putting data access logic in the domain object. This way all people know how to read and write their data to and from the database.
When you segregate data and behavior you no longer have an Active Record. Two common related patterns are Data Mapper and Table/Row Gateway (this one more related to RDBMS's).
Again, Fowler says:
The Data Mapper is a layer of software that separates the in-memory objects from the database. Its responsibility is to transfer data between the two and also to isolate them from each other. With Data Mapper the in-memory objects needn't know even that there's a database present; they need no SQL interface code, and certainly no knowledge of the database schema.
And again:
A Table Data Gateway holds all the SQL for accessing a single table or view: selects, inserts, updates, and deletes. Other code calls its methods for all interaction with the database.
A Row Data Gateway gives you objects that look exactly like the record in your record structure but can be accessed with the regular mechanisms of your programming language. All details of data source access are hidden behind this interface.
A Data Mapper is usualy storage independent, the mapper recovers data from the storage and creates mapped objects (Plain-old objects). The mapped object knows absolutely nothing about being stored somewhere else.
As I said, TDG/RDG are more inwardly related to a relational table. TDG object represents the structure of the table and implements all common operations. RGD object contains data related to one single row of the table. Unlike mapped object of Data Mapper, the RDG object has conscience that it is part of a whole, because it references its container TDG.
So I've been studying the role of the repository pattern as a means of decoupling the persistence layer from my models in an MVC framework. Prior to this, I might have my UserModel calling active record methods directly in order to store/retrieve domain objects.
Here's a sketch of what I'm thinking in regards to the call stack in a request that should create a new User:
Here are my questions:
Is this a correct implementation of the repository pattern?
I understand that the controller should take the user's information from the request and pass it into the model. How does that usually happen? Should the controller create a User object and then pass that into the model? I sure as heck don't wanna just pass in an array of values into the model--nor do I want to pass in 15 arguments to the model method that creates a user.
In order for this pattern to really work, it looks like to me I would need to have a domain object that is just a simple data structure with no behavior and then if I'm using an ORM, I would have an ORM object which will describe how the object is persisted. Initially I resisted this because it feels like duplicate code, but if I'm really separating persistence from the business logic, this would be needed right? For example, what if I went with an in-memory store? I would no longer use the ORM object.
Am I thinking correctly here? Is this acceptable. Please help me connect the dots in my head.
1. Is this a correct implementation of the repository pattern?
I'm not sure where you been doing that research, but you have got it wrong.
Repositories as for separating the domain objects from data mappers.
There no such thing as "models". Model in MVC design pattern is one of the to main layers: presentation layer and model layer.
And the repository pattern is incompatible with active record (anti)pattern, which combines domain and storage logic in single instance, thus causing a major SRP violation.
To use a real world example for, when and how to use a repository here is an example:
You are creating some document management tool, where said documents can come from several sources (for example: local SQL database, SOAP service and cache). In this situation you create a repository, which deals with the "routing" of storage. It is the part of application, that decides which data mapper to use for storing/retrieving each document.
The goal of repository is to separate the domain logic from the interaction with storage. For the system, that was described above, a repository would also let add new data sources, without need to rewrite large amounts of code (if any). You could just add another type of mapper for the document.
2. Should the controller create a User object and then pass that into the model?
To begin with, controller itself should not create anything. Instead your controller should use a factory for acquiring instance of the object that you need. This factory can be provided to the controller through constructor or some other method. This is called: Dependency Injection (to learn more about it, watch this lecture).
Also, as noted above, model is a layer, not any specific class or object. The responsibility of controller is to alter the state of model layer (by passing data to it). You could interact with domain objects and mappers (or repositories) directly in the controller, but it would mean leaking some of the business logic in the controller. It is recommended to instead use services, which then manipulates said domain objects and storage related structures.
As for the issue with 10+ parameter, that you would require for creation of new user account, let's assume you have action with following footprint:
public function postUser( Request $request )
{
....
}
If the action gets called with specific Request instance, you have two options how to deal with large amount of parameters:
Wrap the instance in a decorator, which would let you call a single method for forming the data from request in a specific array. Then you pass this array to the service(s).
Form the array inside the controller's action and pass it, where th data is required.
The former solution is more suited for large scale applications, where such formation of data would be required repeatedly though-out the code. But in a small/medium projects the second option is the common-sense approach.
Thing is, the job of the controller is to take the user's input, and distribute it to the model layer and current view. And formation of such array fits right-in with this mandate.
3. (..) main object that is just a simple data structure with no behavior and then (..)
No. Domain object is not "simple data". It is where most of the domain business logic resides in the application.
And forget about magical ORMs. First step for implementing a repository is to separate the domain and storage logic. Domain object handles the validation and business rules, mapper deals with persistence and data integrity (small example here).
Another thing that you must realize is that repositories for web application do not really interact with in-memory persistence (apart from cache). Instead your repository would be juggling mappers for different data sources.
Should the controller create a User object and then pass that into the model?
I'm not sure what you mean by "pass that into the model" -- the User object is the model. "Controller" and "model" represent different layers in the design, they are not specific objects, and there shouldn't be a separate UserModel object as you mentioned.
The repository interface itself is generally considered part of the model, though the domain objects shouldn't be saving themselves -- this should be done in the controller.
Your controller's job would then be to interpret the request and create a User object, then use the repository to save the user:
$user = new User(...); // based on Request
$repository->save($user);
it looks like to me I would need to have a domain object that is just a simple data structure with no behavior
This is not true, you can and should encapsulate behaviour in your domain objects. As for how persistence is actually implemented, a good ORM should take care of most of the details and you shouldn't have to create additional classes by hand.
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.
By business model, or business objects, I mean plain old objects like a "User" with all their properties name, adress, ...; in addition to all the user properties let's say each user would have an "AppointmentBook" object, each book has a set of "TimeSlot" objects, etc.
The business model has objects with references between them, at least that's how I code a business model in Java.
Here comes the question:
To intialize my business objects, in Java, I would
fetch all of the data from DB only once during application
initialization,
map data from my DB to my business objects
store in memory (maps) and they would be shared across all the requests.
PHP's Share-Nothing-Architecture is confusing me for proper OO programming:
If I use the same logic, I would have to fetch all the objects from DB, for every request (I know I could still cache, but you don't cache all of your DB, it's not a question about caching but rather about the way of programming in PHP and its architecture).
So let's say that for one HTTP request, I just need the User properties and I don't need to access his appointment book. It would be a pitty to fetch all the data from the DB for all the objects the User makes reference to, as I just need his properties. This means that I will initialize PHP objects from my model with a lot of NULL values (NULL because of the objects contained in User that I won't load) which can later on lead to errors.
I was wondering how professional PHP developers usually use their business objects?
(I'm coming from Java)
UPDATE: It was kind of stupid to say that I would load the whole database into memory during application init in Java. What I rather meant is that, if I need to fetch a specific user, I could just load all of its data and that would be accessible through all the requests.
In PHP you do not keep all the data of your domain business model in the memory. Instead you only request from DB ( though cache, if needed ), the data you want.
Model layer in php should be built from multiple domain object and data mappers ( i assume, that part is not so different from Java ). If you need User details, then you fetch only that information from database/cache. You most likely will have a separate mapper just for dealing with user(s).
You display the information about that user, and forget about the query. Next request (when and if it comes) will require different information. Maybe you will want ContactList for that User ... then you really do not need user itself, only his user_id. Again, you let you mapper to fetch data into the domain object responsible for handling contact list, and if contact list contains User instances, then just create them, but leave in "unfetched" state (object knows only own user_id). Fetch them only if you really need to, and only the parts which you will use ins that "view".
P.S. you might have notices, I told that model later should be segmented, but quite often php developers just create single class of each DB table (which implements ActiveRecord) and call it "model". This is a result caused by Ruby on Rails influence on php framework developers, which, IMHO, is one of the worst things that has happened to PHP in past 5 years.
Your Java example implies your storing your entire databases content in memory. If your doing that, what's the point of the database? Why not just create all those object and memdump them for persistence.
If I use the same logic, I would have to fetch all the objects from DB, for every request
That's simply madness, you don't need to fetch anything, you create new instances when you need them and destroy them when you no longer need them.
So let's say that for one HTTP request, I just need the User properties and I don't need to access his appointment book.
That's easy, redesign your user. Your user needs it's properties and a property called appointmentBook which is simply an array of appointment book ids.
If you actually need those appointments you can fetch them from the database later.
This means that I will initialize PHP objects from my model with a lot of NULL values (NULL because of the objects contained in User that I won't load) which can later on lead to errors.
Not really, if this is the case your User object is too big. Make it smaller, you should load the entire user. Except of course the user has to be small enough for you to sensible load it.
If you don't want that then you can always create a UserProperties class and let every User have one. When you load the User you load the properties, but you also have an option to create the properties seperately.
Even in Java you would not load all data from the database into memory. You can however - as you write - often load more compared to short Transaction Scripts you normally have in PHP.
You models should be "clever" then to only load the data from the persistence storage that is needed to perform the requested action. This requires the object to be "clever" enough to lazy-load data probably.
This can be achieved with a Domain Model that knows enough about itself and a Data Mapper that knows enough about the storage for example.
There are other patterns as well which might suit your needs depending on the type of application, however a Domain Model together with Data Mapper is quite flexible.
An exemplary data mapper in the PHP world is Doctrine.