CodeIgniter 2.1.0: Accessing models within Models - php

I have four models in CodeIgniter for a forum I am building:
forum_model
category_model
user_model
subject_model
I wish to access the category, user and subject models within the forum model (ie: browse thread by user / category / subject) but they need to be independent for individual functions (ie: add user / subject / category)
Theres a lot more independent functions and basically what I was wondering was if it is bad practice to create a 'master' forum model (and what the best way to create the model would be) or if I should just do the linking in the controller?
I was thinking about setting the forum_model up like this:
class Forum_model extends CI_Model {
function __construct() {
parent::construct();
$this->load->model('Category_model', 'category');
$this->load->model('User_model', 'user');
$this->load->model('Subject_model', 'subject');
}
}
then possibly accessing the other models within methods using variable variables $this->$model->method()

In 2.1.0, any property (i.e. model reference, library, etc.) not defined in a model's scope will magically access the CI super object:
<?php
function __get($key)
{
return get_instance()->$key;
}
So, as long as you don't have $category $user or $subject member variables in your forum model, this should work.
However, usually it's good practice in MVC for models NOT to know about each other. I'd caution you not to let your forum model function like a controller or a library (otherwise, it should be a controller or a library!).

Related

how to create multiple models against multiple function in single controller in CakePHP

i think, In "CakePHP" one model is against each controller but i have multiple functions in single controller and each function represent different page and database table.
i.e
public function manage_categories(){}
public function manage_sub_categories(){}
above 2 functions are in Admin Controller but now the issue is how to create model against each function to represent database. each function has unique attributes in database.
One thing more either model name should be same to controller name "admin" or this name will be same as functions name. while in normal circumstances model name is same to controller name.
"Users" model name is used against "UsersController"
kindly guide me ti resolve above said issue. i tried enough to solve it bot couldn't.
Thanks in advance.
If you have two database tables it would be logical and best practice in terms of SoC to have two controllers instead of throwing a lot different things that don't belong into the same domain into a single controller.
Sometimes when you just want to use a part of data from an associated model you can access it through the associations:
$this->Model->SubModel->foo();
Also you say you have an admin controller which is a working but not very good approach. Instead CakePHP features prefix routing. So an action accessed like /admin/categories/some_action will route to the CategoriesController some_action() action.
"Users" model name is used against "UsersController"
Is wrong, by convention models should be named singular, not plural. Your UsersController won't find an Users model because it's looking for an User model.
And stay away from Model::query(), use the ORM instead as much as you can.
public function manage_categories(){}
public function manage_sub_categories(){}
Should become:
class CategoriesController extends AppController {
public function admin_index() { /*...*/ }
}
class SubCategoriesController extends AppController {
public function admin_index() { /*...*/ }
}
But assuming that sub-categories belong to a category which is the same table I don't see a need for a second model or second controller at all.

Method in one controller calling a method in another controller, using MVC

so i have a user controller, that has methods to update profile, etc. In the system i am developing the user would need to post articles, etc. So i am confused with the design of the system. The main logic of creating articles would be housed under the article_model. But how should i call the methods?
I can create a function in the user controller that calls on the article model to create article?
I can call a method in the user controller and create an article controller and the user controller calls the method on the article controller, which in turns call the model for the main logic.
Or just directly call on a article controller that connects to the article model.
I personally feel i need to have a user controller into this system, as logically speaking a user creates article. So which design is perfect in terms of logic and best practices.
You can load multiple models in a controller, you’re not just restricting to the model in the same domain as the controller. So if you need to interface with articles in the users controller, then just load the articles model. As deceze says, you shouldn’t call other controllers in one controller; that definitely goes against MVC conventions.
In your case, any interaction with an article should be in the articles controller though, accessible at a URL like /articles/add.
I actually use codeigniter and they do it this way. If you want to post an article from your user or profile controller you can just make an instance or load your model.
class ProfileController extends BaseController {
public function __construct()
{
$this->load->model('article_model');
}
public function index(){
$this->article_model->post();
}
}
don't call a controller from another controller
you can add link to any view called with the profile that reefers to add article
if you have to call the controller from another you may have a look at codeigniter hmvc
HMVC: an Introduction and Application
Try to use this extension HMVC for CI. It's allow to call controller methods in another controllers. Something like this:
class Dashboard extends MX_Controller{
public $autoload = array();
public function __construct()
{
parent::__construct();
}
public function index()
{
$params = 'some_params';
$data['some_data'] = Modules::run('another_controller/method', $params);
}
}
Where another_controller - simple CI controller, what expand MX_Controller.

Would bypass of the controller in CodeIgniter be considered a good practice?

Is directly call to the Model class inside the View is best practice or not? Currently I am using CodeIgniter to develop an application. In different Views of my application I'm including menus that I want to pull from the database. And the thing is currently I am passing the values to the menu through the controller. If I make a common model class and call it from the View and by pass controller. So that there will be one call to Model and it will load menu from the database at once and by pass the controller. By doing this what pros and cons will come?
With codeigniter, your views should not be concerned as to where data comes from, only that it exists. Only your Controllers should be in direct contact with your Models.
It sounds like you have a common menu that you want to load in your views and you don't want to replicate that code across all your Controllers.
To solve this problem, you need to create a common controller that your primary controllers inherit from with a method that fetches the menu.
My_Controller needs to be saved to the core folder in the application directory.
class MY_Controller extends CI_Controller
{
protected function get_menu()
{
// Load your menu here
$this->load->model('menu_model');
return $this->menu_model->get_menu();
}
}
All your primary controllers will inherit MY_Controller
class Home_Controller extends MY_Controller
{
public function index()
{
$page_data = array('menu' => $this->get_menu());
$this->load->view('home/index', $page_data);
}
}
In my opinion no its not best practice. View should contact Controller and Controllers should retrieve data from Model where Model does all the logic. Controller suppose to be the glue or middleman of View and Model.
Controller passes the returned data into View and then you do your foreach loop or whatever to display it.
View should not be doing any logic. Retrieving data from database is somewhat logic.
It is a worst practise. Then why we have controller concept for MVC. :) Mainly all logics goes into Model so thats not good to call model directly.
There will not be any problem, since you are using a common controller.
Note : You should not call model directly from view.

