Thursday, 12 February 2015

CodeIgniter: a good MVC PHP Framework to start with

Here is a list of books, that I particularly, recommend, if you would like to get familiar with CodeIgniter:
  1. "CodeIgniter for Rapid PHP Application", from David Upton (published by Packt Publishing), 2007
  2. "CodeIgniter 1.7 Professional Development", from Adam Griffiths (published by Packt Publishing), 2010
  3. "Wrox Professional CodeIgniter", from Thomas Myer (published by Wiley Publishing), 2008

Model - View - Controller

Model - View - Controller (MVC), as the name implies, is a design pattern that allows developers to cleanly separate their code into three categories:
  • Models maintain data : The Model represents any type of data that your application may use. Some examples of data that your application might use would be: a database, RSS Feeds, API calls, and any other action that involves retrieving, returning, updating, and removing data.
  • Views display data and user interface elements : Views are the information that is being presented on the screen to users through their web browsers. These are usually HTML files, sometimes containing PHP code that builds the template for the website.
  • Controllers handle user events that affect models and views : Controllers are the business logic of your application.They serve as an intermediary between Models and Views. Controllers are the core of your application because they determine how HTTP requests should be handled.The Controller will respond to HTTP requests and generate web pages. It’s the controller that monitors the activity of the user (who clicks a link, moves the mouse, or submits a form)  and takes the appropriate action (such as manipulating the model and updating the view). 

“ Convention over Configuration ”

"Ruby On Rails" has this idea that allows small teams of developers to create web applications in a tenth the time, with less debugging and fewer headaches. This idea has been incorporated into every single PHP framework, CodeIgniter included.
The result has been an enormous amount of time saving and effort reduction in development.

Comparing PHP MVC Frameworks

Several PHP MVC frameworks have emerged in the past few years, among them CakePHP, Symfony, and CodeIgniter. The next section provides a brief comparison of these three PHP
MVC frameworks.

  • CakePHP’s automatic approach allows the developer to create web applications quickly. For example, the automation allows a model to map easily to a database table. If you don ’ t really care how things work underneath, this approach can be strangely liberating. However, if you really want to understand what is happening, you sometimes have to dig around in the core code.
  • Symfony took a page from Ruby on Rails, providing developers with a series of command - line tools to help build admin panels, object - relational mapping schemes, views, and other niceties. Run a few scripts and suddenly you have a surprising amount of work done for you.
  • CodeIgniter has a different approach. Just about all your work will be in the controller. That ’ s where you load libraries, extract data from the model, and pull in views. Everything ’ s in plain sight, so it ’ s easy to keep things organized and troubleshoot problems if and when they occur. There is no standard naming convention for models and controllers. Developers can manually load models or autoload them in the main configuration, and the models don ’ t have to be named a certain way to match up to tables. What this means is that legacy applications are extremely easy to port over to CodeIgniter, and integration with outside database systems is generally very easy. CodeIgniter's approach to MVC is very loose. This means that Models are not required. This is for a number of reasons. Firstly, CodeIgniter's Database Library can be used in both Models and Controllers—meaning that the extra separation of Models can be bypassed. Secondly, the Model isn't tied to the database, as it is in other frameworks such as Ruby on Rails, so the Model isn't needed in this regard. Finally, if using a Model in your application will cause unnecessary complexity, then the Model can simply be ignored. However, Models are extremely useful, even though they are optional. Models can be loaded from any Controller, so if you use a Model function in multiple controllers and you need to change the function, you only need to edit it in one place rather than in all of the controllers. Complex queries should really be put into a Model. A collection of related queries should also be put into a Model as they can be grouped together. This makes your applications simpler, and it allows you to use the functions in any Controller.

CodeIgniter also allows a great deal of flexibility when querying tables.

//place raw SQL in the query() method
$q = $this- > db- > query(“select * from users”);
//or pass in a variable
$sql = “select * from users”;
$q = $this- > db- > query($sql);
//or use the built-in get() method
$q = $this- > db- > get(‘users’);

