Revenir
en haut

Aide de vue Mkurl : simplifier l’assemblage des urls

29/10/2010 0

Un billet très court pour vous proposer une alternative à l’aide de vue url livrée avec Zend Framework.

Utiliser PHP comme moteur de template est une bonne chose mais implique une légère complexité du code dans les vues. Du $this, du escape, des array et j’en passe, certains morceaux de code deviennent très pénibles à lire et polluent le html.

Aujourd’hui nous nous intéressons à l’aide de vue url, dont la syntaxe est :

$this->url(array(
    'module' => 'mon-module',
    'controller' => 'mon-controller',
    'action' => 'mon-action',
    'param1' => 'val1',
    'param2' => 'val2'
), 'ma-route', true);

Ce qui intégré donne :

<a href="<?=$this->url(array(
    'module' => 'mon-module',
    'controller' => 'mon-controller',
    'action' => 'mon-action',
    'param1' => 'val1',
    'param2' => 'val2'
), 'ma-route', true)?>" title="">Le lien de la mort</a>

Je pense que ça se passe de commentaires, tout ça devient très vite un véritable foutoir.

La syntaxe avec les routes et les paramètres par défaut peut être raccourcie :

<a href="<?=$this->url(array(
    'param1' => 'val1',
    'param2' => 'val2'
), 'ma-route', true)?>" title="">Le lien de la mort moins violente</a>

Mais ce n’est pas encore idéal.

Utiliser un pattern pour composer les URLs

Je vous propose une aide de vue qui va générer les URLs en fonction d’un pattern inspiré de l’aide de symfony premier du nom et qui permet de transformer les exemples ci-dessus en :

<a href="<?=$this->mkurl('mon-module/mon-controller/mon-action?param1=val1&param2=val2', true)?>" title="">Le lien moins mortel</a>

<a href="<?=$this->mkurl('@ma-route?param1=val1&param2=val2', true)?>" title="">Le lien encore moins mortel</a>

Pour ce qui est du code, j’avoue ne pas avoir regardé la source dans symfony 1.x qui est peut-être meilleure, mais voilà le code :

<?php
/** Zend_View_Helper_Abstract.php */
require_once 'Zend/View/Helper/Abstract.php';

/**
 * Helper for making easy links and getting urls that depend on the routes and router
 *
 * @package    Tight_View
 * @subpackage Helper
 * @author     Benjamin Dulau
 */

class Tight_View_Helper_Mkurl extends Zend_View_Helper_Abstract
{
    /**
     * Generates an url from a string pattern
     *
     * @access public
     *
     * @param  array $urlPattern String pattern for url
     * @param  bool  $reset      Whether or not to reset the route defaults with those provided
     * @param  bool  $encode     Whether or not to encode the url
     * @return string Url for the link href attribute.
     */

    public function mkurl($urlPattern, $reset = false, $encode = true)
    {
        $module = null;
        $controller = null;
        $action = null;
        $routeName = 'default';

        $urlParts = explode('?', $urlPattern);
        $route = (string)$urlParts[0];
        $queryString = (isset($urlParts[1])) ? $urlParts[1] : array();

        // if starts with @ => route name
        if (!empty($route) && $route[0] == '@') {
            $routeName = mb_substr($route, 1);
        } else { // else standard ":module/:controller/:action" fragments
            $mca = explode('/', $route);
           
            // shift starting '/' if present
            if (empty($mca[0])) {
                array_shift($mca);
            }            
           
            switch(count($mca)) {
                case 3:
                    // :module/:controller/:action
                    $module = $mca[0];
                    $controller = $mca[1];
                    $action = $mca[2];
                break;

                case 2:
                    // :controller/:action
                    $controller = $mca[0];
                    $action = $mca[1];
                break;

                case 1:
                    // :controller/index
                    $controller = $mca[0];
                    $action = 'index';
                break;

                default:
                    throw new InvalidArgumentException(sprintf('Mkurl helper => Invalid URL pattern. The URL pattern must be formatted like as :module/:controller/:action?params, :controller/:action?params, or :controller?params ("%s" given).', $urlPattern));
                break;
            }            
        }

        $urlOptions = array();
        if (!empty($module)) {
            $urlOptions['module'] = $module;
        }
        if (!empty($controller)) {
            $urlOptions['controller'] = $controller;
        }
        if (!empty($action)) {
            $urlOptions['action'] = $action;
        }        

        if (!empty($queryString)) {
            $matched = preg_match_all('@([^&=]+)=(.*?)(?:(?=&[^&=]+=) | $)@x', $queryString, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
            foreach ($matches as $match) {
                $urlOptions[ urldecode($match[1][0]) ] = urldecode($match[2][0]);
            }
        }

        $router = Zend_Controller_Front::getInstance()->getRouter();
        return $router->assemble($urlOptions, $routeName, $reset, $encode);
    }
}

Ce fichier est à placer dans votre dossier « library » (ou autre nom), et vous devez ajouter le namespace dans le fichier de config. application.ini :

resources.view.helperPath.Tight_View_Helper_ = "Tight/View/Helper"

Rien ne vous empêche de l’améliorer si nécessaire (même dans les commentaires :p).

Utilisation

URLs « standards »

Comme vous pouvez le voir dans le code, j’ai décidé de 3 cas d’utilisation :

/:module/:controller/:action/*

<a href="<?=$this->mkurl('/mon-module/mon-controleur/mon-action?param1=val1')?>" title="Mon super lien">
    Super lien
</a>

/:controller/:action/*

<a href="<?=$this->mkurl('/mon-controleur/mon-action?param1=val1')?>" title="Mon super lien">
    Super lien
</a>

Le module par défaut sera utilisé.

/:controller/*

<a href="<?=$this->mkurl('/mon-controleur?param1=val1')?>" title="Mon super lien">
    Super lien
</a>

Le module par défaut et l’action index seront utilisés.

Avec une route

Imaginons la route suivante :

resources.router.routes.photos.route = "/photos/:s/:t"
resources.router.routes.photos.defaults.module = front
resources.router.routes.photos.defaults.controller = photos
resources.router.routes.photos.defaults.action = index
resources.router.routes.photos.defaults.s = last
resources.router.routes.photos.defaults.t = all-period
resources.router.routes.photos.reqs.s = "^(last|most-popular|most-viewed|top-rated|most-commented)$"
resources.router.routes.photos.reqs.t = "^(all-period|today|week|month)$"

Pour obtenir la route par défaut, tout simplement :

<a href="<?=$this->mkurl('@photos')?>" title="Voir toutes les photos">
    Toutes les photos
</a>

Avec des paramètres :

<a href="<?=$this->mkurl('@photos?s=most-popular&t=today')?>" title="Voir les photos les plus populaires aujourd'hui">
    Les plus populaires - aujourd'hui
</a>

Il est possible aussi (heureusement) de pouvoir redéfinir les module/action/contrôleur :

<a href="<?=$this->mkurl('@photos?action=mon-action&s=most-popular&t=today')?>" title="Voir les photos les plus populaires aujourd'hui">
    Les plus populaires - aujourd'hui
</a>

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.

*

Tags HTML autorisés : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Tag code : [cc lang="langage"][/cc] (ex. [cc lang="php"][/cc])