Hi I'm pretty new to MVC framework. I decided to build a small application in MVC to get better understanding.
I googled around and found PIP framework that i can use for simple application and then modify once i will get complete understanding.
PIP can be found here
Now i have one question that by looking to PIP framework, do i need to design to new controller for every page that i will use.
For e.g
applications/
views/
home.php
about.php
contact.php
controllers/
main.php
aboutus.php ??
contactus.php ??
For eg. my default controller and view is main.php and home.php and i have a controller for main.php as below:
<?php
class Main extends Controller {
function index()
{
$template = $this->loadView('home');
$template->set('title', "Welcome Homepage");
$template->render();
}
}
?>
So, in this way, do i need to create new conrollers for about and contact.php
PIP's routing is internalized and requires a specific scaffolding of your controllers:
When you go to:
example.com/main
It looks for the controller main and then the function index by default.
If you were going to have 1 controller per view, then it would be something like:
example.com/main
class Main extends Controller
example.com/about
class About extends Controller
example.com/contact
class Contact extends Controller
However, if you went with a default page controller, this would greatly simplify the scaffolding:
example.com/page/{about|contact|main}
class Page extends Controller {
public function about (){
}
public function contact(){
}
public function main(){
}
}
Now 1 controller will handle the delivery of each of these pages.
With pip the URL defines the controller and function that will be executed. If you want the contact page to be at mysite.com/contact, you do need to add a Contact controller.
You do not need to create a new controller for every page. Lets assume you had a forum. You could have the following urls:
mysite.com/blog/write
mysite.com/blog/view/15
These different URLs would all be handled in one controller, blog.php
<?php
class Blog extends Controller {
public function write()
{
echo 'Hello World!';
}
public function view($postId)
{
echo 'Viewing post: ' . $postId;
}
}
I also used PIP as a starter framework, and extended it to include some additional functionality. I even started to document my efforts, but other projects have taken me in other directions.
Happy to share what I have, and some documentation on my PIP efforts can be found at http://www.shed22.com/pip.
Let me know if you would like a copy of the source code and a sample application.
Stephen
Related
I've developed My Own MVC Framework using php.
I call view files in controller like:
include('../view/home.php');
but I want to use it like:
$this->view('home');
How can I define common function for that where I can just pass view name i.e home only and it will do include view file without passing the full file path?
No one could answer you without seeing your codes really. But this should be my approach.
You should have a class that all your controllers extend. Lets say that you have class Controllers and all your controllers extend it.
Then you may have a method inside the class named view($view_name).
public function view($view_name){
include $some_path . '/' . $view_name . '.php';
}
then whenever you call view by $this->view it will include the view if it exists.
This is not the best approach and I did not test the code. I just wanted to show you the path
I don't know Your MVC file/directory/namespace and etc structure.
But for beginner who tries to learn MVC and Frameworks by "reinventing wheel" (: I can give such example:
1) Create common abstract controller class in app/controllers folder:
namespace App\Controllers;
abstract class Controller {
public function view($name) {
include(__DIR__.'/../views/'.$name.'.php';
}
}
2) Create Your own controller i.e. PagesController and use it:
namespace App\Controllers;
class PagesController extends Controller {
public function home() {
$this->view('home');
}
}
p.s. You may omit namespace-ing, abstract word depending on autoloader logic
I'm currently working on CI for my website, and i'm having some trouble about extending Controller_CI.
I have one controller that deals with login/signin actions, which doesn't need authentication, and others controllers that check if a user session exists before loading content.
For that purpose, I created MY_Controller class and add authentication code in the constructor.
Then I made all my controller extend MY_Controller, except the first one that still extends Controller_CI
My question is : Is it the right way to deals with authentication ? Is it still possible to use Controller_CI even if it's extended ?
I found another pattern :
http://philsturgeon.co.uk/blog/2010/02/CodeIgniter-Base-Classes-Keeping-it-DRY
I guess it's better, but still, I don't understand why not using the first solution.
Thanks
Extending controller class for that purpose will work, but this solution is not much flexible. I would rather create a library that handles authentication, and run it from a controller when it is desired. Please read http://ellislab.com/codeigniter/user-guide/general/creating_libraries.html for details about creating custom libraries in CI.
Please remember you can only extend the CI_Controller with MY_Controller only once. In that aspects it's not a good idea. Suppose you want to implement another feature (e.g. a piece of code that makes a specific entry in the log) for some controllers, but not necessarily the controllers that need authentication you cannot make another MY_Controller.
Using a library is a better thing.
I'm using the flexi auth library on a big CI site. On every controller that requires authentication I just add the following:
public function __construct() {
parent::__construct();
$this->load->library('flexi_auth');
if (!$this->flexi_auth->is_logged_in())
redirect('auth/login');
}
I think a combination of what Phil Sturgeon suggests in that blog post and using a library would be best. So I would create a core controller (by that I mean a controller you place into application/core that extends CI_Controller) called MY_Controller which will look something like this
class MY_Controller extends CI_Controller
{
function __construct()
{
parent::__construct();
}
//Any other functions you want
}
Then judging by your question you currently have controllers that fit into two categories
Controllers that do require a logged in user before they do
anything
Controllers that don't require a logged in user before they do anything
So I would then create another controller in the /application/core directory that extends MY_Controller but in its constructor it checks to see if the user is logged in
class Auth_Controller extends My_Controller
{
function __construct()
{
parent::__construct();
//Check to see if the user is logged in
$this->load->library('authentication');
if(!$this->authentication->user_logged_in())
{
redirect('/login');
}
}
//Any other functions you want
}
Now when you create you controller you can choose which one of the core controllers you want to extend. If its a controller than doesn't require a logged in user you can extend MY_Controller but if it does required a logged in user you can extend Auth_Controller. That way it means you only need to do the user login check once in your code.
Like others have said if may be a good idea to place any authentication code into a library as that's a better place to put it than in a controller.
Summary
So to summarise by having all of your controllers extend core controllers rather than CI_Controller it should cut down on code repetition.
I also currently working on a CI project and had the same issue. I have came up with a different solution to deal with the authentication.
I extended the core controller as bellow,
class MY_Controller extends CI_Controller
{
public $data = array();
public $calledClass ;
public $calledMethod ;
public function __construct()
{
parent::__construct();
$authException['authentication']['login'] = true;
$authException['authentication']['logout'] = true;
$authException['welcome']['index'] = true;
$this->load->library("router");
$this->calledClass = $this->router->fetch_class();
$this->calledMethod = $this->router->fetch_method();
if(!#$authentication[$this->calledClass][$authentication->calledMethod] && !Auth::isUserLoggedIn())
{
# IS_AJAX is a contant defined in the contants.php
# define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
if(IS_AJAX)
{
# if this is an AJAX call, it sets a value in the header ,
# which can be captured in the AJAX response
# to redirect the user to the login page.
$this->output->set_header("auth-him:1");
exit;
}
else
{
redirect("authentication/login");
}
}
}
}
Hope the code above is clear and this helps.
To extend core controller more than one time, If you still need to use 2 controllers to handle authentication, I have followed this method
https://stackoverflow.com/a/22125436/567854
Hope this also helps :)
I am trying to learn how to use the Zend Framework and ive ran into trouble. Im trying to place the current users name in the header of the application (displayed on every page), specifically /layouts/scripts/default.phtml.
The MVC architecture is very new to me and confusing me greatly. I do not want to have to place the logic to display this username in the controller every time (this is probably the wrong way to do it anyway), so where would I place the code to assign this variable if not in each controller?
Cheers
This is the kind of thing that action helpers were designed for. A full tutorial on them is a bit beyond the scope of SO, but there are several good tutorials available.
Start with the Zend Framework Documentation and then take a look at Mathew Weier O'Phinney's tutorial and also this one by Rob Allen.
The issue with using a base controller for this kind of thing is that the resources are loaded regardless of wether your controller needs them or not, whereas action helpers are loaded only if needed.
I almost forgot the excellent ZendCasts have a video on action helpers.
You want a base controller and to assign that in the preDispatch method:
class MyApp_Controller_Action extends Zend_Controller_Action {
public function preDispatch() {
parent::preDispatch();
Zend_Layout::getMvcInstance()->assign('username', getCurrentUserName());
}
}
Then extend your own controllers with that new class:
class MyApp_Module_ActionController extends MyApp_Controller_Action {
}
Then in your layout view:
echo $this->layout()->username;
First, read the manual, and than try to accomplish something like this:
class BaseController extends Zend_Controller_Action {
public function preDispatch() {
// your logic to show the user name goes here
}
}
class SomePageController extends BaseController {}
class SomeOtherPageController extends BaseController {}
This will most likely solve your problem.
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');
In my CI system\libraries directory I have a new class named DD_Controller.php. This file looks like this:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class DD_Controller extends Controller
{
protected $ddauthentication;
function __construct()
{
parent::Controller();
$this->ddauthentication = "Authenticated";
}
}
?>
My application controller is defined like this:
class Inquiry extends DD_Controller
{...}
The Inquiry class works fine when I extend Controller, but I get a
Fatal error: Class 'DD_Controller' not
found in
C:\development\localhost\applications\inquiry\controllers\inquiry.php
on line 4
When I extend DD_Controller. In the config file I have the prefix defined as such:
$config['subclass_prefix'] = 'DD_';
Any idea of what I'm missing?
TIA
This is a better approach. Do the following:
Go to the following directory: your_ci_app/application/core/ and create a php file called MY_Controller.php (this file will be where your top parent classes will reside)
Open this the file you just created and add your multiple classes, like so:
class Admin_Parent extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function test() {
var_dump("from Admin_Parent");
}
}
class User_Parent extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function test(){
var_dump("from User_Parent");
}
}
Create your children controllers under this directory your_ci_app/application/controllers/ . I will call it adminchild.php
Open adminchild.php and create your controller code, make sure to extend the name of the parent class, like so:
class Adminchild extends Admin_Parent {
function __construct() {
parent::__construct();
}
function test() {
parent::test();
}
}
DD_Controller.php should be in /system/application/libraries/
If you're using the same CI for multiple apps, and you want them all to be able to extends their controllers to your custom one then you can extend the base Controller class in the same file.
In system/libraries/Controller.php below the Controller class:
class Mega_Controller extends Controller {
function Mega_Controller()
{
parent::Controller();
// anything you want to do in every controller, ye shall perform here.
}
}
Then you'll be able to do this in your app controllers:
class Home extends Mega_Controller {
....
Since the extended controller class you created will be available. I think this is better then overwriting the base controller, but that would work as well.
I recommend to avoid "cracking" CodeIgniter core files.
Better use its native extending possibilities and try to fit into them.
The same rule I would recommend for any PHP library / CMS.
This rule has few reasons:
- ability to quiclky upgrade without takint into account thousands of notes where and how was cracked in core files;
- portability;
- possibility to share your code - eg, this will be usable by both you and your friends in case of need, and it will help them to keep their library up to date, the same as you.
In other words, this is much more professional and it pays to you in the future by usability, portability and by update application possibility.
Regarding your personal question...
As for me, there is nothing bad to create your own library with everything you need to extend native CodeIgniter Controller, then load this library in Controller's constructor and you are done. The only thing to make better usability is to give short name to your library.
This way you can even divide what you need in different pieces and put into separate libraries:
WebFeatures
AdminFeatures
etc.
Then you just load needed libraries in your controller's constructor and you are done.
P.S. I know that proposed way does not fit into "right" OOP concept, but in the same time you must never forget about the integrity of the libraries used.
Everything above is just one more view of mine 7-years experience in professional web development, so I hope it will be helpful if not to follow, then at least to take into account.
Regards,
Anton