I am in somewhat a mix of MVC and objects and I was wondering if I am going about it the right way or if i could change something to improve my ways.
I have a webapp that uses an MVC model with objects. I chose to use objects as well so i can load them whereever i need them. One of the objects is a Tag object (which extends the basemodel for DB access). With my MVC framework I can load models from the basecontroller and also form the basemodel (both run their own instance). At first I was loading the Tag object from the controller. Today I decided to load it from the model. Both methods work fine, but what would be the better choice and why?
From the controller (tag_controller.php)
function getTags()
{
$this->_tagobject = $this->load->object('tagobject');
$tags = $this->tags-getSomeTags();
}
From the controller with model.
tagmodel.php
function __construct()
{
$this->_tagobject = $this->load->object('tagobject');
}
function getTags()
{
return $this->_tagobject->getTags();
}
tagcontroller.php
function __construct()
{
$this->_tagmodel = $this->load->model('tagmodel');
}
function getTags()
{
$this->_tagmodel->getTags();
}
Any suggestions for improvement are very welcome, because I can't seem to see a real benefit besides having a flexible object.
For most applications, your interaction with a tag object would follow CRUD operations (Create, Read, Update, Delete) so to me it leans more towards the model.
If I were to use tags in Zend Framework (MVC based PHP framework), I would create a tags class extending the Zend_Db_Table class and also a tag class representing the individual data object so I would be able to use it like:
$tags->insert(new Tag('keyword'));
$tags->find('keyword');
$tags->delete('keyword');
Placing this functionality in a controller wouldn't make sense. Then again, that's all my opinion.
Related
I have built a small PHP MVC framework and just want to clarify the best way to get data from one model into another. For example:
I have a Users_model that contains a method called get_users().
I also have Communications_model that needs to get specific or all user data and as such needs to access the get_users() method from the Users_model.
Is it best practice to:
a) Instantiate the Users_model in a controller and pass the data from the get_users() method into the Communications_model?
b) Instantiate the Users_model inside the Communications_model and run get_users() from there, so it can be accessed directly?
c) Another way?
Many thanks for any help.
It depends of your motive behind this.
If you want effect on result, then using well know library, like Doctrine etc. should be your choice.
If you want to learn design patterns, then you should get read about ActiveRecord or DataMapper + Repository patterns. Then implements both and check out.
If you want your code, this way - ORM should represent relations of data, then you should ask what it more important? If you menage communication (bus, train), then user can be there assigned and getting users from communication is OK. If user have communication (like car), then relation is reversed.
All depends, what is you motive behind this. Using library, like Doctrine, could you help you running you application. If you want learn design patterns, then check out both options to get some experience.
What you call "users model" is a repository. And what you call "communication model" looks like a service.
Your communication service should have the user repository passed in constructor as a dependency.
I honestly think, that a huge part of your confusion is that you try to call all of those things "models". Those classes are not part of the same layer. You migth find this answer to be useful.
All are possible ways but what I usually do is, whenever there is any function that I think would be reused a number of times by a number of objects, I declare it as static.
It would save the effort of playing with object declaration and would be easily accessible by ClassName::function();
Again, it's a design choice, usually objects are declared right there in the controller and used as per the need but just to save declaration of objects again and again I follow the approach of declaring function static.
The simple principle here is using the __construct() (constructor) to build the object with the relevant properties from the Database. The User Model will have a static function (therefore accessible through any scope) to create an array of instanced objects by simply passing the model data through a new self() which returns the instance.
The concept is you end up with an array of User_Model instances each being a build of the Database columns to properties. All that's left is to create the Database Model and the functions to retrieve the columns and data.
class Communications_Model {
private $_all_users;
public function getUsers() {
$this->_all_users = Users_Model::loadAllUsers();
}
}
class Users_Model {
private $_example_property;
public function __construct($user_id) {
$data = SomeDatabaseModel::getConnection()->loadUserFromDatabase((int)$user_id);
$this->_example_property = $data['example_column'];
}
public static function loadAllUsers() {
$users = array();
foreach(SomeDataModel::getConnection()->loadAllUsers() as $data) {
$users[] = new self($data['user_id']);
}
return $users;
}
}
Of course, now, you have a $_all_users; property that has an array of instanced User Models containing the data.
Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
I have an application which defines certain actions on common object types.
For example, you can have forum post and images. For each forum post and image you can do the following actions: recommend, comment, rate.
I have currently defined a static class
class CoreObjectUtil
{
protected static $_objObjKey = null;
protected static $_objTypeKey = null;
public static function getComments (...) {...}
public static function getCommentsArray (...) {...}
public static function getRatings (...) {...}
public static function getRatingsArray (...) {...}
}
which is then subclassed like this
class ForumPostUtil extends CoreObjectUtil
{
protected static $_objObjKey = 'forumpost';
protected static $_objTypeKey = 'FP';
}
to provide the relevant functionality for forum posts. The 2 parameters suffice to let the generic code in CoreObjectUtil know what to do for each object type for which these functions are applicable.
To use these functions, I am calling the selectPostProcess() class in my instance classes like this:
public function selectPostProcess ($data)
{
$data = ForumPostUtil::mergeRatings ($data);
$data = ForumPostUtil::mergeComments ($data);
...
}
This works well and keeps the main code centralized in the CoreObjectUtil class with its subclasses providing the data setup to let the code in CoreObjectUtil know what to do.
An alternative approach would be to move the code from CoreObjectUtil into a base instance class which is then inherited in my instance classes. So rather than calling static methods from CoreObjectUtil I would be doing method calls like $this->getComments().
Either approach would work just fine from a functionality type point of view. I'm wondering however what ObjectOriented design guidelines and experienced ObjectOriented developers think of these two approaches. Which way of doing this is preferable and why?
I would appreciate any thoughts/insights on this matter. I can code either way without problem, but I'm having a tough time deciding which route to take.
That code you have now is, I think, the most procedural approach ever posing as OOP i.e what you have now is at the opposite side of OOP. Using the class keyword doesn't make it OOP.
First of all, you should forget about static, it's not that it's bad ot use but it's so easily abused that you really have to try first if the functionality can belong to an object modelling a domain concept (in your case forum related). Only if it doesn't make sense this way, you'll have it as a static method somewhere in a utility class.
Truth be told you have to redesign yur app around the OOP mindset, that is to define classes with behaviour which model a specific concept or process and which have only one responsaiblity. More over you should not mix things like business objects (object which model the forum concepts) with persistence concerns i.e don't put in the same object business functionality and database access. Use a separate class for accessing storage.
Use the Repository pattern to separate business layer from the persistence layer. Try not to mix together create/update functionality with querying IF it complicates things. Use a separate read model specifically for querying in that case.
The code you show us is about querying. You can have a simple DAO/Repository (call it what you want in this case) like this
class ThreadViewData
{
public $Id ;
public $Title;
public $Comments; //etc
}
class ThreadsQueryRepository
{
//we inject the db access object , this helps with testing
function _construct($db) { }
public function GetThread($id){ } //this returns a ThreadViewData
}
The postPRocess functionality is a service that can Merge Ratings and Comments. But maybe the merge functionality is more suitable to the Rating and Comment objects. I don't know the domain to actually give a valid suggestion.
Point is, you have to think in objects not in functions and right now all you have is functions.
I'm building a small framework that I can use for repeated mundane stuff on future small projects.
I'm stuck on the best way to access libraries from inside a controller. I originally implemented a system similar to CodeIgniter's whereby my main controller class is basically a super object and loads all the classes into class variables which are then accessed by extending the controller and doing like $this->class->method()
I find that a little ugly, though. So I thought of just loading each class individually on a per-use basis in each controller method.
What's the best (cleanest) way of doing this?
To only ever have one instance of each class, you could create a simple service container.
class ServiceContainer
{
protected $services;
public function get($className)
{
if (!array_key_exists($className, $this->services)) {
$this->services[$className] = new $className;
}
return $this->services[$className]
}
}
Then create one ServiceContainer instance per application. Inject the container into all of your controllers and use
public function someAction()
{
$this->container->get('Mailer')->send($email_data);
}
Simple example, and obviously needs a lot of work to make useable (for instance autoloading needed and handling of file paths for ease of use, or easier way to add services without getting them, etc).
I dont like the way CodeIgniter does it. Its never seemed right to me. I favor an auto loading class pushed onto the spl_autoload stack. And then just calling the class as normal like:
$class = new SomeClass();
PHP provides autoload functionality with SPL and spl_autoload (and related functions). You can register a custom autoloader for your library code.
For the shared functionality handled by your application, have you considered the Front Controller design pattern?
For projects written in php, can I call more than one (or multiple) controller in class controller? Example in http://img192.imageshack.us/img192/7538/mvc03.gif
ASK: I need to call an action from another controller... And if I do like the picture above, I'm being out-ethics?
Thanks,
Vinicius.
I'm sure that you can do what you want with whichever framework you're using. If you can't do it natively for whatever reason, then you can extend your framework as required.
Having said that, I personally don't like the idea of a controller calling another controller. It seems to somewhat break the MVC paradigm if only from a theoretical standpoint. What I might do instead is build a library class that contains the functionality required and then have both controllers instantiate that class as a member and call the functions required.
For example, using CodeIgniter:
libraries/MyLib.php:
class MyLib
{
public function MyFunc()
{ /* do whatever */ }
}
controllers/ControllerA.php:
class ControllerA extends Controller
{
public function index()
{
$this->load->library('MyLib');
$this->mylib->MyFunc();
}
}
controllers/ControllerB:
class ControllerB extends Controller
{
public function index()
{
$this->load->library('MyLib');
$this->mylib->MyFunc();
}
}
out-ethics? Anywhose... back to reality.
Yes, a controller can call another controller's action. For instance, in cakePHP, this functionality is afforded via requestAction
// pass uri to request action and receive vars back
$ot3 = $this->requestAction('/stories/xenu');
If you're rolling your own, the details of how to implement it will be very specific to your framework.
then you need to modify framework, find place where controller is lounched and add there your second controller.
what framework you are using?
You can do it any way that you want. You don't have to use MVC if you don't want to. However, in MVC you really should only have one controller active at a time. You probably want multiple Views or Models, not another Controller. There is nothing at all wrong in loading, say, a header and footer view for the menu and footer of the site.
If you are building another Controller, then feel that you need to access the functionality of a previous Controller to access its functionality (because it works with a specific / desired Model), then the Model you developed for the latter probably needs to be refactored. IN plain speak, your target Model may be doing too much. Break it up.
You are trying to avoid repeating yourself (DRY) by using calling the methods of a Controller that has already been developed, but in doing so your are creating TIGHT coupling between both controllers! If something changes in the borrowed controller, it will have an effect on the borrowing controller. Not good, Dr. Jones.
Here is a quick overview of the controllers functionality in most of the application:
controller loads a specific model, gets data from it, formats the data and passes the formatted data to the view.
Now there is a search page, which needs to do a search query over entire database (all models). It needs to show each type of data in its particular formatted output on a single page as a list.
The problem:
The search controller can do the search, dynamically load model for each record type, and get the data from model. Problem comes when the data needs to be formatted. I am trying to load the specific controller from the search controller, which is causing problems.
What to do?
PS: I tried using the 'Wick' library, but it fails when the controller's format function tries to use its own model and session object, giving errors about call to a member on a non-object.
After much refactoring and trial/error, It appears that the best way to achieve the above is this way:
Keep the format function in the base controller from which all other controllers are derived. The format options are passed to the function along with the data object as arguments.
Make a static function in each derived controller, which returns the formatting options of the data.
Inside the search controller (which is itself derived from the base controller), for each data object, call the static function of its particular controller which returns the data formatting options, then use that to format the object for the view.
I guess I can say I will stick to using the model only for interaction with the database, and let everything else be done by controller. If anyone has a better solution still, I am all ears.
It sounds like you want to use the Factory design pattern
Make this a library:
class MyModelFactory {
static public function Factory($data) {
$type = key($data);
return new $type($data);
}
}
now, in your controller, you can do something like this:
$model = MyModelFactory::Factory(array($_REQUEST['model'] => $_REQUEST));
and now you have an object of whatever model was specified in $_REQUEST['model']. Be sure to take any security precautions you may need for your application to assure the user has permissions to use the model that they request
Now, since you want to be using common methods and stuff, your models should probably be based off an abstract class / interface.. so instead of
class MyModelOne extends Model {
// stuff
}
You probably want something like this, to ensure your required methods will always be available:
abstract class MyAbstractModel extends Model {
protected $search_params;
public function __construct($data = array()) {
$search_params = $data['search_params'];
}
protected function GetSearchParameters() {
return $this->search_params;
}
abstract public function GetData();
abstract public function GetColumns();
abstract public function DefineViewOptions();
}
class MyModelOne extends MyAbstractModel {
public function GetData() {
$params = array();
$params[] = $this->db->escape_str($this->GetSearchParameters());
// return whatever data you want, given the search parameter(s)
}
public function GetColumns() {
// return some columns
}
public function DefineViewOptions() {
// return some configuration options
}
}
In general you can't load another controller from within a controller in CodeIgniter (although there are mods that allow you to do something like this).
I would try creating a class for formatting your data and add it to the application/library folder. Then load, use and re-use this class throughout your various controllers.
Here is a page from the CodeIgniter documentation Creating Your Own Libraries that explains the details and conventions.
Also, if a class is overkill, creating helper functions is an even lighter approach.
The difference between libraries and helpers in CodeIgniter is that libraries are classes, helpers are just a group of php functions.
Once you have formatted your data, you can load any view from any controller, so you should still have all the re-usability you need so you DRY (don't repeat yourself)
There are a few simple approaches based on the principle of what's simpler (versus what's perfectly DRY). Here's one alternative approach I use with CodeIgniter:
Instead of trying to load multiple controllers, reuse the view fragments from your search controller (or search route, depending which you're using). This requires using the same naming conventions for your data elements so the views are interchangeable, but you should be doing this anyway.
Instead of using multiple models for search, add a single Search model that knows about the things that can be searched on. If you want to prevent duplicate SQL, reuse the SQL between models (this can be done using constants, or loading SQL from disk).
Controllers are not great candidates for reuse from your own PHP code: they route actions and requests for resources to the things themselves. They are intended to be called via HTTP, using the URI interface you've come up with. Calling them from code is a coupling you want to avoid. That said, reusing controllers from JavaScript (or via cURL) is a great, decoupled way to reuse things in any web framework.