Help organising controllers logically - php

I'm working on a site which i'm developing using an MVC structure. My models will represent all of data in the site, but i'm struggling a bit to decide on a good controller structure. The site will allow users to login/register and see personal data on a number of pages, but also still have access to public pages, e.g FAQs, Contact page etc.
This is what I have at the moment...
A Template Controller which handles main template display. The basic template for the site will remain the same whether or not you are logged in.
A main Website Controller which extends the Template Controller and handles basic authentication. If the user is logged in, a User::control_panel() method is called from the constructor and this builds the control panel which will be present throughout the authenticated session. If user is not logged in, then a different view is loaded instead of the control panel, e.g with a login form. All protected/public page related controllers will extend the website controller.
The user homepage has a number of widgets I want to display, which I'm doing via a Home Controller which extends the Website Controller. This controller generates these widgets via the following static calls:
$this->template->content->featured_pet = Pet::featured();
$this->template->content->popular_names = Pet::most_popular();
$this->template->content->owner_map = User::generate_map();
$this->template->content->news = News::snippet();
I suppose the first thing I'm unsure about is if the above static calls to controllers (e.g Pet and User) are ok to remain static - these static methods will return views which are loaded into the main template. This is the way I've done things in the past but I'm curious to find out if this is a sensible approach. Other protected pages for signed in users will be similar to the Home Controller.
Static pages will be handled by a Page Controller which will also extend the Website Controller, so that it will know whether or not the user control panel or login form should be shown on the left hand side of the template. The protected member only pages will not be routed to the Page Controller, this controller will only handle publicly available pages.
One problem I have at the moment, is that if both public and protected pages extend the Website Controller, how do I avoid an infinite loop - for example, the idea is that the website controller should handle authentication then redirect to the requested controller (URL), but this will cause an infinite redirect loop, so i need to come up with a better way of dealing with this.
All in all, does this setup make any sense?! Grateful for any feedback.

I have my controllers laid out like this:
/**
* Global controller
*/
class MY_Controller extends Controller {
function __construct() {
parent::__construct();
// Load templates, modules etc
}
}
/**
* Admin controller
*/
class Admin_Controller extends MY_Controller {
function __construct() {
parent::__construct();
// Check admin is logged in
}
}
/**
* User controller
*/
class User_Controller extends MY_Controller {
function __construct() {
parent::__construct();
// Check user is logged in
}
}
Any user page would extend User_Controller and admin page would extend Admin_Controller that way you can easily put in authentication without many headaches and keep it all seperate.

Related

Using custom named controllers with codeigniter

Hi I'm working on a application that uses a admin environment and a user environment. To make my code and controllers more readable I would like to use some kind of a prefix for my admin and user controllers. Or maybe use a different directory for the admin en user controllers. Without using the exact name in the url to call the controllers.
Does anybody know if there is a way to do this or a work around for my idea.
For example I would like to use: user.[controllername].php or user_[controllername].php
EDIT:
So when I use routes to separate the user controllers from the admin controllers, it brakes my template resolver.
For instance lets say the url is: http://myapplication.com/user/profile in normal cases this would call the user controller and the function profile. My template resolver looks for the folder user and checks if there is a level1.tpl file.
Lets say we want to edit this profile the url would be: http://myapplication.com/user/profile/edit/1 now it would search in the folder user for a level2.tpl file and would call the function edit with id 1.
The problem with the routes is that it prepends something to the url witch I don't want because then it searches in the wrong folder for instance when we use admin/dashboard it will look in the folder admin instead of the folder dashboard.
So basically what I only need is only to tell the application to use a different directory where the controllers are located or a different filename base on what kind of user is logged in.
Thanks in advance, for sharing you knowledge.
You can do that in many ways.
1. Create two file in application/core named "Admin_Controller.php" and "User_Controller.php" with following class signature,
class Admin_Controller extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
}
and
class User_Controller extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
}
In these classes you can do use your PHP logic to do whatever you wants, just simply extends your Controllers to Admin_Controller or User_Controller.
eg: class Home extends User_Controller {} or class Dashboard extends Admin_Controller {}
2. You can also simply do that with routes.php
eg:
// for admin
$route['admin/(.+)'] = 'admin_$1';
// for frontend
$route['(.+)'] = 'user_$1';
I hope this might give you some idea.

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.

CI Hacking the routes

So, i have some problem.
I just want to create some website where visitor can interact with my site if they're registered.
Let say they've provided their username,email,password, blah..blah..blah...
And then after they provided their blah..blah..blah.. it will autologin (if their data is passed) to my site.
After they logged in my site, they must provided more data again, like they uploaded their profile picture, how they control their privacy in my site, like step by step registration.
I don't want they interact with my site, until they complete their registration.
How do i make every page in my site looks like registration page until they finished their registration.
It's not like i will give this kind of function right.
if(is_login()){
if(is_registration_complete()){
//you're free to go
} else {
// complete your registration first
}
} else {
//you're not logged in
}
In my every controller, if you know what I mean :)
How do I create this function globaly?
If their registration isn't complete, they will go to registration controller, in every routes.
If they complete their registration, they will go to the, yeah you know the default routes.
I'm so sorry if my English is bad, English isn't my native language, sorry for grammar mistakes :)
The easiest is probably to create a library with your checking function and then to include it in the Constructor of the impacted ControllerS :
class Blog extends CI_Controller {
public function __construct()
{
parent::__construct();
// Load the lib here or Autoload
$this->load->library('mylogincheckhelper');
$this->mylogincheckhelper->is_complete();
}
}
And then you do all the ckecks and routing in the Lib.
create a view with your post-registering stuff and make them conditionally visible. and include the view in your templates.
One way you can do it is to create a custom controller by extend the core CI_Controller. Then you can have your page controllers extend from your custom controllers. By extending, you inherit the functions of the parent, as well as run the parent constructor (or run it if you override it), making them "globally available" to whoever extends it.
//extend the core controller
class MY_Controller extends CI_Controller {
//override to provide additional functionality
public function __construct(){
//run the core controller
parent::__construct();
//then do your login and registration checks here
//you can put code here, call another function or load a helper class
//or better, redirect them to your registration page
}
}
//your page's controller extending from your custom controller
class Page extends MY_Controller {
//not overriding the constructor will execute the parent constructor
//every page that extends your extended controller will inherit it's functions
//and execute it's constructor
}

