CakePHP: using models in different controllers - php

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.

Related

Access Laravel Resource Controller from HTTP Controller

I'm implementing a small project to maintain a list of books. I'm using PHP 7, Laravel 5.5, Eloquent and SQLite.
I created a Model class book and the respective resource controller BookController. For the sake of simplicity, a book only has to public properties: title and author.
Furthermore, I created an AdminController that creates an admin page. I want to use this page to add books to the database and remove other ones.
My BookController has a store() function:
public function store(Request $request)
{
// Validate the request...
$book = new Book;
$book->title = $request->title;
$book->author = $request->author;
$book->save();
}
My AdminController has a HTML form with input fields for new books (one for title, one for author) as well as a submit button. This button calls AdminController#post.
Now I wonder how to actually add the book from there.
Should I call the BookController from the AdminController and pass the request object to the BookController? Is this the way, controllers communicate in Laravel? Or should I avoid the store function and add the functionality to the AdminController directly?
I think you should separate two controller for two purposes. You can declare variable as Book model in other controllers and work with it.
You can using BookController for both, just need to define two routes for one controller and write some logic in the store method, my viewpoint... that is not good way. Because it need check some vars to detect which request from admin and from user. I don't want to make some thing complex between workflow of user & admin.

Controllers structuring in PHP frameworks

I'm going for an example to make the question easier:
If you are implementing facebook, you want to separate user information from account information, from posts, from from from, that means there will be a model for user, a model for user info, a model for posts, a model for for for.
now if you go to user profile, it loads information from all these models, the question is how would you structure the controllers, of course you need controllers for each model to define it's unique actions, but how do i handle the rendering?
do i make a new controller that takes care of all renderings? or do i just put render profile in the user controller - which means it will have access to other models - or do i put in each controller a rendering of it's own and then combine them together...
or maybe if you have a better approach?
i just do not know the consequences of each approach that i thought of, and i don't know if there is a better approach that i didn't think of.
As others mentioned, you don't need a controller specifically for each model. However, given your Facebook example, it's quite simply done through relationships.
An oversimplification would be:
A User model to hold the user's account information and relationships
class User extends Eloquent {
public function posts() {
return $this->hasMany('posts', 'from_user_id');
}
}
A Post model to hold the content and from/to relationships to User
class Post extends Eloquent {
public function from() {
return $this->belongsTo('user', 'from_user_id');
}
public function to() {
return $this->belongsTo('user', 'to_user_id');
}
}
Then perhaps you'd have UserController load a view like so:
class UserController extends BaseController {
public function index($id) {
$user = User::find($id);
return View::make('user_page', array(
'user' => $user,
'posts' => $user->posts()->with('to')->get()
));
}
}
of course you need controllers for each model to define it's unique actions
No, this is wrong.
Controllers are part of your presentation layer, some might say you need a controller for each view object which is okay but for the model layer, it has nothing to do with the number of controllers you have.
a View is an object that toggles multiple templates and once again this has nothing to do with your controller, rendering is a view responsibility.
to understand it more, take a look here , here and here
those are really useful information to start with.
Wrong answer - controllers are not part of presentation layer - they are part of transport layer. Their task is to react on HTTP request.
Request is dispatched by Router. To proof take a look at Laravel source. Controller is a part of Routing package. When you call for example:
Route::get("/","HomeController");
You are just registering request parameters in RouteCollection. But everything is happening inside Router. Controllers can exist without any kind of view layer.

Phalcon - Proper way to route large number of models

I have many models in my project. If I'm following phalcon default convention, I will have to create separate controllers for each models. So if I have 30 models and I want to build simple crud page, then I will have to create 30 controllers as well. I'm using the same crud views for each controller
I route the crud to : /project/admin/:controller/:action. The application is well and running but the problems are :
I have to manage every single controllers
Most of these controllers share same methods and attributes, just different table and few validation
So I want to combine them into a single controller AdminController. Here, I listed all the crud-related actions for each models. For example, accountListAction, cityEditAction, etc. Well yes indeed that the page will become much longer (and IDE will took more time to check) but the result is, shared methods and attributes are reusable between each actions.
Now there are only one controllers. I can access 'list' of model 'account' through /project/admin/accountList. To make the routing looks better, I add more route to specific actions so now, I can access it through project/admin/account/list. (had to define route for every single actions)
The question is : Am I doing it wrong ? Is there any better method to do this ?
What I wanted to achieve is : less controller files, less redundancy
if you have some methods, what you need in many controllers, you can make BaseController
class ControllerBase extends Phalcon\Mvc\Controller
{
public function something_what_you_need_in_many_controller(){
}
}
and then use it while creating controllers:
class PeopleController extends ControllerBase
{
}
so you will have that function something_what_you_need_in_many_controller() in PeopleController.
You don't have to create controller for every model. These 2 are different layers of application, you have controllers - they tells in what view put what data and it can use many models at once. Models are just to handle the connection of data between controller and database.
I think your approach is good but you just need to organize it a bit diferent to make your life easier. Maybe something like this:
As you already did, combine your CRUD operations in a single
controller (AdminController)
Instead of creating a action for every combination of CRUD/Model (like cityEditAction), create one action for each CRUD and any aditional action you want (exportToCSVAction for example)
Then at every action you receive as first parameter the model type like list/city and if needed the id as second paremeter like list/city/2.
After this every action can be implemented to work with any model type. Here's a example of a deleteAction():
public function deleteAction($modelType, $id)
{
if($this->modelTypeExists($modelType))
{
//Check if the user has the required privilegies for this action
//See http://docs.phalconphp.com/en/latest/reference/acl.html
if($this->acl->isAllowed($currentUser->accessGroup, $modelType, "delete"))
{
//Get the model being manipulated
$model = $this->getModelById($modelType, $id);
//Attempt to issue the required action
if ($model->delete() == false)
{
//Something went wrong with the deletation
}
else
{
//Horray!!
}
}
else
{
//Denied
}
}
else
{
//Error
}
}
NOTE: modelTypeExists and getModelById aren't built-in functions, they're just illustrative functions for the answer.

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.

CodeIgniter 2.1.0: Accessing models within Models

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!).

Categories