Laravel 4

Laravel 4 : chapitre 9 : Les contrôleurs

Nous avons vu que nous pouvons nous contenter de routes et de vues pour créer un site. C’est parfait tant qu’on doit faire des choses simples mais avec une application un peu lourde on peut se retrouver avec beaucoup de code dans le fichier des routes, ce qui n’est pas très judicieux. Une autre option consiste à créer des contrôleurs (schéma MVC). Cette solution permet aussi l’injection automatique de dépendances comme nous le verrons plus tard.

Créer un contrôleur

Si vous regardez dans le dossier app/controllers vous trouvez le fichier HomeController.php :

class HomeController extends BaseController {
/*
|--------------------------------------------------------------------------
| Default Home Controller
|--------------------------------------------------------------------------
|
| You may wish to use controllers instead of, or in addition to, Closure
| based routes. That's great! Here is an example controller method to
| get you started. To route to this controller, just add the route:
|
|    Route::get('/', 'HomeController@showWelcome');
|
*/

public function showWelcome()
{
    return View::make('hello');
}

}

On vous explique que c’est un exemple pour réaliser vos propres contrôleurs. La syntaxe est simple : on crée une classe qui hérite de BaseController. Notez que le nom de la classe, conformément au PSR-1 adopte le principe du StudlyCaps,  c’est à dire que chaque mot commence par une majuscule, y compris le premier (contrairement au camelCase). Le fichier de cette classe se trouve dans le même dossier app/controllers/BaseController.php :

class BaseController extends Controller {

    /**
     * Setup the layout used by the controller.
     *
     * @return void
     */
    protected function setupLayout()
    {
        if ( ! is_null($this->layout))
        {
            $this->layout = View::make($this->layout);
        }
    }

}

Cette classe hérite de la classe Controller qui est la classe générique de Laravel pour les contrôleurs. Vous pouvez donc placer ici du code qui concerne tous vos contrôleurs. Il y a d’ailleurs déjà une méthode pour générer un template. Nous allons pour le moment laisser de côté la classe BaseController et voir comment on active un contrôleur avec une route. Puisqu’on a déjà un contrôleur on va l’utiliser. En plus on nous explique gentiment dans le commentaire comment on doit faire Smile. Entrez donc ce code dans le fichier des routes :

Route::get('/', 'HomeController@showWelcome');

Si vous n’avez pas supprimé le fichier app/views/hello.php vous devez obtenir cet affichage :

img30Si vous l’avez supprimé il suffit de le recréer avec ce code :

<h1>Hello World!</h1>

Avec ce que nous avons vu jusqu’à présent l’utilisation de contrôleur n’apporte pas grand chose si ce n’est d’organiser le code différemment. Au lieu de le mettre directement dans la route on le déporte dans le contrôleur. Tout cela prendra son sens avec des fonctionnalités plus avancées que nous verrons ultérieurement.

Un contrôleur « RESTful »

Vous pouvez avec Laravel créer un contrôleur qui réponde aux conventions de nommage de la norme REST. Voyons un exemple simple de contrôleur :

class GuestController extends BaseController {

    /**
	* Affiche le formulaire de login
	*
	* @return View
	*/
	public function getLogin()
	{
            //  ...
	}

    /**
	* Traitement du formulaire de login
	*
	* @return Redirect
	*/
	public function postLogin()
	{
             //  ...    
	}
}

On a deux actions login, une avec la méthode GET et l’autre la méthode POST. Au niveau des routes on se contente de cette ligne de code :

Route::controller('guest', 'GuestController');

Avec l’URL http://localhost/blog/public/guest/login on active l’action login qui correspond à la méthode getLogin. Avec la même URL mais la méthode POST on active l’action login qui correspond à la méthode postLogin. Il suffit donc de bien préfixer les action avec get et post. Je montrerai un exemple complet d’application dans un article ultérieur.

Créer un contrôleur de ressource avec artisan

Laravel possède un outil en ligne nommé artisan. Il permet de faire bien des choses. Pour vous en rendre compte entrez php artisan en ligne de commande :

img11

Vous pouvez voir qu’il y a pas mal de commandes disponibles. Nous allons nous intéresser pour le moment à la commande controller:make qui sert justement à créer un contrôleur. Voyons les options de cette commande :

img12

Nous allons commencer par une création simple :

img33On nous dit que le contrôleur a été créé, nous le trouvons effectivement dans app/controllers/mon_controleur.php :

<?php

class mon_controleur extends BaseController {

/**
* Display a listing of the resource.
*
* @return Response
*/
public function index()
{
//
}

/**
* Show the form for creating a new resource.
*
* @return Response
*/
public function create()
{
//
}

/**
* Store a newly created resource in storage.
*
* @return Response
*/
public function store()
{
//
}

/**
* Display the specified resource.
*
* @return Response
*/
public function show($id)
{
//
}

/**
* Show the form for editing the specified resource.
*
* @return Response
*/
public function edit($id)
{
//
}

/**
* Update the specified resource in storage.
*
* @return Response
*/
public function update($id)
{
//
}

/**
* Remove the specified resource from storage.
*
* @return Response
*/
public function destroy($id)
{
//
}

}

