How to structure my CakePHP admin plugin - php

I'm considering creating a plugin for the admin portion of my application and am seeking some guidance on how it should be structured. I will be using CakePHP 2.5.x.
Part 1:
I will be Auth as well as Acl. Should I be configuring this within /app/Controller/AppController.php or /app/Plugin/MyPlugin/Controller/MyPluginAppController.php?
Part 2:
Let's say I want to access the Post Model: /app/Model/AppController.php from within my plugin. What's the best way to do this within my plugin?
Which one of these files should I create to handle this? Do I even need to create a model within my plugin if I'm just extending the model from the main app?:
//Model
/app/Plugin/MyPlugin/Model/Post.php //Will this conflict with /app/Controller/PostsController.php?
/app/Plugin/MyPlugin/Model/MyPluginPost.php
//Controller
/app/Plugin/MyPlugin/Controller/PostsController.php //Will this conflict with /app/Controller/PostsController.php?
/app/Plugin/MyPlugin/Controller/MyPluginPostsController.php
How should I handle the data within the plugin's Post Controller? Am I on the right track with this?
<?php
// app/Plugin/MyPlugin/Controller/MyPluginAppController.php
App::uses('Posts.Post', 'Controller');
class MyPluginPostsController extends MyPluginAppController {
public function index() {
$this->Post->recursive = 0;
$this->set('posts', $this->Paginator->paginate());
return $this->Crud->execute();
}
}
I realize I've asked a lot of questions, I just want to make sure what I'm doing is feasible/logical.

Related

how to retrieve data in view Independent of controller in codeigniter

I have a sidebar in my site that receive some information from db and I can't use controller for retrieve data because I have different controller and same sidebar. How can I print this data in view page.
when I wrote in P.h.P code in the view it shows an error that it cant define variables.
How could I do this?
When you find that you need the same code in many different controllers a "custom library" (class) is the perfect choice. Documentation for creating your own libraries is found HERE.
Controllers should be using models to get data from the database. Custom libraries can also use models just like controllers. Here is a very basic custom library called Sidebar. It depends on a model (sidebar_model) that will not be shown. The purpose of the Sidebar library is to return the variables need by the sidebar_view file.
File: application/libraries/Sidebar.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Sidebar
{
protected $CI; // Read the documentation link to see why this is needed.
public function __construct()
{
$this->CI = & get_instance();
$this->CI->load->database(); //only needed if not already done
$this->CI->load->model('sidebar_model');
}
public function get_sidebar_data()
{
return $this->CI->sidebar_model->get_sidebar();
}
}
The library method get_sidebar_data() returns the variables for the view.
Here is a controller that uses the custom library. It will use the custom library and a view file (not shown) containing HTML for the sidebar.
File: application/controllers/Main.php
class Main extends CI_Controller
{
function __construct()
{
parent::__construct();
$this->load->library('sidebar'); //can also be autoloaded
}
public function index()
{
$data['sidebar'] = $this->sidebar->get_sidebar();
$this->load
->view('banner')
->view('sidebar_view', $data)
->view('main_view')
->view('footer_view');
}
}
Any other controller that needs to show the sidebar would use this same pattern.
This controller loads four different view files and is using "method chaining" which is encouraged. Method chaining executes a tiny bit faster. But the best reason for using it? Less typing.
The method chaning could also be type like this:
$this->load->view('banner')->view('sidebar_view', $data)->view('main_view')->view('footer_view');
But, IMO, putting each ->view() on a separate line makes it easier to read.
You can create a helper for your common tasks. Then create a function for your sidebar and call it where you need it. Check this link for more details about creating helper
You can also create a library for it. Although it will not a very good choice.
create sidebar (view page) and Call model directly inside that sidebar (view page).
secondly call sidebar (view page) directly inside all other view pages.

codeigniter: one controller several actions

