I'm new to PHP frameworks and to start my venture I went to try FuelPHP. After a few days of testing around I understood how things work. Controllers control the actions, views control the $content and the template controls the layout. But what about models, What are they for?
Models are abstractions over data stored elsewhere, they encapsulate the data access through standard object creation, method calls, property access, etc. just like ordinary objects. The main idea here is that the controller (or whatever object that requires the data) doesn't need to know how to get the data or how it's stored. It could be stored in files, web (via webservice), database, whatever thing that could persist data. The data could be retrieved with webservice request, database query, file reading, etc.
For instance, "gimme student record with id 1" could be as simple as student := new student(1); and after that you have access to the student's name, address, etc. But how does the student retrieve its data? Where does it store the data? It's out of concern and could be tuned (or should be tunable) as needed.
models controle your data and have a direct contact with your db have a read here
You might have say
Contact With ID,Name,Detail and ContactType properties.
The idea is to keep it minimal it's basically something to cart around all the useful properties of an entity.
This is the current definition of MVC. Nothing about the backend in it. That would be some seperate library / dll that only knows about model, and how the underlying data is stored in the DB.
Related
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.
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.
I am working on this app that accesses session variables in the model layer. This just seems wrong but am willing to be proven wrong. Maybe not wrong but, in most places in app, session variables are handled in controller and passed in as arguments but, in other places, the session value is just accessed. Am I wrong that this seems like bad practice?
edit:
one reason I don't like sessions in models is that it seems to make it more complex to test. Keep it as just params passsed to functions and then recordset passed back.
thx
It depends.
The way I think about this is such:
A Model represents your data layer.
most of the time that data layer will be DB Table based
The Session is just another data storage medium.
Conclusion: If the data that your model represents is stored in the Session, than it is OK to access that data from within the model
An example is a Session based shopping cart. My cart's objects are models of my session data.
Controller shd do a check weather session exist or not before using the model which uses that session inside it .
No it shouldn't. The storage type, should be apart from your business logic. For example:
I have one simple plug-in that perform the access check and put the user object on the registry. So, instead of access session, the model have access to the registry, which is well defined.
$User = Zend_Registry::get('User'); // User model object
From the theoretical point of view, everything should be accessed through data mappers. In the future, if you change from session storage to something else, you'll need to update it just in one place. Your models do not need to know from where the data came from.
If you are taking more than one path to get your data, probably this will cause some problems when your application get large.
The OOP and layered systems approach suggestion is to created specialized objects and layers and keep things simple preventing specific actions to be spread all over the code.
But again, you do not need to change that unless you see advantages.
Keep in mind that sometimes refactoring is more efficient than try to predict everything.
What's stored in the session variables? If it's simply 'logged in? Y/N', then they probably don't need to be part of the model layer. If, however, it's more complex than that, they are probably inextricably linked to your business model and should be treated as such.
The examples at the bottom of the Zend Test documentation show how to test the full MVC using a login function. Presumably you could do the same when testing models?
I am searching for a database abstraction layer in future PHP projects. Until now I have worked with plain SQL-commands and arrays on the one hand fully featured ORMs like Doctrine on the other hand.
I don't like ORM because most of the time the job is to get a list of data from the database and to send it to the template engine. Both work fully fine with arrays and there's no need to make it all complicated by capsule the data in an object when the template just needs the plain array. I don't like the plain-SQL approach either because for the simple CRUD stuff I have to write everything myself and also I don't like to maintain two models of my data (one in the DB and the other within my database access object).
Is there something which let's me define the model one time only and generates the elementary stuff for me (like in Doctrine) but which saves me from the active record pattern?
The db is not a model, its the raw data source, and the model is, in thoery, more than just the data fields, it should also be the methods that affect the model's data.
You are always going to have to tell the program what to insert and where into the db, even if you use a library that encapsulates the sql or if you write it yourself.
If you find yourself writing the similar "insert" and "select" commands over and over, then its time to design some functions or classes.
So I am a little confused on the object oriented part of PHP. Right away I will apologize for the fact I know very little about PHP and databases.
My question is when you are making, say, a database to hold users in it, why would you want to make a class/object for that user when you can just pull info from the database?
Also, if you were to make a object/class where is the data for the objects stored? For example, if I have a class with a username and email, and I make that object, were does it get stored?
Thanks for taking your time to help a learning noob!
My question is when your making per
say a database to hold users in it,
why would you want to make a
class/object for that user when you
can just pull info from the database.
You make objects to abstract away specific functionality. What happens if you move to, say, Microsoft SQL Server (hypothetically speaking)? Rather than update your entire site, you just edit the implementation of the object.
Also if you were to make a
object/class where is the data for the
objects stored? Like a class with a
username and email, and I make that
object, were does it get stored.
The same place as any other variable.
There are a LOT of reasons why you want to use some abstraction on top of just raw database access in any reasonably large software system. If you're looking at an Object Oriented approach you should consider that one of the core ideas of the Object Oriented paradigm is that an object encapsulates both data and logic that acts on that data.
Let's take a concrete example. Say that a part of your application (the UI) needs to display user information, including a nicely formatted user name. In an OO world you could have a User object which would store a local copy of the data in the database, and expose methods like getFormattedName(), or something similar. Now the rest of your application can use that code without needing to know about the database, or even how the name is formatted. On the other hand if you were just pulling data directly from the database then the UI part of the application (which doesn't really care about databases) still has to know itself how to get information about the user from the database, and how to format the users name nicely.
To put it simply, there are logic not captured in a database table but related to the entry. The database only stores the raw data. How the data is used and how it interacts with the rest of your application should be captured in your object methods.
You're missing a fundamental of object-oriented design. Ignoring inheritence entirely, Objects combine information/data and functions/procedures/operations into a single unit called an object. This object performs operations (methods/behaviors/functions/procedures) and has attributes. A database will not have the entire set of operational/procedural information. By design, a database will only contain data, and know nothing of how the data can be used or what the data does.
Databases store data in a tabular fashion which is designed to be speedy. Objects are so much more flexible; they can be trees, they can be lists, they can be widgets, or anything else out of a million things. They can represent presentation, data, or structure. And sometimes they are even faster (when it's easier to calculate a value on the fly rather than retrieve it from a database). Databases are very powerful and important but are only appropriate for a small subset of the tasks that a web application performs. The rest are made easier by objects.