Laravel se conforme à l’architecture RESTful ce qui explique la présence de toutes ces méthodes. Pour clarifier un peu tout ça voilà le code modifié avec un retour évocateur  :

<?php

class mon_controleur extends BaseController {

	public function index()
	{
		return "Réponse de base";
	}

	// GET /ma_ressource/create
	public function create()
	{
		return "La ressource doit être créée ici";
	}

	// POST /ma_ressource
	public function store()
	{
		return "Ressource mémorisée";
	}

	// GET /ma_ressource/{id}
	public function show($id)
	{
		return "C'est ici qu'on montre la ressource ".$id;
	}

	// GET /ma_ressource/{id}/edit
	public function edit($id)
	{
		return "C'est ici qu'on modifie la ressource ".$id;
	}

	// PUT /ma_ressource/{id}
	public function update($id)
	{
		return "C'est ici qu'on met à jour la ressource ".$id;
	}

	// DELETE /ma_ressource/{id}
	public function destroy($id)
	{
		return "C'est ici qu'on supprime la ressource ".$id;
	}

}

On va aussi déclarer la ressource dans le fichier des routes, ce qui va avoir pour effet de créer toutes les routes correspondant à cette ressource avec une seule ligne de code :

Route::resource('ma_ressource', 'mon_controleur');

En réponse à http://localhost/laravel/public/ma_ressource j’obtiens donc :

Réponse de base

En réponse à http://localhost/laravel/public/ma_ressource/toto j’obtiens donc :

C’est ici qu’on montre la ressource toto

En réponse à http://localhost/laravel/public/ma_ressource/toto/edit j’obtiens donc :

C’est ici qu’on modifie la ressource toto

Pour les autres commandes il faut un peu plus d’intendance puisqu’on a les verbes POST, PUT et DELETE.

Par exemple pour l’enregistrement d’une ressource créez ce formulaire :

<form action="ma_ressource" method="post">
    <input name="Valider" type="submit">
</form>

Quand vous cliquez sur le bouton vous devez obtenir :

Ressource mémorisée

Pour ce qui concerne les méthode PUT et DELETE la mise en œuvre est un peu plus délicate.

Si vous ne voulez pas toutes les fonctionnalités vous pouvez créer un contrôleur limité à vos besoins. La commande d’artisan comprend les options –only et –except. Mais il faut aussi le signaler dans l’appel de la ressource. Par exemple si vous ne voulez que show et edit :

Route::resource('ma_ressource', 'mon_controleur',
array('only' => array('show', 'edit')));

Vous avez donc la possibilité d’utiliser ce type de contrôleur dans vos applications si vous voulez coller à l’architecture REST ou tout simplement partir sur une base cohérente.

Je donne un exemple complet d’une ressource avec un générateur dans un article ultérieur.

Print Friendly, PDF & Email

