CodeIgniter, le framework au service des Zéros
Last updated on Monday, January 7, 2013
  • 2 semaines
  • Difficile

Ce cours est visible gratuitement en ligne.

Got it!

Le modèle

Vous avez vu les contrôleurs et les vues. Vous avez vu les helpers et les bibliothèques. Il ne vous manque plus que les modèles !

Dans cette partie, nous utiliserons le pattern Active Record de la classe database pour effectuer nos requêtes.

Anatomie d'un modèle

Tout au long de ce chapitre, nous allons créer un modèle pour la gestion d'un système de news.

Création du modèle

Créez un fichier news_model.php dans votre dossier ./application/models/.
Voici ce que vous allez y placer. Il s'agit d'un modèle basique.

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

class News_model extends CI_Model
{
	public function get_info()
	{
		//	On simule l'envoi d'une requête
		return array('auteur' => 'Chuck Norris',
			     'date' => '24/07/05',
		             'email' => 'email@ndd.fr');
	}
}

Le modèle est donc une classe qui hérite de la classe Model et qui contient des méthodes. Dans le cas où vous voulez implémenter le constructeur, il faut obligatoirement appeler le constructeur parent.
La méthode get_info permet de retourner des données pour réaliser vos tests. Par la suite, nous y effectuerons une vraie requête.

Utiliser le modèle

Avant d'utiliser un modèle depuis un contrôleur, il faut le charger via le contrôleur. Pour cela, vous avez la méthode model de la bibliothèque Load.

<?php

class User extends CI_Controller
{
	public function accueil()
	{
		//	Chargement du modèle de gestion des news
		$this->load->model('news_model');
	}

Le fichier news_model.php étant dans le dossier model, CodeIgniter le trouvera tout seul.

Maintenant que nous avons chargé le modèle, nous allons récupérer les données de la méthode get_info.

<?php
class User extends CI_Controller
{
	public function accueil()
	{
		//	Chargement du modèle de gestion des news
		$this->load->model('news_model');

		$data = array();

		//	On lance une requête
		$data['user_info'] = $this->news_model->get_info();

		//	On inclut une vue
		$this->layout->view('ma_vue', $data);
	}
}

Ainsi, le $this->news_model nous permet d'avoir accès aux méthodes du modèle. En fait, une fois inclus, le modèle agit exactement comme une bibliothèque.

Renommer le modèle

Si vous avez donné des noms trop longs à vos modèles, vous avez la possibilité de les renommer. Pour cela, il faut utiliser le deuxième paramètre de la méthode model.
<?php $this->load->model('nom_du_fichier', 'nom_a_donner');

Voici ce que cela donne avec l'exemple précédent :

<?php

class User extends CI_Controller
{
	public function accueil()
	{
		//	Chargement du modèle de gestion des news
		//	Nous l'appellerons newsManager
		$this->load->model('news_model', 'newsManager');

		$data = array();

		//	On lance une requête
		$data['user_info'] = $this->newsManager->get_info();

		//	Et on inclut une vue
		$this->layout->view('ma_vue', $data);
	}
}

Maintenant, nous ne faisons plus
<?php $this->news_model->get_info();
mais bien
<?php $this->newsManager->get_info();

Vous pourrez penser que c'est un détail mais bien nommer ses modèles permet d'améliorer la lisibilité de votre code. Prenez de bonnes habitudes dès le début.

Nous avons fait le tour de ce qui constitue le modèle. Une fois qu'il est inclus, nous pouvons avoir accès à ses méthodes de la même façon qu'une bibliothèque. Cependant, nous n'avons pas encore eu l'occasion de réaliser de vraies requêtes. La prochaine partie vous permettra de faire vos premiers pas avec la bibliothèque database car nous construirons un modèle pour un système de news.

Le modèle de gestion des news

Notre précédent modèle n'en était pas vraiment un car nous ne lui avons pas fait effectuer de requêtes. Nous nous sommes contentés de lui faire retourner un tableau pour faciliter l'écriture de la méthode. Maintenant, nous allons créer le modèle pour la gestion d'un système de news.

Voici la table :

Image utilisateur

Le code SQL :

CREATE TABLE `news` (
	`id`		SMALLINT(5)	UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`auteur`	VARCHAR(30)	NOT NULL,
	`titre`		VARCHAR(100)	NOT NULL,
	`contenu`	TEXT		NOT NULL,
	`date_ajout`	DATETIME	NOT NULL,
	`date_modif`	DATETIME	NOT NULL
)

ENGINE = MyISAM DEFAULT CHARSET = utf8;

Et le prototype du modèle :

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

class News_model extends CI_Model
{
	protected $table = 'news';
	