OOP abstraction with CodeIgniter Models

I'm writing a library search engine where a user can search based on various criteria (e.g., author, title, publisher, etc.) with CodeIgniter. So, I defined the interface BookSearch which all classes responsible for searching the database will implement
interface BookSearch{
/**
Returns all the books based on a given criteria as a query result.
*/
public function search($search_query);
}
If I want to implement a search based on authors I can write he class AuthorSearch as
class AuthorSearch implements BookSearch extends CI_Model{
function __construct(){
parent::__construct();
}
public function search($authorname){
//Implement search function here...
//Return query result which we can display via foreach
}
}
Now, I define a Controller to make use of these classes and display my results,
class Search extends CI_Controller{
/**
These constants will contain the class names of the models
which will carry out the search. Pass as $search_method.
*/
const AUTHOR = "AuthorSearch";
const TITLE = "TitleSearch";
const PUBLISHER = "PublisherSearch";
public function display($search_method, $search_query){
$this->load->model($search_method);
}
}
This is where I hit my problem. The CodeIgniter manual says that, to invoke a method in a model (i.e., search), I write $this->AuthorSearch->search($search_query). But since I have the class name of the search classes as strings, I can't really do $this->$search_method->search($search_query) right?
If this was in Java, I'd load objects into my constants. I'm aware that PHP5 has type hinting but the target platform for this project has PHP4. And also, I'm looking for a more "CodeIgniter" way of doing this abstraction. Any hints?
You can really do $this->$search_method->search($search_query). Also in CI you can assign library name as you want.
public function display($search_method, $search_query){
$this->load->model($search_method, 'currentSearchModel');
$this->currentSearchModel->search($search_query);
}
What you're talking about it the driver model. You can, in fact, do what you're suggesting can't be done:
<?php
$this->{$search_method}->search($search_query);
CodeIgniter has CI_Driver_Library & CI_Driver classes to do this (See CodeIgniter Drivers).
However, I've found that it's usually simpler to implement an interface / extend an abstract class like you're doing. The inheritance works better than CI's drivers.

CakePHP: using models in different controllers

I have a controller/model for projects. so this controls the projects model, etc, etc. I have a homepage which is being controlled by the pages_controller. I want to show a list of projects on the homepage. Is it as easy as doing:
function index() {
$this->set('projects', $this->Project->find('all'));
}
I'm guessing not as I'm getting:
Undefined property: PagesController::$Project
Can someone steer me in the right direction please,
Jonesy
You must load every model in the controller class by variable $uses, for example:
var $uses = array('Project');
or in action use method
$this->loadModel('Project');
In my opinion the proper way to do this is add a function to your current model which instantiates the other model and returns the needed data.
Here's an example which returns data from the Project model in a model called Example and calls the data in the Example controller:
Using Project Model inside Example Model:
<?php
/* Example Model */
App::uses('Project', 'Model');
class Example extends AppModel {
public function allProjects() {
$projectModel = new Project();
$projects = $projectModel->find('all');
return $projects;
}
}
Returning that data in Example Controller
// once inside your correct view function just do:
$projects = $this->Example->allProjects();
$this->set('projects', $projects);
In the Example view
<?php
// Now assuming you're in the .ctp template associated with
// your view function which used: $projects = $this->Example->allProjects();
// you should be able to access the var: $projects
// For example:
print_r($projects['Project']);
Why is this "better" practice than loading both models into your controller? Well, the Project model is inherited by the Example model, so Project data now becomes part of the Example model scope. (What this means on the database side of things is the 2 tables are joined using SQL JOIN clauses).
Or as the manual says:
One of the most powerful features of CakePHP is the ability to link relational mapping provided by the model. In CakePHP, the links between models are handled through associations.
Defining relations between different objects in your application should be a natural process. For example: in a recipe database, a recipe may have many reviews, reviews have a single author, and authors may have many recipes. Defining the way these relations work allows you to access your data in an intuitive and powerful way. (source)
For me it's more reasonable to use requestAction. This way the logic is wrapped in the controller.
In example:
//in your controller Projects:
class ProjectsController extends AppController {
function dashboard(){
$this->set('projects', $this->Project->find('all'));
}
$this->render('dashboard');
}
Bear in mind that you need to create dashboard.ctp in /app/views/projects of course.
In the Page's dashboard view (probably /app/views/pages/dashboard.ctp) add:
echo $this->requestAction(array('controller'=>'projects', 'action'=>'dashboard'));
This way the logic will remain in the project's controller. Of course you can request /projects/index, but the handling of the pagination will be more complicated.
more about requestAction(). but bear in mind that you need to use it carefully. It could slow down your application.

Categories