12 commentaires

  • sassy

    En lisant mieux , je constate que je me suis trompé dans la déclaration du route:
    Route::ressource(‘ma_ressource’,’MonControleur’); c’est plus correct.
    Et le problème se déplace lui aussi :
    Call to undefined method Illuminate\Routing\Router::ressource()

  • sassy

    Panique à bord,
    Arrivé au niveau des contrôleurs, j’ai suivi à la lettre le tuto et là message d’erreur coup sur coup. Et pas des plus simples. A l’adresse : http://localhost:8000/maRessource
    Laravel répond :
    14. ErrorException …/­bootstrap/­compiled.php 4769
    ErrorException
    Undefined offset: 1
    open: /Users/…/Sites/site1/laravel/bootstrap/compiled.php
    }
    protected function getClassClosure($controller)
    {
    $d = $this->getControllerDispatcher();
    return function () use($d, $controller) {
    $route = $this->current();
    $request = $this->getCurrentRequest();
    list($class, $method) = explode(‘@’, $controller);
    return $d->dispatch($route, $request, $class, $method);
    };
    Que faire .?
    Ceci n’était pas du aux _ et autres. Non pour résoudre le problème, il faut que dans ma déclaration Route, j’indique par exemple:
    Route::get(‘maRessource’,’MonControleur@index’);
    Si quelqu’un à une idée, je suis preneur.
    Merci

  • beesofts

    « On nous dit que le contrôleur a été créé, nous le trouvons effectivement dans app/controllers/mon_controleur_php » ; ce serait plutôt app/controllers/mon_controleur.php. J’ai aussi rencontré un problème dû au caractère _. Comme tu l’as dis toi-même ce n’était pas très judicieux de l’utiliser, et il faudrait peut-être ajouter une note dans ton tuto, ça m’aurait éviter de chercher, de trouver une réponse, et de constater qu’en fait la solution se trouvait déjà dans les commentaires 🙂
    De plus au lieu de ‘return « Ressource créée »;’, j’aurai plutôt indiqué ‘return « C’est ici qu’on crée une ressource »;’

  • Juli3nG

    Bonjour, je rencontre un problème de conception…
    J’ai besoin d’avoir une page qui comporte un formulaire de filtres ainsi qu’un graphique généré après la validation du formulaire de filtres.
    Je suis parti sur un controller resource avec comme seule fonction « index », car il ne sera pas possible de modifier, supprimer, enregistrer le model que je veux exploiter.

    J’ai deux principaux problèmes, le premier est que mon model n’est pas à proprement parler une « entité », j’ai une table pleine de données dont je dois extraire des délais avec des GROUP BY, etc… Ces délais seront ensuite rendus sous forme de colonnes dans mon graphique. Comment faire pour créer un model « Délais » ?
    Mon deuxième soucis est que cette resource sera uniquement affichable et filtrable. Du point de vue controler resource, comment je dois gérer ma page template contenant le formulaire de filtre et mon graphique ?

    Je suis parti sur ça :


    class DelaisController extends \BaseController {

    /**
    * Display a listing of the resource.
    *
    * @return Response
    */
    public function index()
    {
    //Récupération de tous les délais depuis mon MODEL

    //Récupération des paramètres
    $parameters = Input::query();
    //Si des paramètres sont présents
    if(!empty($parameters)){
    //Validation des paramètres
    //Filtrer les délais par rapport aux paramètres reçus
    }
    //Si la demande vient d'une requête AJAX
    if(Request::ajax()){
    //JSON des délais pour transmission à la librairie JS Highcharts
    } else{
    $data = array(
    //Titre de la page
    'title' => 'Délais',
    //Sous-titre de la page
    'subtitle' => 'Processus pré, per et post-analytique',
    //Message informatif ou de retour
    'msg' => Form::msgInfo("Ce formulaire est en version beta."),
    //Population des différents champs du formulaire de filtre (pour le moment avec des données de test, plus tard avec des models)
    'jours' => array('1'=>'Lundi', '2'=>'Mardi', '3'=>'Mercredi', '4'=>'Jeudi', '5'=>'Vendredi', '6'=>'Samedi', '7'=>'Dimanche'),
    'instances' => array(''=>'', '1'=>'Lundi', '2'=>'Mardi', '3'=>'Mercredi', '4'=>'Jeudi', '5'=>'Vendredi', '6'=>'Samedi', '7'=>'Dimanche'),
    'sites' => array('1'=>'Lundi', '2'=>'Mardi', '3'=>'Mercredi', '4'=>'Jeudi', '5'=>'Vendredi', '6'=>'Samedi', '7'=>'Dimanche'),
    'correspondants' => array('1'=>'Lundi', '2'=>'Mardi', '3'=>'Mercredi', '4'=>'Jeudi', '5'=>'Vendredi', '6'=>'Samedi', '7'=>'Dimanche'),
    'delais' => //JSON des délais pour transmission à la librairie JS Highcharts
    );
    return View::make('benchmark.delais')->with($data);
    }
    }
    }

    Je ne dois pas être très clair… C’est assez compliqué à expliquer je trouve.

    • bestmomo

      Salut,

      Je ne suis pas sûr d’avoir tout compris mais déjà pourquoi créer un contrôleur de ressource si tu utilises que l’index ? Par contre tu pourrais utiliser un contrôleur RESTful pour gérer ton application.

      Puisque tu as une table tu as un modèle qui correspond à cette table avec lequel tu fais tes requêtes et tu peux envoyer directement le résultat à ta vue. Tu n’as pas besoin d’un autre modèle.

      Tu traites le retour du formulaire dans une méthode postXXX de ton contrôleur. Tu relances ta requête et renvoies le résultat selon les filtres à ta vue.

      Je pense que ma réponse doit être aussi claire que ta question 🙂 .

  • Frink

    Bonjour,

    Petit commentaire par rapport au nom du contrôleur généré avec artisan.

    Chez moi class mon_controleur extends BaseController génère une erreur (avec les urls de test). Laravel me dit qu’il ne trouve pas la classe en question (mon_controleur).

    En remplacant ‘mon_controleur’ par ‘MonControleur’ (dans la classe, dans son nom de fichier et dans le fichier routes.php, of course) , plus de message d’erreur.

    Est-ce en rapport aux conventions de nommage ou est-ce que j’ai encore fait une erreur mystique de newbie avec ‘mon_controleur’? J’en sais rien.

    En tout ça, je tenais à le signaler, au cas où ça pourrait aider quelqu’un 🙂

    Merci encore pour cette série de tuto de très bonne qualité!

    Frink

    • bestmomo

      Ce n’est pas très judicieux de ma part de n’avoir pas respecté la convention de nommage du PSR-1, mais ça doit fonctionner avec n’importe quel nom, il faut juste faire un composer dumpautoload pour enregistrer la classe.

      • christoff

        Bonjour,
        Petite précision pour les néophytes et linuxiens comme moi, il faut taper dans la console :

        php ../composer.phar dump-autoload

        Si on est positionné dans le répertoire laravel et que composer.phar est en amont du répertoire.

Laisser un commentaire