	/**
	 *	Ajoute une news
	 */
	public function ajouter_news()
	{
		
	}
	
	/**
	 *	Édite une news déjà existante
	 */
	public function editer_news()
	{
		
	}
	
	/**
	 *	Supprime une news
	 */
	public function supprimer_news()
	{
		
	}
	
	/**
	 *	Retourne le nombre de news
	 */
	public function count()
	{
		
	}
	
	/**
	 *	Retourne une liste de news
	 */
	public function liste_news()
	{
		
	}
}


/* End of file news_model.php */
/* Location: ./application/models/news_model.php */

Le point sur Active Record

CodeIgniter vous propose deux manières de lancer des requêtes à la base de données : en l'écrivant en langage SQL ou en utilisant Active Record.

Active Record est un patron sur lequel on peut s'appuyer pour faire nos requêtes. Il s'utilise en trois étapes :

  • création de la requête avec les méthodes de la classe Database ;

  • exécution de la requête ;

  • manipulation des données que la base de données a renvoyées.

Dans la suite de ce tutoriel, j'utiliserai autant que possible Active Record. Maintenant, nous allons implémenter chaque méthode du modèle une par une.

Méthode ajouter_news

Cette méthode permet d'ajouter une news. Ainsi, les champs id, date_ajout et date_modif devront être gérés par la méthode. Celle-ci a besoin de 3 paramètres : l'auteur, le titre et le contenu.

<?php