Helpers and Libraries

  • CakePHP is pretty light on built - in helpers and libraries,
  • Symfony ’ s suite of tools for unit testing, scaffolding, and admin generation is probably the best of all three. These tools may not be used every day, but they offer plenty of shortcuts for the developer.
  • CodeIgniter comes with an amazing range of libraries and helper files that cover a lot of what you will encounter in just about every project: caching, security, file uploads, link building, form building, text parsing, regular expressions, database queries, FTP, e - mail, calendaring, sessions, pagination, image manipulation, validation, XML - RPC, dates, cookies, XML, and more. You can also extend built - in libraries and helpers and create your own.

The Famous "Hello World" example using CodeIgniter v2.2

Let's create a simple Hello World controller, with a file called hello.php in codeigniter/application/controllers/.

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class hello extends CI_Controller {

public function __construct(){
parent::__construct();
}
public function index()
{
echo("Hello, World!");
}   
}

Firstly, you can see that the controller is a class that extends the base CI_Controller class. Controllers should always extend the base class so that you can use all of CodeIgniter's syntax and have access to all CI resources.
If you have a constructor in your Controller then you need to call upon the CI_Controller constructor, as we have in the example hello Controller.
You should call it as follows:

parent::__construct();

The next thing to note is that there is a function with the name index. This is the default function, and will be called when another function has not been called. To see this being run, simply navigate to the URL http://yourwebsite.ext/index.php/hello/ and you should see the words Hello, World! on the screen.

here, CodeIgniter being my web project folder, thus, the appropriated URL will be the following one: http://localhost/CodeIgniter/index.php/hello


CodeIgniter URLs

CodeIgniter URLs use Uniform Resource Identifiers (URI). In simple terms, CodeIgniter's URLs are simply segments. These segments are then split up andused to load a particular controller and method. Here is a typical CodeIgniter URL:

http://mywebsite/index.php/controller/method/parameters

Everything after the index.php segment is used by CodeIgniter to determine what to load. The first segment is the name of the Controller. The second segment is used to determine which function to load—if this is blank then the index function will be used. The final segment will be used to pass any data to the function.


Defining a default Controller

CodeIgniter has the ability to set a Controller as the default controller. Thisis the controller that is to be called when no other controller is passed toindex.php. A default CodeIgniter install will set the default controller towelcome.php calling the view 'welcome_message'– this is the default CI welcome page.


<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Welcome extends CI_Controller {

/**
* Index Page for this controller.
*
* Maps to the following URL
* http://example.com/index.php/welcome
* - or -  
* http://example.com/index.php/welcome/index
* - or -
* Since this controller is set as the default controller in 
* config/routes.php, it's displayed at http://example.com/
*
* So any other public methods not prefixed with an underscore will
* map to /index.php/welcome/<method_name>
* @see http://codeigniter.com/user_guide/general/urls.html
*/
public function index()
{
$this->load->view('welcome_message');
}
}

Here, you can see that the function $this->load->view is called to access a specific view 'welcome_message', corresponding to the file [codeigniter]/application/views/welcome_message.php

To set a different default controller, open the file application/config/routes.php and change welcome to the name of any other controller in your application.

$route['default_controller'] = "welcome";


Going further with "Hello World" example - introducing views

