i use a simple PHP framework (like Codeigniter) without ORM.
I have a database with product data (prices, sells, page in catalog...).
And i want to calculate the conversion per page and the conversion per product.
The calculations with SQL are not a problem, but i don't really know where to put them in.
Should I create a "Page" and a "Products" model with methods like
"Page::getConversions($page_id)" or a "ConversionPerPage" and a "ConversionPerProduct" model, or sth. completely other.
I think that the best model classes are to have two classes for each table - one for object and plural for static classes.
For example: if you have Page table then you should have Page and Pages classes.
First one will allow you to have one object from table and you can do the regular methods on it like:
$page = new Page($page_id);
$conversions = $page->getConversions();
$page_number = $page->getNumberInBook(); etc
On the other hand in Pages class you can put the methods that will (usually) return the array of Page and those methods will usually be static:
$pages = Pages::getPagesByCatalog($catalog_id);
This way you will have real OOP and code complete with full model MVC implementation.
I hope that this model hierarchy will help you. We are using it in our office and it showed to be really good.
All the best!
Basically, you create models based on the database schema. So, first option is preferred. Moreover, it should be instance method instead of class method (the object is then identified from the $page_id).
Presumably you are going to have Page and Product models anyway so I would add the getConversions() function to those.
Related
I have read a book about MVC last week and a general one about design patterns, but I'm still confused as to where SQL queries belong in my code: the model or in the controller?
Let's take a very simple example, where you have a /popular page that will print the 5 most popular stories on a website.
In your model, you would have a class for prepared staments, and a class for assisting in the creation of the SELECT query. In your view, you'd have the HTML elements that display the /popular page.
Where does the query "SELECT most popular stories LIMIT 5" belong to? Is that something a controller class should ask, taking query methods from the model and passing to the view, or should the query be declared instead on a model class related to the /popular page?
Is the distinction even relevant? Would placing that query on the controller or the model be both considered professional ways to build a MVC?
Thank you. It seems most people get stuck understanding what to place on controllers
Edit: thanks for help everyone. Unfortunately as a new account I can't upvote any helpful posts yet
Usually (based on my experiences with MVC frameworks) the model layer takes care of database-related stuff in MVC.
Consider following approach:
Create abstract class which covers all the DB operations (selects, updates, etc). Each table would be a PHP class extending such class. You can then define DB table name in for instance private field, constructor or depending on model name.
Each controller (or the single controller) would load desired model, and use its methods to fetch data as associative arrays or objects, delete the data, change it.
After all DB operations have been done, controller returns view and passes data as its parameters.
Note that models are great place to put all the validation rules, and some helper methods due to the fact that they can be easily tested in PHPUnit.
Okay, so here's the deal. I'm working with a custom CMS, and I'd like for the code to be as optimized as possible. I've been reading/watching tuts/etc. like crazy about the repository pattern in general as well as specifically using it with Laravel's Eloquent. There are probably some really dumb questions/thoughts in here, but bear with me. :-) Sometimes there's no easy way to ask about terminology/best practices without looking silly.
As with many things, there are million ways I could "make it work"; my dilemma is essentially a matter of "best practice."
General Scenario/Question
Let's assume I am trying to get a Page for my CMS from the database. From what I can understand the typical way to set up the repository pattern with Eloquent is to have the following files:
Page.php -- the Eloquent Model
PageRepositoryInterface.php -- the "contract" for what should be in Page repo's
EloquentPageRepository.php -- the Page repository that can grab data via Eloquent
Easy enough. So I might use it this way. Assuming I have a getPageById method in EloquentPageRepository.php, I could just do something like this from my controller:
$page = $this->repo->getPageById();
Now my question arises: what type of data should getPageById() return? Some people recommend setting it up to return an Eloquent collection. Others say just a plain array or generic object.
Ideally I feel like my scenario would best lend itself to having EloquentPageRepository grab the data from Eloquent and actually return an instance of a custom Page class that I have. For example, something along the lines of this:
<?php namespace Acme\Repositories\EloquentPageRepository;
use Acme\...\PageObject as PageObject; // Better name than PageObject?
//...
class EloquentPageRepository implements PageRepositoryInterface {
// Omitting constructor, etc.
public function getPageById($id)
{
// Grab the row via Eloquent (obviously not stored in Page:: at
// this point. I'm just using it here for clarity and time's sake.
$page = Page::find($id);
// Now we have an Eloquent collection stored in $page, but I'd
// like to return the data inside an instance of my custom class.
$pageObj = new PageObject($page->title, $page->body);
return $pageObj;
}
}
To me, this seems good because it gives a consistent delivery format from repo to repo. It also allows me to perform some constructor logic on my pageObject. Finally, it allows me to have some custom methods on the PageObject (that are repository-agnostic).
It's similar to a collection, but I don't think it's exactly that. It's basically just an instance of a class that I'm immediately populating with my database info.
My questions, listed:
Is it considered bad practice to use a repo to stuff eloquent data into a specific object and return it?
I don't want to call my class "PageObject," because that's just lame. I'd way rather call it something like "PageCollection," except for the fact that it's not actually a collection. Is there actually a name for the way that I'm using this class? It's not a collection, it's a ...? I have no idea about this, I'm just searching for any input you have.
It whole depends on what you expect from the repository pattern. Are you using the repository pattern because in the future you're going to swith of data layer and needs a new repository. If you're using Eloquent as long as your cms live then you can return an eloquent object. If you want it very flexible then make a new page object(PageComposer as mentioned in the comments). This is one of the strengts of the repository pattern so I suggest you make a PageComposer class which you instantiate and return by the repository.
Normally you can call it Page because its a page and it ships some information of a page. But that name you've already give to the Eloquent model. You can consider changing the eloquent models name and call your return object Page.
I'm just wondering, I'm not an expert on MVC but have been shifting our code towards a better MVC structure on the Zend Framework over the past few years. I basically have different models handling different sets of logic for different entities in the database. For example, a Product model, and a Customer model, etc.
Is it OK for my Product model to instatiate a Customer model, so that it can use some of the Customer functions?
OR is this the job of a controller, to call the relevant functions of Customer, and pass the results to the Product?
Let's say the Product needs to know if a Customer has certain records within it, so that the Product can decide on the correct data to return to the controller.
I am just curious on the 'best way'. I would want to instatiate a "model within a model" since the logic is needed from different controllers which call the same Product model function.
Many thanks!
IMHO it is OK to instantiate a "model within a model" as shown in case of CakePHP here:
CakePHP: calling other Model functions
You may also check these links One, Two and Three
You use bellow code
$product = new Application_Model_Product(); // create model class object, any model name which you want to user
$product->getProductList(); // just any function from model
Ok, I couldn't insert the overview image, but I'm required to create a PHP app for my studies, it must allow student to register, and the administrator to edit course and student info.
We are not required to code it in an OOP style, but since its the best programming practice to code in OOP, why not learn OOP from the beginning.
I'm a beginner but I know the basics about OOP, classes, inheritance, setters and getters and all that cool lingo, but I'm struggling to decide which parts of this app should be objects, should I make course and student classes or add, edit and delete classes? Any advice on how to approach and visualize such a problem would be appreciated.
Very roughly: This is how I would do it:
Store your data in SQL or XML. You will need two SQL tables, one for Students and one for Courses. You can use one XML file containing all the data, or you can use two files (which I recommend).
Create a class called, for example, dataItem with a property like '$arr_fields' corresponding to a single data record (a single row in a SQL table, or an XML record).
The dataItem class should have the following methods (all public):
loadFromSQL() (or loadFromXML())
saveToSQL() (or saveToXML())
add(), edit() and delete()
a view() method using HTML
These methods are obviously used to read and write data between the SQL/XML data and $arr_fields of the class, and to display the data in $arr_fields. The keys of $arr_fields are the SQL column names (or XML tag or attribute names) for the specific SQL table.
Try not to call loadFromSQL() or saveToSQL() in your constructor or in any of the other methods which are used to modify only the class data. Keep these actions separate. EDIT: This is a personal preference which helps me to keep track of the state of my objects.
Create Student and Course classes that extends the dataItem class.
You can override methods, for instance the view() method, inside your extended classes if you need to.
Then you can call the methods in Students and Courses from an Admin object (like rcdmk suggested) or maybe from StudentFolder and CourseFolder classes whose view() method contains buttons for the actions that need to be performed. (Let StudentFolder and CourseFolder extend a Folder class that you create).
UPDATE:
For example: If your primary key in a SQL table is id, then dataItem's loadFromSQL($id, $tablename) should set $arr_fields so that its keys are the column names and it's values are the values from the row whose primary value is equal to $id.
In Students, you can then override loadFromSQL() as follows:
class Students extends dataItem {
// other attributes
public function loadFromSQL($id) {
parent::loadFromSQL($id, "Students");
}
}
EDIT: On reconsideration, it might be better to set $arr_fields["id"] = $id and also set $tablename with the constructor for dataItem - then you never have to override loadFromSQL() or specify parameters for it. loadFromSQL() should then load the record if it exists. saveToSQL() should save $arr_fields in SQL if $arr_fields["id"] is set and create a new record if it is not set. Anyway, you must find a consistent way of interacting with the data which works for you, these are just possibilities.
However, if you are not experienced with OOP and SQL or XML, you might be opening a can of worms for yourself and it might be better to just do your assignment using functions only and php arrays for your data. Unless you have some time to learn...
From a simple perspective:
Abstract the main objects as classes and use methods for actions of this objects:
Student (object) are deleted (action) by the Admin (object), so
Admin class will have a deleteStudent method, because Admin deletes Students.
Another aprouch is to concentrate all Student related actions in the Student class:
Student class will have a public delete method that Admin can use.
Anyone that think this in better ways of explanation can edit this wiki.
Think about which aspects of your system are actually objects, you know, something you can do something with. The methods are what you do to the objects. So, you're on the right track with course and student classes, and add, edit, and delete would be methods of those classes.
But don't get too bogged down with it. If it's not your core assignment objective, you could quickly get in over your head by trying to do everything exactly the right way. If you can formulate a clear way to get to where you need to go, then go for it, if it seems confusing, back off it a little and learn some more.
You say that you know the basis of OOP, however you ask whether you should create Course, Student classes OR Add, Delete, Edit classes. Well maybe there are other practices, but I guess the most popular one and the only I am aware of is to use nouns as classes and verbs as their methods. Hence, intuitively there is something wrong with class "Add" or "Edit". What I would have done if I were were, is to think of all "entities" that might be considered an object - like Student, Course, Lecturer, Class (Room) and depending on how advanced your model should be you can add more like Building etc. Then try to implement basic things like creating new student, registering for a course, associating teacher with a course etc. Once you have it in place and IT IS WORKING you might want to add advanced things, like inheritance. For example you might want to say, that both Teacher and Student are a Person so you might want to create such abstract class and use inheritance.
I have an index action in my users_controller that get a list of users. For each user i want to calculate the number of projects they have associated (one user => many projects). I was thinking of using a method like getProjectTotal and calling it for each user. Would I put this method in the users_controller and call it like
$this->getProjectTotal($id)
in the view?
Thanks,
Jonesy
Sure. It sounds like this is just a helper method based on the call. I do that all the time. I'll typically set the method visibility to private or at least protected to keep it from being called accidentally in a rendering scenario.
I'm still relatively new to CakePHP, but I've been using the built-in counterCache in Cake 1.2 to track the number of hasMany records for a parent Model in one of my apps. Create a field in your parent Model to store the hasMany count, and enable counterCache in the $belongsTo property for the child Model, and you're good to go. It automatically updates the counterCache count field in the parent model whenever the # of "hasMany" records increases/decreases. I like this method of tracking as it keeps the controller a little cleaner if all you need is the count without any other conditions.
Docs: http://book.cakephp.org/view/816/counterCache-Cache-your-count
Also, I'm still new to MVC, but I think if you're going to gather the count via a private/protected controller method, you'd want to call it in the controller and then send the data to the view, not perform the actual method from the view, in this scenario.
Also - yes you can make a controller method for work that isn't going to render a view - BUT - in your case you should use counterCache / a Model function since you are either fetching / counting / manipulating actual data related to the Project model and it's relationship with the User model and current logged in User specifically.
When building out my controllers I tend to stick to methods that render a view or return data for an element called from requestAction. If the method is computational or setting up variables but doesn't require a template or isn't called from an element I move it to a component / helper / model / behavior. Combined with a docblock with #requestAction in the flags for introspection and I can get a list of regular actions, and data returning actions without worrying that a controller is full of other methods.