I'm using codeigniter. I'm currently working on my routes and controller.
Last week, I explored symfony2 and I liked something:
class DefaultController extends Controller
{
public function indexAction()
{
return $this->render('LVIndexBundle:Default:index.html.twig');
}
public function servicesAction()
{
return $this->render('LVIndexBundle:Default:services.html.twig');
}
public function shoppingAction()
{
return $this->render('LVIndexBundle:Default:services.html.twig');
}
In the controller, each action renders a view.
I would like to do the same in codeigniter -> get several functions / actions leading to distinct views.
I'm new to codeigniter. So far, I understood that 1 controller = 1 view.
I'd like to get 1 controller = several functions for several pages. Otherwise, that would be a lot of pages.
Thanks very much for your help!
Based on my experience(s):
In CI, a controller can has more than 1 view php file
ex (function indexAction as a controller function):
public function indexAction()
{
$this->load->view('header');
$this->load->view('content');
$this->load->view('footer');
}
In Symfony and Codeigniter the controllers are just classes that can hold multiple methods. The methods that are called (called Actions in Symfony) are the place that decides which view(s) must be rendered. One of the main differences between Symfony and CI controllers are the routings that Symfony uses. The routes makes Symfony more flexible then CI.
take a look for an explanation of CI controllers
p.s. Symfony is much more advanced then CI. I like to advise you Symfony :-)
Its absolutely not true that there should be one view per controller. even something as simple as validating a form - you will call different views depending on if the validation passes or not.
Strongly suggest you step through the Tutorial in the codeigniter manual. this is going to answer a lot of questions and its very practical.

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.

How to load Model into a controller in MVC

I am working on building a lightweight MVC, mainly for the learning process but I would like it to be good enough to use eventually.
Below is a basic example/demo of how a basic controller might would look, let's assume the URI has been processed and routed to this controller and these 2 methods.
1) I need to get data from database/cache/etc... inside my Model classes, I just need help on how I should load my models into my example controller below, you can see that I have added this below $profileData = $this->model->getProfile($userId) that is just made up and does not exist's, how could I get something like that to work though? Or should I load the model into the class a different way?
2) A lot of pages will require a user to be logged into the site. SHould I process that part below in the controller to check if a user is logged in, example, before building the profile page, check if user is logged in, if not then build a login page instead and add these checks inside of each controller method/page?
/**
* Example Controller
*/
class User_Controller extends Core_Controller {
// domain.com/user/id-53463463
function profile($userId)
{
//GET data from a Model
$profileData = $this->model->getProfile($userId);
$this->view->load('userProfile', $profileData);
}
// domain.com/user/friends/
function friends()
{
//GET data from a Model
$friendsData = $this->model->getFriendlist();
$this->view->load('userFriends', $friendsData);
}
}
core
abstract class Core_Controller {
protected $view;
protected $model;
function __construct(DependencyContainer $dependencyContainer){
$this->view = new Core_View();
//$this->view = $dependencyContainer->get(view);
}
}
There are probably tons of ways to accomplish what you are trying.
The "easiest" is probably to just override the constructor and instantiate the model directly.
in User_Controller:
public function __construct(DependencyContainer $dc) {
parent::__construct($dc);
$this->model = new User_Model();
}
I'm guessing that you are looking for something a little more automated though. If you want the Model to have the same name as the controller minus "_Controller", just use get_class($this) in the constructor and use PHP's string functions to parse out what you want. Once you have that in a variable, you can use that variable to instantiate the model:
in Core_Controller:
public function __construct(DependencyContainer $dc) {
$this->view = new Core_View();
// $model_class should be 'User_Model' now
$model_class = str_replace('_Controller', '_Model', get_class($this));
// now instantiate the model
$this->model = new $model_class();
}
I haven't actually worked with any framework that can only have one model associated with each controller (except may CakePHP? I can't remember). With Symfony, the models and controllers are completely decoupled so you can use any model with any controller. You just instantiate the model as need. Symfony use the Doctrine ORM so for example, in a controller action, if you needed a model you would do something like this:
$model = Doctrine::getTable('User');
It might be worthwhile to consider a design more like that in order to promote a decoupled design and I promise that you will want more than one model in some controller at some point.
2.) As far as authentication. Something that seems to be fairly common is to have some sort of setting (whether in a config file or a member variable) that says whether or not the current action needs the user to be authenticated. This is processed each time the action runs (Yii calls these kinds of things filters). If the user needs to be logged in, it stores the page that they are trying to access, and then redirects them to a log in page (you should only ever have to create one). Once they properly authenticate, it will redirect them back to where they were originally heading.

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