(The example will be based on that presented at http://12devsofxmas.co.uk/2011/12/codeigniter/, )

As you can see in our previous example, we’ve used this amazingly powerful framework to echo a line of text to the screen and frankly that’s embarrassing so we’d better get onto something vaguely resembling MVC…

Let's create a file called hello.php in the /application/views folder, so we can begin separating our code out nicely, and put this code inside it.

<?php echo $greeting; ?>

And let's change the content of the controller index function by the following code in order to call our view:

//create an array to hold the data we wish to pass to the view

$data = array();

$data['greeting'] = 'Hello world';

//use the load view function to load 'hello.php' and pass the $data array for the view to use 

$this->load->view('hello',$data); 

Now, let's again call http://localhost/codeigniter/index.php/hello and you should see the same output that before, excepted that  the whole point here is we’ve wrapped some data up in an array and passed it to the view ‘hello’ ;


Adding a variable for the name the function becomes : 


public function index($name = 'Alun')

{

    $data['greeting'] = 'Hello '.$name;



    $this->load->view('hello',$data);



}

http://localhost/codeigniter/index.php/hello/smith ; you should see "Hello Smith"


Going still further with "Hello World" example - introducing models

So now we’ve seen a View and a Controller but we’ve not done anything with the Models yet.

Let's create a model "hello_model", within application\models folder by creating a file hello_model.php with the following code :

class hello_model extends CI_Model {

    
    function hello($name, $lang)
    {

        //create an array of "greetings"

        $hello = array();
        $hello['en'] = 'Hello';
        $hello['fr'] = 'Bonjour';
        $hello['de'] = 'Guten Tag';
        $hello['lol'] = 'Oh Hai';

        /* check if a value has been found in the array */
        /* if not default it to 'en' */

        if( ! isset($hello[$lang]))
        {
            $lang = 'en';
        }
        return $hello[$lang]." ".$name;
    }
    
}

And, let's add a new function (action) "greeting" in our "hello" controller :
class hello_model extends CI_Model {

public function greeting($name)
{
           $this->load->model("hello_model"); 
           $data = array();  
           $data['greeting'] = $this->hello_model-> hello($name,$lang);  

           $this->load->view('greeting',$data);
}

Calling the URL http://localhost/CodeIgniter/index.php/hello/greeting/Smith/fr
will then give:

Bonjour Smith


Introducing Database in the model

Next step : that will be the introduction of database query in the model; for that, you will have to define the database access within the config\database.php file and add 'database' in $autoload['libraries'] array within the config\autoload.php file;

Let's create, for example, the following table :
--
-- Table structure for table `greetings`
--

CREATE TABLE `greetings` (
`greetingid` int(11) NOT NULL AUTO_INCREMENT,
`lang` varchar(10) CHARACTER SET utf8 NOT NULL,
`text` varchar(255) CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (`greetingid`)
) ;

--
-- Dumping data for table `greetings`
--

INSERT INTO `greetings` VALUES(1, 'de', 'Guten Tag ');
INSERT INTO `greetings` VALUES(2, 'en', 'Hello');
INSERT INTO `greetings` VALUES(3, 'fr', 'Bonjour');
INSERT INTO `greetings` VALUES(5, 'lol', 'Oh Hai');

The equivalent "hello" function of the previous model will be that one:


function hello($name, $lang){

        $data = array();

        $params = array('lang' => $lang);

        $result = $this-> db-> get_where('greetings', $params, 1);

        if ($result-> num_rows() > 0){

            // $data = $result-> row_array();

            $data =$result->result_array();

            $text = $data[0]['text']

        }
        // var_dump($data);
        $result-> free_result();
        return $text." ".$name;;
    }

Notice that build-in method for database access :

$this-> db-> get_where()

This function is identical to the use of the built-in get() method/function except that it permits you to add a "where" clause in the second parameter, instead of using the db->where() function:

$query = $this->db->get_where('mytable', array('id' => $id), $limit, $offset);

You should read the CodeIgniter documentation related to active record, if you would like deeply andersstanding on database built-in functions, at https://ellislab.com/codeigniter/user-guide/database/active_record.html


Nota : differences between CodeIgniter version 1.7.2 and 2.X.X

I noticed that there are the major differences in the way controllers and models are constructed between version 1.7.2 and version 2.0.0, differences which concerns class constructors.
  • Version 1.7.2
Controllers
class Contact extends Controller {
  function Contact() {
    parent::Controller();
  }
}
Models

class Contact_model extends Model {
  function Contact_model() {
    parent::Model();
  }
}
  • Version 2.0.0

Controllers

class Contact extends CI_Controller {
  function __construct() {
    parent::__construct();
  }
}
Models

class Contact_model extends CI_Model {
  function __construct() {
    parent::__contruct();
  }
}