Can i handle Codiegnitor admin and main website within same application?

actually i am looking to handle my website/admin panel withing same application. so i want to know that is that possible?
i means structure something like this
http://www.mysite.com
and for admin
http://www.mysite.com/admin
so this all i need to handle withing one application of codeignitor. i don't want two codeignitor installation for this purpose.
Sure, you can, see the section at CI docs which says:
Running Multiple Applications with one CodeIgniter Installation
You can also create separate folders for your controllers, models and views like:
+controllers
+front (main site controllers will go here)
+admin (admin controllers will go here)
+models
+front (main site models will go here)
+admin (admin models will go here)
+views
+front (main site views will go here)
+admin (admin views will go here)
See the section:
Organizing Your Controllers into Sub-folders
First Create a base controller for the front and/or backend. Something like this:
// core/MY_Controller.php
/**
* Base Controller
*
*/
class MY_Controller extends CI_Controller {
// or MY_Controller if you use HMVC, linked above
function __construct()
{
parent::__construct();
// Load shared resources here or in autoload.php
}
}
/**
* Back end Controller
*
*/
class Admin_Controller extends MY_Controller {
function __construct()
{
parent::__construct();
// Check login, load back end dependencies
// Create and setup admin user session and other all dynamic admin url for image,js,css,etc..
}
}
/**
* Default Front-end Controller
*
*/
class Front_Controller extends MY_Controller {
function __construct()
{
parent::__construct();
// Load any front-end only dependencies
// Get user data of session and generate other all dynamic front url for image,js,css,etc..
}
}
Back end controllers will extend Admin_Controller, and front end controllers will extend Front_Controller.Now You can create any admin side controller & models and extends to Admin_Controller and front side extends to Front_Controller.
E.g (Any Admin Controller) :
class Admin extends Admin_Controller{
function __construct(){
parent::__construct();
}
}
E.g (Any Front Controller) :
class Home extends Front_Controller{
function __construct(){
parent::__construct();
}
}
Use URI routing where needed, and create separate controllers for your front end and back end side. All helpers, classes, models etc. can be shared if both the front and back end controllers live in the same application.

Code Igniter - how would you structure this site?

I'm going to do my first site in code ignitor, a fairly basic site like this:
home
login / register
members area
protected page 1
protected page 2
protected page 3
general info section
page 1
page 2
page 3 (dynamic table of reports)
about section
page 1
page 2
blog section
listing
article page
I've gone through a couple of basic tuts and have read some of the documentation but still feel unsure on what would be the best way to structure this. Could anyone that is experienced with CI show me an example of how they' do it?
some specific Qs are:
header with nav panel will be the same on all pages. normally i'd code that as an include with if/else to show highlighted current section. I guess I'd just keep this as an include (view) and either load it first via the controller or include it in every view?
I'd envisage having a model called 'user' which will handle the login and registration, a model called 'blog' and a model called 'reports'. Does that sound right?
for static sections like about, I guess there'd be no model and i'd just have a controller with a function for each static page? i.e. about.php with page1(), page2() and all they do is load static views?
1 -> To fix this problem, I decided to use my own controller like this
Using CI 2.x, create a file under app/core called MY_Controller.php like so :
<?php
class MY_Controller extends CI_Controller {
function __construct() {
parent::__construct();
}
public function loadView($view) {
$this->load->view('header');
$this->load->view($view);
$this->load->view('footer');
}
}
And then I extend this controller instead of the CI one. Be sure that your $config['subclass_prefix'] = 'MY_'; in the config.php file.
2-> yes
3-> thats about it :D
I'm a newbie here (codeigniter) but:
For headers/footers I adopted the template strategy from here (first alternative). Worked nice.
Before models, I'd plan the controllers -roughly one per each section. I made all them inherit from a MY_controller here I place common funcionalilty. And yours models seems about right to me. I think them rathar as DAOs, or "service objects" that provide access to the database and not much more. GEneral intelligence of the site (if needed) should be in a custom library, or inside the controllers.
Yes.
You should use an CI library to handle your user registration and per page authorisation.
Here's a very simple example on how you could do it. Keep in mind that CI uses the MVC pattern
class Reports extends CI_Controller {
public function __construct() {
parent::__construct();
// load database if needed
// load a model if needed
}
public function page() {
//get the page requested
$page_id = $this->uri->segments(2);
// based on the page_id do something.
$data['somedata'] = 'About us data here';
// this is an actual file loaded from the template view
$data['maincontent'] = 'my_page';
$this->load->view('template',$data);
}
}
class About extends CI_Controller {
public function __construct() {
parent::__construct();
// load database if needed for this page
}
public function page() {
// same here
//get the page requested
$page_id = $this->uri->segments(2);
// based on the page_id do something.
$data['somedata'] = 'About us data here';
// this is an actual file loaded from the template view
$data['main_content'] = 'my_about_page';
$this->load->view('template',$data);
}
}
in the template file
$this->load->view('template/header');
$this->load->view('template/nav');
$this->load->view($main_content);
$this->load->view('template/footer');

Categories