A quick question this time about the M in Mvc.(using codeigniter, but the question is general)
Suppose I have several models that are responsible for accessing several tables in my database, Is it frowned upon making one flexible model that can deal with everything?
specifically in php-codeigniter, for example:
$this->MY_model->getByID($table,$ID)
So this example code can be used to get by ID of any table I want thus saving me time and I'm able to reuse most of my model code.
This of course can be expanded further
$this->MY_model->update($table,$info) as an example.
So my question is, If all of the above is okay, Where is the 'limit' to such operations? Naturally we wouldn't want something really specific in this type of model, like this method:
$this->MY_model->getAllActiveUsers()
My basic approach is this:
Any method that can be used in more than one table should be used in the extended model.
Any method that should be used in only one table, should be in it's own model.
Just to be clear i'm not looking for an opinion, But rather wondering what's the standard approach to these issues.(for example, imagine an application with 50 models, should CRUD be written for all 50 of them?)
Thanks in advance!
What you are mulling about is pretty standard operation for most Codeigniter developers. If you are going to be doing a lot of CRUD in the DB, then it makes sense to add a set of generic CRUD methods to your base MY_model and then extend it. If you do a search on Google...you'll likely get results for 100s of people who have setup their own base models including CRUD and other common methods used by most Codeigniter projects...here are just a couple:
https://github.com/jamierumbelow/codeigniter-base-model
https://github.com/jenssegers/CodeIgniter-My-Model
should CRUD be written for all 50 of them?
No. You would extend your base model and use it's generic CRUD methods where they make sense and just override certain properties (table name). Then, if you needed something more specific you could create additional, more granular methods in your new model as you suggested.
Related
In most of the frameworks you have model classes that represents row in the database.
For example php code:
class User extends Model {}
I'm giving Laravel eloquent example but this is true for most php frameworks.
Then you add the relationships in the class:
public function pictures()
{
return $this->hasMany('App\Picture');
}
Then you add some methods like this:
public function deleteComments()
{
// delete comments code here
}
My first question is: Is this good design architecture because after years when the project becomes large you will have many relationships (pictures, comments, posts, subscriptions, etc connected to the user).
The class could become 10k lines of code or so.
In that case, the class will become very large and hard to maintain.
Also the Single Responsible Principle maybe is violated because you have too many methods in one class.
Also if I want to use the class it in another app I cannot, simply because I'll have to pull also the pictures, comments and etc in the second application(website).
If I make other classes like "UserPictures", "UserPictureDeleter" the code will get more complicated.
So is this good practice and if not do you have any suggestions on how to make the code not bloated with so many methods but easy to use.
Do you agree that all these methods belong to the User class?
Laravel and some another framework provide Active Record conception in their base classes of model. The main idea of Active Record is a representation of table row as an object that includes data of a row and methods of work with databases.
Using of Active Record pattern is fully justified in small simple applications because this pattern gives an ability to fast develop your application. But if your application has a lot of code and difficult business logic, Active Record will make many problems in the architecture of your application. Active Record can make the following problems:
violation of the Single Responsibility Principle that makes bloated code. Active Record always violates this principle, because it always has two responsibility: it implements business logic and methods of database work
violation of low coupling principle (GRASP) that makes code reuse more difficult
сreation of qualified abstraction is difficult if you use Active Record pattern
The solution to those problems is using of OOP abstractions instead of using of table rows abstractions. For example, you can use Domain Model and Domain-driven design. This approach is better than Active Record pattern for large applications.
Unfortunately, those concepts are too large-volume for explanation in this post, but you can read "Domain Driven Design" by Eric Evans. It is a good book about application design. Also, you can find many articles about those concepts in google. For example Building a Domain Model, Implementing Domain-Driven Design in PHP (Laravel)
You could improve your model with Interfaces.
If you need one class to inherit a certain behavior common to another, having designed the interface, you need the new class to only implement the interface.
Interfase based programming
coding to interfase in PHP
The class could become 10k lines of code or so
Each relationship function is 2-4 lines of code so unless you have 2500-5000 relationships, this class is not going to be 10k lines of code. If you do, you already have bad database design.
Also the Single Responsible Principle maybe is violated because you
have too many methods in one class.
Nowhere does the SRP state that you cant have too many methods in one class. It states that a class should have only a single responsibility/reason to exist.
Also if I want to use the class it in another app I cannot, simply
because I'll have to pull also the pictures, comments and etc in the
second application(website).
This class is a Model class. Its responsibility is to represent one database table. If you have the same table structure in other apps, then yes, you should pull in this class and you would need to pull in pictures, comments, etc. as well since you have the same table structure. If not, you shouldn't pull it in. I don't see any problem here.
Consider the following talk from Adam Wathan. He addresses an issue in naming, which leads to bloating of classes. If you consider his methodology of naming methods and shifting the responsibilities, you'll end up with smaller classes and easier to read code.
Besides don't let yourself get indoctrinated by some rules and 'laws' that exist in programming. If you need a class that is 10k lines, but it's readable then go for it.
I am currently looking to redesign a feature on my web application.
The web application utilizes Yii (version 1) for the back-end.
In this instance I have a model and controller. The model is used to store all the userTracking data and is appropriately a userTracking model however the actual logic for the model is in a controller called UserController. I have a function called actionTrackUser($id) which is used to implement various tracking logic for a particular user and create a model for that user.
I however now need to extrapolate this functionality from the UserController to a seperate trackingController which will implement tracking for various models.
I need to be able to utilize this functionality however in the new controller and old controller. I was wondering as to the best approach for this in Yii 1 that implements MVC correctly. I thought about making a trackingModel and having the userTracking model extend that but then I would have a lot of business logic in a model in order to use it in two places.
I am fairly new to MVC and Yii so I was wondering as to the best approach to take here?
I have purposely left code out of this question as it is more a theoretical question regarding the implementation of such functionality in Yii.
Any help is appreciated.
Thanks!
I am not sure that there may be a 'best' approach. However, you need to choose an approach that works best for you. Be guided by what will work for your situation, and what will make manageable code for you and others in the future.
There is nothing wrong with your current userTracking model and controller. You state that the "actual logic for the model is in a controller." You may want to relook at that to move appropriate data management, constraints and validation rules to the model at least.
You can move functions to a separate trackingController and still use the userTracking model. There is no rules that says you have to have a matching model and controller set, and it is quite possible for a controller to manage more that one model at a time.
I generally start with activeRecord models, which map against data stores (database tables in most cases). I use corresponding Form models to reflect forms that are markedly different from activeRecord models, and I use domain models to reflect complex business objects that are feature rich, and reflect lots of runtime attributes (like calculated fields) and state data (like publish state, which are calculated from other fields - for example a user could have validation status, paid status, active status, account level and so on that all work together to indicate what activity is possible for the user).
I'm trying to understand the MVC pattern in Phalcon.
In my current application I only need ONE template file for each table. The template contains the datagrid, the SQL statement for the SELECT, the form, add/edit/delete-buttons, a search box and all things necessary to interact with the database, like connection information (of course using includes as much as possible to prevent duplicate code). (I wrote my own complex framework, which converts xml-templates into a complete HTML-page, including all generated Javascript-code and CSS, without any PHP needed for the business logic. Instead of having specific PHP classes for each table in the database, I only use standard operation-scripts and database-classes that can do everything). I'm trying to comply more with web standards though, so I'm investigating alternatives.
I tried the INVO example of Phalcon and noticed that the Companies-page needs a Companies model, a CompaniesController, a CompaniesForm and 4 different views. To me, compared to my single file template now, having so many different files is too confusing.
I agree that separating the presentation from the business logic makes sense, but I can't really understand why the model and controller need to be in separate classes. This only seems to make things more complicated. And it seems many people already are having trouble deciding what should be in the model and what should be in the controller anyway. For example validation sometimes is put in the model if it requires business logic, but otherwise in the controller, which seems quite complex.
I work in a small team only, so 'separation of concerns' (apart from the presentation and business logic) is not really the most important thing for us.
If I decide not to use separate model and controller classes,
what problems could I expect?
Phalcon's Phalcon\Mvc\Model class, which your models are supposed to extend, is designed to provide an object-oriented way of interacting with the database. For example, if your table is Shopping_Cart then you'd name your class ShoppingCart. If your table has a column "id" then you'd define a property in your class public $id;.
Phalcon also gives you methods like initialize() and beforeValidationOnCreate(). I will admit these methods can be very confusing regarding how they work and when they're ran and why you'd ever want to call it in the first place.
The initialize() is quite self-explanatory and is called whenever your class is initiated. Here you can do things like setSource if your table is named differently than your class or call methods like belongsTo and hasMany to define its relationship with other tables.
Relationship are useful since it makes it easy to do something like search for a product in a user's cart, then using the id, you'd get a reference to the Accounts table and finally grab the username of the seller of the item in the buyer's cart.
I mean, sure, you could do separate queries for this kind of stuff, but if you define the table relationships in the very beginning, why not?
In terms of what's the point of defining a dedicated model for each table in the database, you can define your own custom methods for managing the model. For example you might want to define a public function updateItemsInCart($productId,$quantity) method in your ShoppingCart class. Then the idea is whenever you need to interact with the ShoppingCart, you simply call this method and let the Model worry about the business logic. This is instead of writing some complex update query which would also work.
Yes, you can put this kind of stuff in your controller. But there's also a DRY (Don't Repeat Yourself) principle. The purpose of MVC is separation of concerns. So why follow MVC in the first place if you don't want a dedicated Models section? Well, perhaps you don't need one. Not every application requires a model. For example this code doesn't use any: https://github.com/phalcon/blog
Personally, after using Phalcon's Model structure for a while, I've started disliking their 1-tier approach to Models. I prefer multi-tier models more in the direction of entities, services, and repositories. You can find such code over here:
https://github.com/phalcon/mvc/tree/master/multiple-service-layer-model/apps/models
But such can become overkill very quickly and hard to manage due to using too much abstraction. A solution somewhere between the two is usually feasible.
But honestly, there's nothing wrong with using Phalcon's built-in database adapter for your queries. If you come across a query very difficult to write, nobody said that every one of your models needs to extend Phalcon\Mvc\Model. It's still perfectly sound logic to write something like:
$pdo = \Phalcon\DI::getDefault()->getDb()->prepare($sql);
foreach($params as $key => &$val)
{
$pdo->bindParam($key,$val);
}
$pdo->setFetchMode(PDO::FETCH_OBJ);
$pdo->execute();
$results=$pdo->fetchAll();
The models are very flexible, there's no "best" way to arrange them. The "whatever works" approach is fine. As well as the "I want my models to have a method for each operation I could possibly ever want".
I will admit that the invo and vokuro half-functional examples (built for demo purposes only) aren't so great for picking up good model designing habits. I'd advise finding a piece of software which is actually used in a serious manner, like the code for the forums: https://github.com/phalcon/forum/tree/master/app/models
Phalcon is still rather new of a framework to find good role models out there.
As you mention, regarding having all the models in one file, this is perfectly fine. Do note, as mentioned before, using setSource within initialize, you can name your classes differently than the table they're working on. You can also take advantage of namespaces and have the classes match the table names. You can take this a step further and create a single class for creating all your tables dynamically using setSource. That's assuming you want to use Phalcon's database adapter. There's nothing wrong with writing your own code on top of PDO or using another framework's database adapter out there.
As you say, separation of concerns isn't so important to you on a small team, so you can get away without a models directory. If it's any help, you could use something like what I wrote for your database adapter: http://pastie.org/10631358
then you'd toss that in your app/library directory. Load the component in your config like so:
$di->set('easySQL', function(){
return new EasySQL();
});
Then in your Basemodel you'd put:
public function easyQuery($sql,$params=array())
{
return $this->di->getEasySQL()->prepare($sql,$params)->execute()->fetchAll();
}
Finally, from a model, you can do something as simple as:
$this->easyQuery($sqlString,array(':id'=>$id));
Or define the function globally so your controllers can also use it, etc.
There's other ways to do it. Hopefully my "EasySQL" component brings you closer to your goal. Depending on your needs, maybe my "EasySQL" component is just the long way of writing:
$query = new \Phalcon\Mvc\Model\Query($sql, $di);
$matches=$query->execute($params);
If not, perhaps you're looking for something more in the direction of
$matches=MyModel::query()->where(...)->orderBy(...)->limit(...)->execute();
Which is perfectly fine.
Model, View and Controller were designed to separate each process.
Not just Phalcon uses this kind of approach, almost PHP Frameworks today uses that approach.
The Model should be the place where you're saving or updating things, it should not rely on other components but the database table itself (ONLY!), and you're just passing some boolean(if CRUD is done) or a database record query.
You could do that using your Controller, however if you'll be creating multiple controllers and you're doing the same process, it is much better to use 1 function from your model to call and to pass-in your data.
Also, Controllers supposed to be the script in the middle, it should be the one to dispatch every request, when saving records, when you need to use Model, if you need things to queue, you need to call some events, and lastly to respond using json response or showing your template adapter (volt).
We've shorten the word M-V-C, but in reality, we're processing these:
HTTP Request -> Services Loaded (including error handlers) -> The Router -> (Route Parser) -> (Dispatch to specified Controller) -> The Controller -> (Respond using JSON or Template Adapter | Call a Model | Call ACL | Call Event | Queue | API Request | etc....) -> end.
I'm currently developing a simple web application with Symfony 2 that process orders with products and lines of orders. Actually I have three Doctrine entities (Product, Line and Order). I will work with the data of these models and I need filter by date, add, delete, list, and make some administrative things with all the data.
As far I know this will be Service territory and is best practice to keep the controller away from doing this.
My question really is if I need to create ONE class with the methods that I need for all operations and then call them from the Controller, or create one Service class for each Doctrine Model (OrderManager, LineManager...) or orient more to task specific (RecountTotal, FilterDate...) But with the last method I think that each Service will have only one method inside.
Which is the best practice for this?
You are totally correct in stating this is NOT a job for controller.
It's totally fine to use only one manager to contain all your data access methods.
class BaseManager { // Name it as you like
...
}
If you find yourself having very similar methods for different entities, you may want to split into different managers (OrderManager, LineManager, ProductManager) and have them extend a common BaseManager to reduce code duplication.
Additional classes for filters and counting should not be necessary unless you have some advanced requirements.
My understanding of the MVC is as follows (incase it's horribly wrong, I am afterall new to it)
Models are the things that interface with the database
Views are the design/layout of the page
Controllers are where everything starts and are essentially the page logic
I'm using CodeIgniter but I would hazard a guess it's not just limited to that or possibly even just to PHP frameworks.
Where do I put global classes?
I may have a model for Products and I then run a query that collects 20 products from the database. Do I now make 20 models or should I have a separate class for it, if the latter, where do I put this class (other controllers will need to use it too)
Model is the wrong word to use when discussing what to do with products: each product is a value object (VO) (or data transfer objet/DTO, whatever fits in your mouth better). Value objects generally have the same fields that a table contains. In your case ProductVO should have the fields that are in Products table.
Model is a Data Access Object (DAO) that has methods like
findByPk --> returns a single value object
findAll --> returns a collection of value objects (0-n)
etc.
In your case you would have a ProductDAO that has something like the above methods. This ProductDAO would then return ProductVO's and collections of them.
Data Access Objects can also return Business Objects (BO) which may contain multiple VO's and additional methods that are business case specific.
Addendum:
In your controller you call a ProductDAO to find the products you want.
The returned ProductVO(s) are then passed to the view (as request attributes in Java). The view then loops through/displays the data from the productVO's.
Model is part of your application where business logic happens. Model represents real life relations and dependencies between objects, like: Employee reports to a Manager, Manager supervises many Employees, Manager can assign Task to Employee, Task sends out notification when overdue. Model CAN and most often DO interface with database, but this is not a requirement.
View is basically everything that can be displayed or help in displaying. View contains templates, template objects, handles template composition and nesting, wraps with headers and footers, and produces output in one of well known formats (X/HTML, but also XML, RSS/Atom, CSV).
Controller is a translation layer that translates user actions to model operations. In other words, it tells model what to do and returns a response. Controller methods should be as small as possible and all business processing should be done in Model, and view logic processing should take place in View.
Now, back to your question. It really depends if you need separate class for each product. In most cases, one class will suffice and 20 instances of it should be created. As products represent business logic it should belong to Model part of your application.
In CakePHP there are 3 more "parts" :
Behaviors
Components
Helpers
Logic that are used by many models should be made as a behavior. I do not know if CodeIgniter have this logic or not, but if it doesnt, I would try to implement it as such. You can read about behaviors here.
(Components helps controller share logic and helpers help views in the same way).
The simplest way is to:
Have a model class per database table. In this case it would be an object that held all the Product details.
Put these classes into a package/namespace, e.g., com.company.model (Java / C#)
Put the DAO classes into a package like com.company.model.dao
Your view will consume data from the session/request/controller In this case I would have a List<Product>.
Oh, you're using PHP. Dunno how that changes things, but I imagine it has a Collections framework like any modern language.
#Alexander mentions CakePHPs Behaviors, Components and Helpers. These are excellent for abstracting out common functionality. I find the Behaviors particularly useful as of course the bulk of the business logic is carried in the models. I am currently working on a project where we have behaviors like:
Lockable
Publishable
Tagable
Rateable
Commentable
etc.
For code that transcends even the MVC framework i.e. code libraries that you use for various things that are not tied in to the particular framework you are using - in our case things like video encoding classes etc. CakePHP has the vendors folder.
Anything that effectively has nothing to do with CakePHP goes in there.
I suspect CodeIgniter doesn't have quite as flexible a structure, it's smaller and lighter than CakePHP, but a quick look at the CakePHP Manual to see how Behaviors, Components, Helpers, and the Vendors folder may be helpful.
It should be an easy matter to just include some common helper classes from your models keep nice and DRY