I am writing a Data Mapper in PHP and am trying to work out how to implement an Identity Map when my domain objects follow Class Table Inheritance.
The problem, as I see it, is that an Identity Map cannot guarantee that data is manifested only once in the in-memory model because hierarchical objects are relying on hierarchical data.
For example, in my database I have a Parent table and a Child table. In my domain model I have a Parent class, and extending from that, a Child class. I can instantiate both a Parent object and a Child object, and record their identities in an Identity Map, no problems. If client code requests the same Parent or Child, I can return it from my cache, rather that the database, no problems.
But what happens if the Parent and the Child both relate to the same parent record? i.e. the same data in the Parent table? I now have that data represented twice in-memory, and if it's modified in one (or both instances) I risk overwriting the changes.
It seems to me that somehow the Identity Map needs to follow a hierarchy similar to the Domain Objects and Mappers themselves, however it gets a bit complex at that point. Also, I have lots of Dependent Mappings to take into account too.
Any ideas/advice much appreciated!
If you find you have lots of repeated/duplicate data, the design is wrong...
I.e. if you're parent has say an address which is shared by a child, you should have an address table, and each of those records will point to the single entry in the address table etc.
Then it's a case in you're app to have the relevant rules, i.e. if address is changed in child account... what do you do? update (which means parent will also have new address) or insert a new one.
I defined an interface, iQueueable, and only objects which implement this interface may be queued to have their changes written to the database.
Child objects have the full complement of object properties, so they implement iQueueable. Parent objects can not be queued.
This still allows parent and child object to fall out of synchronisation, but now there is only one source of database changes.
Related
I develop an application that allows to access two different ERP systems. I want to abstract away some differences, such that I can search the same entity in both systems and represent a list that contains entities of both (e.g. a list of invoices). I'm thinking about how to architect this.
One approach is using the ActiveRecords pattern, have a Document class that extends from ObjectModel and then create two subclasses that each contain the database field to object property mapping. I feel it is cumbersome, because these object then represent a single instance of a Document, and still need to handle queries that result in a collection of documents.
I never touched doctrine2, but as I'm reading about Active Record vs Data Mapper pattern, it seems that it could bring a solution to my problem. Therefore my question:
Is it possible to have one object (here Document), and link two data mapper configurations to it, one for each data source ?
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.
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.
Put simply about Table Data Gateway (TDG) implementation: you create separate TDG class that contains SQL for CRUD operations with concrete table. So, your models communicate not directly with a datasource (for example database) but via those abstracted ones - TDG classes. So, it's just an approach for making another level of abstraction and it's just a wrapper for communicating with database - get and modify the data. IMHO TDG classes should not contain members, only methods. Here's a good schema that visualizes the use TDG pattern. When using TDG approach, SQL should be moved from model classes to datasource (TDG) classes. And all data that I retrieve from DB through TDG classes are stored in my model members.
Now, what about active record implementation? If I would merge data access and my model class into one model class then would I implement active record? I was unable to find a clear distinction or how those patterns look in PHP and differ from each other.
Often, I'm having one singleton database class and then separate model class for each database table. Each model class has CRUD + several custom (count, avg and etc.) operations. Some classes have members for persisting results from CRUD or custom operations - thats's done upon the need. Could this approach be identified as active record? Also, if I would move SQL from my model classes to TDG classes would this be Table Data Gateway?
From http://martinfowler.com/eaaCatalog/index.html
Table Data Gateway: An object that acts as a Gateway (466) to a database table. One instance handles all the rows in the table.
Active Record: An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.
The obvious main difference is that TDGs wrap access to a table and only returns row data, while ARs wrap access to a row in the table and adds business logic to it.
Unless you have very low impedance mismatch, having a TDG is preferred because with AR your business/domain objects follow the structure in the database, which us usually not how your domain objects should be modeled. A Row may know how to persist itself, but a Person should not know. It is more maintainable in the long run to to separate persistence logic and domain logic.
Regarding your Singleton DB object have a look at Is there a use-case for singletons with database access in PHP?.
All,
Building a small web app using PHP. I don't have much programming experience.
In my app, I have created a class to access DB records which I call DAO_DBrecords. The class includes basic functions to create new records, update existing records, etc. Currently, the class satisfies all my DAO needs for all my DB tables. In the functions, I pass as one of the argument a string that represents the DB table (users, articles, etc).
At this point I could do either of 3 things:
Use this class throughout my program whatever the type of record (i.e., table) I'm dealing with.
Create specific classes for each type of record (e.g., DAO_Users), which inherit from DAO_DBrecords but are otherwise empty.
Create specific classes for each type of record (e.g., DAO_Users), which inherit from DAO_DBrecords and specify the DB table the class can access via a variable (e.g., private $table = 'users'). In the parent class, the variable would be null, or an empty string.
Again, at this point I am not envisioning the need for table specific functions (but that might change).
Which of those (if any) is the right approach?
Thanks,
JDelage
Edit: I have edited option 3 which previously read:
3. Create specific classes for each type of record (e.g., DAO_Users), which inherit from DAO_DBrecords and specify the DB table the class can access via a constant (e.g., const TABLE = 'users'). In the parent class, the constant would be null, or an empty string.
I will choose the 3rd option. In DAO_Users you can eventually put methods to do specific things on the user record itself (for example, create and store a salted password, send verification email, fetch all user's friends from the database as DAO_Users collection, fetch all user's comments, etc).
In this way you can both use a DAO pattern and organize all app "actions" in classes by action target.