	/**
	 *	Ajoute une news
	 *
	 *	@param string $auteur 	L'auteur de la news
	 *	@param string $titre 	Le titre de la news
	 *	@param string $contenu 	Le contenu de la news
	 *	@return bool		Le résultat de la requête
	 */
	public function ajouter_news($auteur, $titre, $contenu)
	{
		
	}

Pour ajouter un nouvel élément dans la base de données, nous pouvons utiliser la méthode insert. Nous allons passer le nom de la table au premier paramètre. Ensuite, nous pouvons utiliser le deuxième paramètre pour les données (sous forme d'un tableau associatif) ou bien nous pouvons utiliser la méthode set pour remplir champ par champ les données à insérer.

Nous utiliserons les méthodes set + insert car elles permettent de mieux contrôler l'insertion de données.

Voici le prototype de la méthode set.
<?php $this->set ( $nom_du_champ, $valeur, $echappement_automatique = true )

<?php

	/**
	 *	Ajoute une news
	 *
	 *	@param string $auteur 	L'auteur de la news
	 *	@param string $titre 	Le titre de la news
	 *	@param string $contenu 	Le contenu de la news
	 *	@return bool		Le résultat de la requête
	 */
	public function ajouter_news($auteur, $titre, $contenu)
	{
		//	Ces données seront automatiquement échappées
		$this->db->set('auteur',  $auteur);
		$this->db->set('titre',   $titre);
		$this->db->set('contenu', $contenu);
		
		//	Ces données ne seront pas échappées
		$this->db->set('date_ajout', 'NOW()', false);
		$this->db->set('date_modif', 'NOW()', false);
		
		//	Une fois que tous les champs ont bien été définis, on "insert" le tout
		return $this->db->insert($this->table);
	}

Cette technique est particulièrement intéressante car elle nous permet de fixer les valeurs champ par champ. Une fois que nous avons fini, nous utilisons la méthode insert en fournissant le nom de la table. Vous remarquerez que le troisième paramètre de la méthode set permet d'empêcher l'échappement des données. En effet, la chaîne de caractères NOW() ne doit pas être insérée en tant que telle mais elle doit être interprétée.

Cette méthode pourra être appelée de cette façon depuis un contrôleur :

<?php

public function accueil()
{
	$this->load->model('news_model', 'newsManager');

	$resultat = $this->newsManager->ajouter_news('Arthur',
						     'Un super titre',
						     'Un super contenu !');
	var_dump($resultat);
}

Vous pouvez aussi chaîner votre requête de cette façon :

<?php

public function ajouter_news($auteur, $titre, $contenu)
{
	return $this->db->set('auteur',	 $auteur)
			->set('titre', 	 $titre)
			->set('contenu', $contenu)
			->set('date_ajout', 'NOW()', false)
			->set('date_modif', 'NOW()', false)
			->insert($this->table);
}

Comme vous le voyez, nous avons réalisé une requête sans utiliser le langage SQL, uniquement avec des méthodes de la classe Database.

Méthode modifier_news

Pour cette méthode, nous allons procéder de la même manière qu'avec la méthode ajouter_news, sauf que nous n'appellerons pas en dernier la méthode insert mais la méthode update. De plus, il nous faudra appeler une autre méthode avant update afin de renseigner la condition pour mettre à jour le champ, ce sera la méthode where.

Comme c'est la première fois que nous modifions des données de la sorte, je commence par le code et je vous expliquerai après.

<?php

/**
 *	Édite une news déjà existante
 *	
 *	@param integer $id	L'id de la news à modifier
 *	@param string  $titre 	Le titre de la news
 *	@param string  $contenu Le contenu de la news
 *	@return bool		Le résultat de la requête
 */
public function editer_news($id, $titre = null, $contenu = null)
{
	//	Il n'y a rien à éditer
	if($titre == null AND $contenu == null)
	{
		return false;
	}
	
	//	Ces données seront échappées
	if($titre != null)
	{
		$this->db->set('titre', $titre);
	}
	if($contenu != null)
	{
		$this->db->set('contenu', $contenu);
	}
	
	//	Ces données ne seront pas échappées
	$this->db->set('date_modif', 'NOW()', false);
	
	//	La condition
	$this->db->where('id', (int) $id);
	
	return $this->db->update($this->table);
}

Dans un premier temps, nous mettons à jour les deux champs que nous souhaitons modifier. Si l'un des deux a pour valeur null, alors il sera ignoré.
Puis nous complétons la date et l'heure de la mise à jour.
Ensuite, il faut lui dire quelles sont les entrées que nous souhaitons modifier. Ici, nous avons choisi d'autoriser la modification uniquement par le champ id. Cela se fait par la méthode where. Si nous ne lui disons pas quels sont les champs que nous souhaitons modifier, alors nous modifierons toutes les entrées que possède la table.
Puis en dernier, nous lançons la méthode update pour exécuter la requête en lui donnant en paramètre le nom de la table.

Vous pouvez rendre cette méthode plus flexible en autorisant la modification de la news par un autre champ que id. En effet, la méthode where peut aussi recevoir un tableau associatif du type : nom_du_champ => valeur.
Ainsi, vous pouvez créer une condition : « si $id est un tableau, alors ce tableau sera donné à la méthode where sans spécifier de champ ».

Nous l'implémenterons comme cela :

<?php

//	Exemple de valeur pour $id.
$id = 5;
$id = array('id' => 9);
$id = array('pseudo' => 'Arthur',
            'titre' => 'monTitre');

/* ******* */

if(is_array($id))
{
	$this->db->where($id);
}
else
{
	$this->db->where('id', (int) $id);
}

En utilisant des méthodes pour générer vos requêtes, ce genre de chose est très facile à faire.

Méthode supprimer_news

Cette méthode n'aura qu'un seul paramètre : l'id de la news à supprimer. Pour la suppression d'entrées, nous utiliserons la méthode delete. Nous l'utiliserons une fois la condition where définie.

<?php

/**
 *	Supprime une news
 *	
 *	@param integer $id	L'id de la news à modifier
 *	@return bool		Le résultat de la requête
 */
public function supprimer_news($id)
{
	return $this->db->where('id', (int) $id)
			->delete($this->table);
}

Méthode count

Pour les méthodes permettant de retourner le nombre d'entrées, la bibliothèque database nous propose une méthode toute prête : count_all_results.

Pour l'utiliser, il faut dans un premier temps recourir à la méthode where pour restreindre le nombre de résultats retournés, puis à la méthode count_all_results pour exécuter la requête.

<?php

/**
 *	Retourne le nombre de news.
 *	
 *	@param array $where	Tableau associatif permettant de définir des conditions
 *	@return integer		Le nombre de news satisfaisant la condition
 */
public function count($where = array())
{
	return (int) $this->db->where($where)
			      ->count_all_results($this->table);
}

Voici un exemple d'utilisation de cette méthode :

<?php

public function accueil()
{
	$this->load->model('news_model', 'newsManager');

	$nb_news = $this->newsManager->count();
	$nb_news_de_bob = $this->newsManager->count(array('auteur' => 'Bob'));
}

Dans le premier cas, comme nous n'avons pas défini de paramètre, nous avons envoyé à la méthode where un tableau vide. Cela équivaut à retourner le nombre total d'entrées.
Dans le deuxième cas, le tableau que nous donnons en paramètre permet d'affiner la requête et de ne retourner que le nombre d'entrées où le champ « auteur » vaut « Bob ».

Méthode liste_news

Les requêtes permettant de sélectionner un ensemble d'entrées fonctionnent de la même manière que les requêtes sous forme de chaînes de caractères.

  • Il y a une méthode select pour réduire la taille des données récupérées. Sa valeur par défaut est * qui permet de récupérer tous les champs.

  • Il y a une méthode from qui permet de spécifier la table souhaitée.

  • Il y a une méthode join pour faire des jointures.

  • Il y a des méthodes conditionnelles. Nous avons vu where, mais il y en a d'autres (or_where, like, or_like, etc.).

  • Il existe aussi d'autres méthodes telles que limit ou order_by, qui ont les mêmes utilités que dans le langage SQL.

Il en existe beaucoup d'autres mais vous avez remarqué que les noms des méthodes sont les mêmes (ou presque) que les mots-clés du langage SQL.

Intéressons-nous à présent à l'implémentation de la méthode :

<?php

/**
 *	Retourne une liste de $nb dernières news.
 *	
 *	@param integer $nb	Le nombre de news
 *	@param integer $debut	Nombre de news à sauter
 *	@return objet		La liste de news
 */
public function liste_news($nb = 10, $debut = 0)
{
	return $this->db->select('*')
			->from($this->table)
			->limit($nb, $debut)
			->order_by('id', 'desc')
			->get()
			->result();
}

Cette requête se lit comme cela : « Sélectionne tous les champs de la table $this->table, donne-moi $nb news à partir de la news $debut et ordonne le tout du plus grand id au plus petit.

Notre modèle de news

Voici le modèle de news que nous avons réalisé :

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

/**
 *	News_model
 *
 *		ajouter_news($auteur, $titre, $contenu)
 *		editer_news($id, $titre = null, $contenu = null)
 *		supprimer_news($id)
 *		count($where = array())
 *		liste_news($nb = 10, $debut = 0)
 */

class News_model extends CI_Model
{
	protected $table = 'news';

	/**
	 *	Ajoute une news.
	 *
	 *	@param string $auteur 	L'auteur de la news
	 *	@param string $titre 	Le titre de la news
	 *	@param string $contenu 	Le contenu de la news
	 *	@return bool		Le résultat de la requête
	 */
	public function ajouter_news($auteur, $titre, $contenu)
	{
		return $this->db->set('auteur',	$auteur)
			        ->set('titre', 	$titre)
				->set('contenu',	$contenu)
				->set('date_ajout', 'NOW()', false)
				->set('date_modif', 'NOW()', false)
				->insert($this->table);
	}
	
	/**
	 *	Édite une news déjà existante.
	 *	
	 *	@param integer $id	L'id de la news à modifier
	 *	@param string  $titre 	Le titre de la news
	 *	@param string  $contenu Le contenu de la news
	 *	@return bool		Le résultat de la requête
	 */
	public function editer_news($id, $titre = null, $contenu = null)
	{
		//	Il n'y a rien à éditer
		if($titre == null AND $contenu == null)
		{
			return false;
		}
		
		//	Ces données seront échappées
		if($titre != null)
		{
			$this->db->set('titre', $titre);
		}
		if($contenu != null)
		{
			$this->db->set('contenu', $contenu);
		}
		
		return $this->db->set('date_modif', 'NOW()', false)
				->where('id', (int) $id)
				->update($this->table);
	}
	
	/**
	 *	Supprime une news.
	 *	
	 *	@param integer $id	L'id de la news à modifier
	 *	@return bool		Le résultat de la requête
	 */
	public function supprimer_news($id)
	{
		return $this->db->where('id', (int) $id)
				->delete($this->table);
	}
	
	/**
	 *	Retourne le nombre de news.
	 *	
	 *	@param array $where	Tableau associatif permettant de définir des conditions
	 *	@return integer		Le nombre de news satisfaisant la condition
	 */
	public function count($where = array())
	{
		return (int) $this->db->where($where)
				      ->count_all_results($this->table);
	}
	
	/**
	 *	Retourne une liste de $nb dernière news.
	 *	
	 *	@param integer $nb	Le nombre de news
	 *	@param integer $debut	Nombre de news à sauter
	 *	@return objet		La liste de news
	 */
	public function liste_news($nb = 10, $debut = 0)
	{
		return $this->db->select('*')
				->from($this->table)
				->limit($nb, $debut)
				->order_by('id', 'desc')
				->get()
				->result();
	}
}


/* End of file news_model.php */
/* Location: ./application/models/news_model.php */

La réalisation de ce modèle vous permettra de comprendre bien plus facilement la documentation sur la bibliothèque database, et plus particulièrement le pattern Active Record.

Désormais, vous en savez suffisamment sur CodeIgniter pour construire un site web. Vous ne connaissez pas tout de ce framework. Je ne vais pas vous lâcher comme cela, bien entendu. Mais si vous avez bien compris tout ce que nous avons vu dans ces deux parties, vous êtes en mesure de réaliser un bon nombre de sites.

Example of certificate of achievement
Example of certificate of achievement