I've been looking at Laravel for awhile and I decided to finally pick it up. It's my first time using a PHP framework and I'm having some trouble grasping the purpose of the models.
I've been reading a lot of newbie guides and this is pretty much all that is in their model (Laravel wise),
class Model extends Eloquent {
}
And then in their controller they do something like this,
$model = new Model;
$model->text = "text";
$model->save();
I'm no expert at the MVC pattern (probably the biggest newbie out there) but I thought the whole point (or at least a small point) was to separate a lot of actions. And that the model was supposed to be responsible of handling everything DB-wise. So in a way, this seems wrong to me or at least not the best practice.
But if you start setting up a bunch of functions you could run into the issue of having one model for every table. Which again, doesn't seem right. So you have to make the model, in a way, ambiguous. In the sense that it can take any actions against any table?
It all just seems really confusing to me at the moment.
You are going to need a model for evey table, because there are other things related to models that cannot be shared, like column names and validation, but if you think you are repeating yourself, you can create a BaseModel and add all methods or even overload Eloquent methods in it:
class BaseModel extends Eloquent {
public function whatever() {
}
public function save(array $options = []) {
// do what you need to do
parent::save();
}
}
Then create your models using it:
class Order extends BaseModel {
}
But you don't need much on a model, if your models and tables names follows Laravel pattern (in this case the table name would be 'orders'), then you just need this simple declaration to have a model working for your table.
Edit:
Controllers are meant to transfer data from a model to a view, but they should not know too much about your data, almost everything about them should lies in your models ("Fat models, skinny controllers"), so they need to know just enough to have "control".
class OrdersController extends BaseController {
public function process()
{
$order = Order::find( Input::get('orderId') )->process();
return View::make('orders.showProcessedOrder')->with('order',$order);
}
}
Models are a wrapper around your database tables. Your database tables are the real-world things you are making your application about. Models allow you to use your programming language for CRUD'ing (creating, reading, updating or deleting) data. OOP is all about classes and objects, and converting things like incoming HTTP requests and data storage into that form.
Your question is a good one. When you learn how to make Web applications, having a three-tiered web app - a presentation layer, a business-logic layer and data-storage layer with data stored in a relational database - works great, and it makes no doggone sense to add an extra layer of database-related stuff in the code.
And, like Antonio wrote, in MVC programming, "fat models, skinny controllers" is what you're working towards. The controller ideally should just be a couple of lines of code that pass the incoming request to the correct model where it could be validated, added to the database, etc. (But it is easiest to put that in the controller while you're first learning/figuring MVC out.)
Related
I've noticed that all my models look very similar. Most of them tend to follow a pattern where they are collections of methods containing active record code that are just slight variations on one another. Here is an example:
class Site extends CI_Model {
public function get_site_by_id($id)
{
// Active record code to get site by id
}
public function get_sites_by_user_id($user_id)
{
// ...
}
// ...
public function get_site_by_user_id_and_url_string($user_id, $url_string)
{
// ...
}
// Non active record methods and business logic
// ...
}
This approach has worked fine for me but I'm wondering if there is a more elegant solution. It just doesn't seem right to me that I should have to create a new method every time I need to look up data in a new way. Is this common practice or am I missing a way to refactor this?
Strictly following your request, you could add an intermediate class between the main model class (CI_Model) and your class (Site), something like
class MyCommonMethodsClass extends CI_Model {
}
and you would extend it in your classes (Site), while putting the common code on it. That would work and could be somehow'elegant'. In fact at the end you would end up adding your basic crud, site adapted actions, to it.
Now, if that's 'clean', that's another thing. Again, strictly speaking the model does that. It takes care of common and 'advanced' getters. And yes, they almost always have the tendency to have the same code all around your website. The problem is that, although that looks nice in your code (less code) you're technically sacrificing abstraction between your business logic and the db. Are you a model purist or practical one ?
I think this is matter of opinion but I think best practice is to create some sort of Create, Retrieve, Update, Delete (CRUD) model which does many basic SQL functions like GetID, UpdateByID, GetById and so on.
CRUD models can only go so far in helping you with more modular queries. But it makes sense to call a function called GetId and pass it some parameters than to have different functions for each table.
As I say though, CRUD's can only go so far. For example it would make sense to have a function that queries a database users table to check if a user has verified and username & password match. As this is a unique and not an abstract function, it should have it's own function defined.
Also as a best practice, Logic and Database access should never be mixed in the same file.
It is common practice to have different methods to handle getting your data like that. The Single Responsibility Principal states that every object should only do one thing, by making multiple methods that get very specific data you are creating very maintainable and easy to debug code.
If you have multiple classes that are providing essentially the same functionality, then this would suggest that there may be something wrong with your class hierarchy (a so-called "code smell"). If they have similar interactions then that suggests that they are related in some way. If that's the case then the chances are they should all be inheriting from a common superclass that implements the functionality common to all your subclasses, with each subclass simply specializing the generalized functionality of the superclass.
The advantages of this approach are:
You're not repeating work (SPOT, DRY)
Code that interacts with the classes can be written in a more general way and can handle any object that inherits from the superclass (substitution)
I do not think there is any thing wrong with creating an 'base' model class to extend you other models by. If it is solid and well tested, it can make you life easier. What is the point of creating the same CRUD functions over and over again?
Another benefit of doing it is that you can have a base development repository that you clone to start all new projects.
If you need an example of how to do this then look at a question I previously asked.
You can also do the same with your controllers.
I've recently delved into using an ORM in my CodeIgniter application and one i've gone for is Propel. Now this gives me the power to basically use Propels classes as the 'Model' but is this bad practive?
So my controller code would be as follows:
<?php
class Page extends Controller {
function __construct() {
parent::__construct();
}
function index() {
$foo = FooQuery::create()->limit(10)->find();
$data['content'] = array('foo'=>$foo);
$this->load->view('home', $foo);
}
}
?>
I want to solve this issue before I carry on developing my application. An example of how I should do this would be very helpful if you do consider this to be bad practice please.
Thanks in advance
Yes, it's bad practice.
The model should contain all of your data logic and abstract it all away from the rest of the program. To the rest of the application, the models should look like black boxes out of which it gets its data. If you use an ORM as your model, you're leaking the abstraction and tightly coupling your controller to your data layer.
Instead, create your models, and deal with the ORM in there. That way if you ever need to adjust your data model, you can just change it in one place (the model layer) and know that the abstraction will hold.
With the Query classes Propel now uses, I think the difference with a more "formal" Model becomes smaller and smaller. If this will become a library that you release into the world it would be an advantage to have an abstraction layer so you can have different backends, but if it is an in-house application I would just use the Query classes as your Model.
But remember that the Query classes are created to feel like an actual object, and that they hide the relational part as much as they can. You can use this to your advantage. Check out this article about rewriting your SQL queries with Query methods, especially the third answer: move more and more into your Query class, so your Controller doesn't feel like it uses a database.
// Instead of this code in your controller,
// tightly coupled to your database logic
$books = BookQuery::create()
->filterByTitle('%war%')
->filterByPrice(array('max' => 10)
->filterByPublishedAt(array('max' => time()))
->leftJoin('Book.Author')
->where('Author.Name > ?', $fameTreshold);
// You would use this code in your controller
// and create small methods with the business logic in the BookQuery class
$books = BookQuery::create()
->titleContainsWord('war')
->cheap()
->published()
->writtenByFamousAuthors();
I've found this to be an occasional necessary evil when your ORM is following the Active Row pattern.
The problem I always run into is that a model only represents a single instance of the data structure. It makes no sense to add collection retrieval methods into the model.
This is where I have historically used a service layer to handle pulling in collections of models. Although to be honest lately I've simply wrote a controller helper object that just abstracts my table object.
It depends a lot on what you are doing and why. in this example you are putting a limit clause in the query - is that business or display logic? From my perspective, it's hard to argue that it's business logic - that I get back 10 elements is irrelevant to the model - that's just how many I think makes sense to using in one page. If you want that rule to be consistent across controllers, you could set some config value to enforce consistency. But putting it in the model just makes the model needless large (there's a difference between fat models and obese models)
I would say that limits, orders and offsets are often not business logic. Even a simple where might or might not be depending on the case. If there's a join there, it's a sign that something is wrong.
The example from Jan Fabry is mostly pretty good. filterByTitle looks about the same to me as titleContainsWord. filterByPublishedAt(array('max' => time())) is much worse than ->published(). In general, the less you controllers need to know about the inner data structure, the better.
I have a practical doubt ,
I am using OO php , and i am new to it. I am using zend framework to be clear.
I am writing controllers(class) and actions(methods) with in it say PatientMapper.php which has all single mysql table related actions and Patient.php which has all setter and getter functions.
I get a doubt that when should i write a new controller.
Should i write a controller for all the actions on a single mysql table .
or a single controller for all actions related to a module.
As opposed to the previous answers, I would say that your controller should not be related to your DB.
Controllers don't handle business logic, your models do.
Besides that, you can write a controller for each entities.
User is an entity, which can be wrapped in a controller, even if it depends on several tables.
If your controller is getting bigger and bigger, you can switch to module (Zend Framework terminology) and create an User module, which has an Account controller, etc...
I think you should write controller for single mysql table, because if your application will grow up you can end with few thousand line controllers.
A controller groups actions that conceptually belong together somehow. The controller might use one specific model class (which is not necessarily a database accessing class) only, but it may also use many of them.
Important is, that the controller should not contain the logic of the model classes. The sole responsibility of a controller is to receive and delegate the input for a specific interaction you allow users to do with your application to the model. And in webbased MVC, it is usually also responsible to update the View according to the result of the operation.
The most important distinction one has to understand in MVC is that M should be able to live on it's own while V and C belong together. V and C form just the UI to your application and they should not do anything beside that. Basically, your M is your application, while your VC just sits on top of it. Should really be M|VC imho
With that said, if you feel your application can get away with a single Controller, then use a single appController. But once you find yourself adding actions that could conceptually fit into a separate controller, then add a new controller. If your application is a simple CRUD app, then have one controller per database table. If it does something else, then give it something that fits the scenario.
IMHO I would suggest a action for each mysql table related action
for maintainability. These would be ligtweight actions that just call your model for that table
#gordon - Yeah my application is a CRUD application. SO i need to create a model for each table..This is the most accepted way rite. And yeah i am bit clear abt controllers..
i have a page where in i need data from 3 tables. So i will need to call all 3 model methods to get the data rite...
I have a small doubt...i use code like this at the beginning of the beginning of class .and this was written by other developer....i am using it.. i am finding it difficult to use joins ,bcos this is locking the DB..any help on how to use joins over here
protected $_dbTable;
public function setDbTable($dbTable)
{
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (!$dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception('Invalid table data gateway provided');
}
$this->_dbTable = $dbTable;
return $this;
}
public function getDbTable()
{
if (null === $this->_dbTable) {
$this->setDbTable('Application_Model_DbTable_Appointment');
}
return $this->_dbTable;
}
this is the select part..not able to use join
$select = $this->getDbTable()->select()
->from("patient_appointment",array('pa_pd_patient_id',
'DATE_FORMAT(pa_datetime,"%h:%i %p") as pa_time','pa_datetime','pa_um_id'
,'pa_created_date','pa_mode','pa_type'))
->where('date(pa_datetime) = ?', $date)
->where('pa_pd_patient_id = ?', $patientId)
->order('time(pa_datetime)');
$resultSet = $this->getDbTable()->fetchAll($select);
I'm seriously confused about the concept of the 'Model' in MVC. Most frameworks that exist today put the Model between the Controller and the database, and the Model almost acts like a database abstraction layer. The concept of 'Fat Model Skinny Controller' is lost as the Controller starts doing more and more logic.
In DDD, there is also the concept of a Domain Entity, which has a unique identity to it. As I understand it, a user is a good example of an Entity (unique userid, for instance). The Entity has a life-cycle -- it's values can change throughout the course of the action -- and then it's saved or discarded.
The Entity I describe above is what I thought Model was supposed to be in MVC? How off-base am I?
To clutter things more, you throw in other patterns, such as the Repository pattern (maybe putting a Service in there). It's pretty clear how the Repository would interact with an Entity -- how does it with a Model?
Controllers can have multiple Models, which makes it seem like a Model is less a "database table" than it is a unique Entity.
UPDATE: In this post the Model is described as something with knowledge, and it can be singular or a collection of objects. So it's sound more like an Entity and a Model are more or less the same. The Model is an all encompassing term, where an Entity is more specific. A Value Object would be a Model as well. At least in terms of MVC. Maybe???
So, in very rough terms, which is better?
No "Model" really ...
class MyController {
public function index() {
$repo = new PostRepository();
$posts = $repo->findAllByDateRange('within 30 days');
foreach($posts as $post) {
echo $post->Author;
}
}
}
Or this, which has a Model as the DAO?
class MyController {
public function index() {
$model = new PostModel();
// maybe this returns a PostRepository?
$posts = $model->findAllByDateRange('within 30 days');
while($posts->getNext()) {
echo $posts->Post->Author;
}
}
}
Both those examples didn't even do what I was describing above. I'm clearly lost. Any input?
Entity
Entity means an object that is a single item that the business logic works with, more specifically those which have an identity of some sort.
Thus, many people refer to ORM-mapped objects as entities.
Some refer to as "entity" to a class an instance of which represents a single row in a database.
Some other people prefer to call only those of these classes as "entity" which also contain business rules, validation, and general behaviour, and they call the others as "data transfer objects".
Model
A Model is something that is not directly related to the UI (=View) and control flow (=Controller) of an application, but rather about the way how data access and the main data abstraction of the application works.
Basically, anything can be a model that fits the above.
MVC
You can use entities as your models in MVC. They mean two different things, but the same classes can be called both.
Examples
A Customer class is very much an entity (usually), and you also use it as part of data access in your app. It is both an entity and a model in this case.
A Repository class may be part of the Model, but it is clearly not an entity.
If there is a class that you use in the middle of your business logic layer but don't expose to the rest of the application, it may be an entity, but it is clearly not a Model from the perspective of the MVC app.
Your example
As for your code examples, I would prefer the first one.
A Model is a class that is used as a means of data abstaction of an application, not a class which has a name suffixed with "Model". Many people consider the latter bloatware.
You can pretty much consider your Repository class as part of your model, even if its name isn't suffixed with "Model".
I would add to that the fact that it is also easier to work with the first one, and for other people who later may have to understand your code, it is easier to understand.
All answers are a heavy mashup of different things and simply wrong.
A model in DDD is much like a model in the real world:
A simplification and abstraction of something.
No less and no more.
It has nothing to do with data nor objects or anything else.
It's simply the concept of a domain part. And in also every complex domain
there is always more than one model, e.g. Trading, Invoicing, Logistics.
An entity is not a "model with identity" but simply an object with identity.
A repository is not just a 1st level cache but a part of the domain too.
It is giving an illusion of in-memory objects and responsible for fetching
Aggregates (not entities!) from anywhere and saving them
i.e. maintaining the life cycle of objects.
The "model" in your application is the bit which holds your data. The "entity" in domain-driven design is, if I remember correctly, a model with an identity. That is to say, an entity is a model which usually corresponds directly to a "physical" element in a database or file. I believe DDD defines two types of models, one being the entity, the other being the value, which is just a model without and identity.
The Repository pattern is just a type of indexed collection of models/entities. So for instance if your code wants order #13, it will first ask the repository for it, and if it can't get it from there, it will go and fetch it from wherever. It's basically a level 1 cache if you will. There is no difference in how it acts with a model, and how it acts with an entity, but since the idea of a repository is to be able to fetch models using their IDs, in terms of DDD, only entities would be allowed into the repository.
A simple solution using service and collection:
<?php
class MyController {
public function index() {
$postService = ServiceContainer::get('Post');
$postCollection = $postService->findAllByDateRange('within 30 days');
while($postCollection->getNext()) {
echo $postCollection->current()->getAuthor();
}
}
}
EDIT:
The model(class) is the simple representation of the entity scheme. The model(object) is a single entity. The service operates on models and provides concrete data to the controllers. No controller has any model. The models stand alone.
On the other "side", mappers map the models into persistance layers (e.g: databases, 3rd party backends, etc).
while this is specifically about Ruby on Rails, the same principles and information still apply since the discussion is around MVC and DDD.
http://blog.scottbellware.com/2010/06/no-domain-driven-design-in-rails.html
What are some of the ways you have implemented models in the Zend Framework?
I have seen the basic class User extends Zend_Db_Table_Abstract and then putting calls to that in your controllers:
$foo = new User;
$foo->fetchAll()
but what about more sophisticated uses? The Quickstart section of the documentation offers such an example but I still feel like I'm not getting a "best use" example for models in Zend Framework. Any interesting implementations out there?
EDIT: I should clarify (in response to CMS's comment)... I know about doing more complicated selects. I was interested in overall approaches to the Model concept and concrete examples of how others have implemented them (basically, the stuff the manual leaves out and the stuff that basic how-to's gloss over)
I worked for Zend and did quite a bit of work on the Zend_Db_Table component.
Zend Framework doesn't give a lot of guidance on the concept of a "Model" with respect to the Domain Model pattern. There's no base class for a Model because the Model encapsulates some part of business logic specific to your application. I wrote a blog about this subject in more detail.
Persistence to a database should be an internal implementation detail of a Model. The Model typically uses one or more Table. It's a common but improper object-oriented design to consider a Model as an extension of a Table. In other words, we should say Model HAS-A Table -- not Model IS-A Table.
This is an example of IS-A:
class MyModel extends Zend_Db_Table_Abstract
{
}
This is an example of HAS-A:
class MyModel // extends nothing
{
protected $some_table;
}
In a real domain model, you would use $some_table in the methods of MyModel.
You can also read Martin Fowler's take on the Domain Model design pattern, and his description of the Anemic Domain Model antipattern, which is how many developers unfortunately approach OO programming.
I personally subclass both Zend_Db_Table_Abstract and Zend_Db_Table_Row_Abstract. The main difference between my code and yours is that explicitly treat the subclass of Zend_Db_Table_Abstract as a "table" and Zend_Db_Table_Row_Abstract as "row". Very rarely do I see direct calls to select objects, SQL, or the built in ZF database methods in my controllers. I try to hide the logic of requesting specific records to calls for behind Zend_Db_Table_Abstract like so:
class Users extends Zend_Db_Table_Abstract {
protected $_name = 'users';
protected $_rowClass = 'User'; // <== THIS IS REALLY HELPFUL
public function getById($id) {
// RETURNS ONE INSTANCE OF 'User'
}
public function getActiveUsers() {
// RETURNS MULTIPLE 'User' OBJECTS
}
}
class User extends Zend_Db_Table_Row_Abstract {
public function setPassword() {
// SET THE PASSWORD FOR A SINGLE ROW
}
}
/* CONTROLLER */
public function setPasswordAction() {
/* GET YOUR PARAMS */
$users = new Users();
$user = $users->getById($id);
$user->setPassword($password);
$user->save();
}
There are numerous ways to approach this. Don't think this is the only one, but I try to follow the intent of the ZF's design. (Here are more of my thoughts and links on the subject.) This approach does get a little class heavy, but I feel it keeps the controllers focused on handling input and coordinating with the view; leaving the model to do the application specific work.
Don't ever use Zend_Db_Table as your model. It just gets you into trouble. Either you write your own model classes which use Zend_Db_Table to talk to your database or you can read my blog post here for a hack that allows you to somewhat combine the "Model" class and Zend_Db_Table.
The main thing to not is that when you use Zend_Db_Table directly in your controllers you end up doing the same things in multiple places. If you have to make a change to some of that logic, you have to make a change in multiple places. Not good. My first professional project was done like this because I was the one in the company who had to learn how to use ZF and it's a total mess now.
I also tend to write helper functions into my classes for sophisticated fetches. Somthing like $table->doNameFetchAll() or $table->doOrderFetchAll().
I've been doing some research on Models for ZF and came across an interesting series of articles by Matthew Weier O'Phinney which are well worth checking out:
Using Zend_Form in your Models
Applying ACLs to Models
Model Infrastructure
It's not "production code" and a lot is left to the imagination, but it's a good read and has helped me quite a bit.
A model has nothing to do with the database. What if I am fetching data from an RSS feed or a SOAP service or reading files from the FS?
I put all these kinds of things in models. In that case, my model class might not extend anything. I'm about to write a model that uses methods of other models.
Skip ZF for the models part, there are much better solutions. The "M" in ZF's "MVC" is pretty much absent. Reading their docs they don't really mention models at all -- which is a good thing, it means you can use just about anything you want without writing lots of adapter code.
Take a look at Doctrine for models instead. It is quickly becoming the de-facto ORM for PHP.
You can do more complicated queries, check the Advanced usage section in the Zend_Db_Table manual page.
$select = $table->select();
$select->from($table,
array('COUNT(reported_by) as `count`', 'reported_by'))
->where('bug_status = ?', 'NEW')
->group('reported_by');
you can extend the Zend_Db_Table_Abstract class and add some useful methods to it. for example you can add a changePassword() method to your user class and manipulate it's data. or you can change the default __toString() method of your class, so you'll have a customized __toString() method that, let's say returns the whole contact information of the user (name, address, phone number) in a well formatted string. in your constructor you could populate your data into properties of your object. then use them like:
public function __toString() {
$data = $this->_name . ', ' . $this->_adderss . ', call: ' . $this->_phone;
return $data;
}
your model extends the Zend_Db_Table_Abstract just to ease the process of accessing its data, but the functionality you could have on that data is all up on your creativity and need.
I recommend you the book "php|architect's guide to programming with zend framework" by Cal Evans. the book is very informative and easy to read. chapters 4 and 6 are going to be useful for this matter.
A database entity is not the only kind of model component. As such, it doesn't really make sense to speak of models (in plural) - Your application has one model, which contains a multitude of components. Some of these components could be table gateways (And thus extend from Zend_Db), while others would not.
I recommend that you get hold of the book Domain Driven Design by Eric Evans, which does an excellent job of explaining how to construct an object model.
I use Propel 1.3 instead of Zend_Db_Table.
It's tricky to setup, but awesome.
It can examine your database and auto-generate all your models.
It actually generates 2 levels and 2 types of model.
Examples for 'user' table:
Level 1: BaseModel & BasePeer: these get overwritten every time you regenerate your ORM. i.e. BaseUser.php & BaseUserPeer.php
Level 2: StubModel & StubPeer: these don't get overwritten. They're the ones you customize. i.e. User.php & UserPeer.php
Type 1: Model - for basic CRUD operations, not queries i.e. User.php
Type 2: Peer -- for queries. These are static objects. i.e. UserPeer.php
So to create a user:
$derek = new User();
$derek->setFirstName('Derek');
$derek->save();
To find all dereks:
$c = new Criteria();
$c->add(UserPeer::FIRST_NAME, 'Derek');
$dereks = UserPeer::doSelect($c);
http://zfsite.andreinikolov.com/2008/08/zend_db_table-time-overhead-about-25-percents/
Bit of a catch 22, Zend_Table is nice in principle, but generates some performance overheads (without caching)...