Les routes propres - Zend Framework 1.12 partie 7

Tutorial Application Facebook PHP/JS : les routes propres.

Publié le 02/10/2013

Liste des tâches :

  • - Paramétrage de la route dans le fichier application.ini
  • - Mise en place d’un réquete dans le model
  • - Construction de la route dans la vue
  • - Récupération du GET dans le controller
  • - Ajout d’une class de traitement clean url

Dans le cas de cette application et dans le cas de la rubrique portfolio, nous souhaitons avoir des routes propres les url des articles de nos rubrique en substituant l’id de l’article dans l’url par le champ id_propre de la table realisations de la bdd.

1 - Paramétrage de la route dans le fichier application.ini

Nous allons ajouter dans le fichier "APPLICATION_PATH"/application/config/application.ini, les lignes suivantes :


resources.router.routes.portfolio-article.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.portfolio-article.route = "fiche-portfolio-(.+)"
resources.router.routes.portfolio-article.defaults.controller = "portfolio"
resources.router.routes.portfolio-article.defaults.action = "index"
resources.router.routes.portfolio-article.map.1 = "id_propre"
resources.router.routes.portfolio-article.reverse = "fiche-portfolio-%s"

2 - Mise en place d’un réquete dans le model

Dans notre model "APPLICATION_PATH"/library/Next/Model/Realisation.php, ajouter la méthode suivante qui nous permettra d’aller chercher les informations de la réalisation dans la base :


// get selected realisation and linked document using id_propre
static function getRealisationPortfolioByIdPropre($id_propre)
{
    $q = Doctrine_Query::create()
        ->from('Next_Model_Realisations r')
        ->leftJoin('r.Next_Model_Documents d')
        ->where('r.id_propre = ?', $id_propre)
        ->andWhere('r.status = 1');

    $result = $q->fetchArray();
    return $result;
}

3 - Construction de la route dans la vue

Nous allons construire la route dans la vue qui va nous permettre d’atteindre l’article voulu en fonction de l’id_propre passé en paramètre. Pour cela nous allons ouvrir le fichier de vue "APPLICATION_PATH"/application/modules/default/views/scripts/index/index.phtml et inserer la route dans les href de nos liens.

Cet exemple de balise a montre comment appeler la route dans l’attribut href :

<?php echo $record['title']; ?>

4 - Récupération du GET dans le controller

Dans le fichier "APPLICATION_PATH"/application/modules/default/controllers/PortfolioController.php, nous allons récupérer l’id_propre en GET et faire une requête pour récupérer les données de la réalisation en base :


<?php
class PortfolioController extends Zend_Controller_Action
{
    public function init()
    {
        // set place holder rubrique
        $this->view->placeholder('rubrique')->set('portfolio');

        // set layout
        $this->_helper->layout->setLayout('portfolio');
    }

    // action to display a realisation item
    public function indexAction()
    {
        // set filters and validators for GET input
        $filters = array(
            'id_propre' => array('HtmlEntities', 'StripTags', 'StringTrim')
        );
        $validators = array(
            'id_propre' => array('NotEmpty'),
        );
        $input = new Zend_Filter_Input($filters, $validators);
        $input->setData($this->getRequest()->getParams());

        /* article title for head */
        $result_title = Next_Model_Realisations::getRealisationPortfolioByIdPropre($input->id_propre);
        $this->view->title_head = $result_title[0]['title'];

        /* Navigation pagination system */

        // test if input is valid
        // retrieve requested record
        // find next and prev item for pagination
        // attach to view
        if ($input->isValid())
        {
            // get selected realisation and linked document
            $result = Next_Model_Realisations::getRealisationPortfolioByIdPropre($input->id_propre);

            // test if result from request is not empty
            if (!empty($result))
            {
                // send result to view
                $this->view->records = $result[0];

                /* pagination system */

                // find the id of the current item and send it to view
                $this->view->current = $this->view->records['position'];

                // send id current item to var
                $position_current = $this->view->records['position'];

                // NEXT POSITION
                // query for finding next position item
                $resultNext = Next_Model_Realisations::findNextRealisation($position_current);

                // test if it's the the item is the higher position
                // query for the position from the last realisation
                // send the value to the view
                if($resultNext == null)
                {
                    // query for last realisation position
                    $resultNextLast = Next_Model_Realisations::lastRealisationPosition();

                    // send the value to the view
                    $this->view->next = $resultNextLast[0];

                }
                else
                {
                    $this->view->next = $resultNext[0];
                }

                // PREVIOUS REALISATION
                // query for the previous item
                $resultPrevious = Next_Model_Realisations::findPreviousRealisation($position_current);

                // test if it's the last item
                if($resultPrevious == null)
                {
                    // query first realisation position
                    $resultPreviousLast = Next_Model_Realisations::firstRealisationPosition();

                    $this->view->previous = $resultPreviousLast[0];
                }
                else
                {
                    $this->view->previous = $resultPrevious[0];
                }

            }
            else
            {
                throw new Zend_Controller_Action_Exception('Page not found', 404);
            }
        }
    }
}

5 - Ajout d’une class de traitement clean url

Nous allons ajouter une classe utilitaires qui va se charger de nettoyer les url afin de fournir des routes propres. Pour cela nous allons utliser la librairie que nous allons ajouter String.php dans le dossier "APPLICATION_PATH"/library/Next/ :

Cette classe contiendra le code suivant :


<?php
class Uzik_String
{
    public static function getPrenom($auteur)
    {   
        $rst = $auteur;
        $n = strpos($auteur, ',');
        
        if ($n)
            $rst = substr($auteur, $n + 2);
        
        return $rst;
    }

    public static function getNom($auteur)
    {   
        $rst = $auteur;
        $n = strpos($auteur, ',');
        
        if ($n)
            $rst = substr($auteur, 0, $n);
        
        return $rst;
    }
    
    public static function getPrenomNom($auteur)
    {
        return self::getPrenom($auteur) . " " . self::getNom($auteur);
        
    }

    public static function truncate($string, $limit = 32, $break="", $pad="…") 
    { 
        // return with no change if string is shorter than $limit  
        if(strlen($string) <= $limit) return $string; 
        
        // is $break present between $limit and the end of the string? 
        if ($break == '')
            $breakpoint = $limit;
         else
            $breakpoint = strpos($string, $break, $limit);
            
        if(false !== $breakpoint) { 
            if($breakpoint < strlen($string) - 1) { 
                $string = substr($string, 0, $breakpoint) . $pad; 
            } 
        } 
        
        return $string;
    }
    
    public static function makePassword($length = 8)
    {
        $chars = "abcdefghijkmnopqrstuvwxyz0123456789";

        srand((double)microtime()*1000000);     
        $i = 0;
        $pass = '' ;

        while ($i < $length) {
            $num = rand() % 33;
            $tmp = substr($chars, $num, 1);
            $pass = $pass . $tmp;
            $i++;
        }

        return $pass;
    }
    
    public static function cleanSEO($string)
    {

        //Suppression des accents
        $result = self::convertAccents($string);
    
        //Suppression des espaces en début et fin de chaîn
        $result = trim($result);

        //mise en minuscule
        $result = strtolower($result);
 
        //Remplacement des espaces et caracteres spéciaux
        $result = str_replace(" ",'-',$result);
        $result = preg_replace('#([^a-z0-9-])#','-',$result);
 
        //Suppression des tirets multiples
        $result = preg_replace('#([-]+)#','-',$result);
 
        //Suppression du premier caractère si c'est un tiret
        if ($result{0} == '-') $texte = substr($result,1);
 
        //Suppression du dernier caractère si c'est un tiret
        if(substr($result, -1, 1) == '-') $result = substr($result, 0, -1);
 
        return $result;

    }

    public static function isUTF8($str) 
    {
        $length = strlen($str);
        for ($i=0; $i < $length; $i++) {
            $c = ord($str[$i]);
            if ($c < 0x80) $n = 0; # 0bbbbbbb
            elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb
            elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb
            elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb
            elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb
            elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b
            else return false; # Does not match any model
            for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
                if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
                    return false;
            }
        }
        return true;
    }

    /**
     * Converts all accent characters to ASCII characters.
     *
     * If there are no accent characters, then the string given is just returned.
     *
     * @param string $string Text that might have accent characters
     * @return string Filtered string with replaced "nice" characters.
     */
    public static function convertAccents($string) {
        if ( !preg_match('/[\x80-\xff]/', $string) )
            return $string;

        if (self::isUTF8($string)) {
            $chars = array(
            // Decompositions for Latin-1 Supplement
            chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
            chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
            chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
            chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
            chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
            chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
            chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
            chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
            chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
            chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
            chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
            chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
            chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
            chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
            chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
            chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
            chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
            chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
            chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
            chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
            chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
            chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
            chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
            chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
            chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
            chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
            chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
            chr(195).chr(191) => 'y',
            // Decompositions for Latin Extended-A
            chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
            chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
            chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
            chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
            chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
            chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
            chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
            chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
            chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
            chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
            chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
            chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
            chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
            chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
            chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
            chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
            chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
            chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
            chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
            chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
            chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
            chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
            chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
            chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
            chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
            chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
            chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
            chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
            chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
            chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
            chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
            chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
            chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
            chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
            chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
            chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
            chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
            chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
            chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
            chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
            chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
            chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
            chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
            chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
            chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
            chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
            chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
            chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
            chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
            chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
            chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
            chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
            chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
            chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
            chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
            chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
            chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
            chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
            chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
            chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
            chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
            chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
            chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
            chr(197).chr(190) => 'z', chr(197).chr(191) => 's',
            // Euro Sign
            chr(226).chr(130).chr(172) => 'E',
            // GBP (Pound) Sign
            chr(194).chr(163) => '');

            $string = strtr($string, $chars);
        } else {
            // Assume ISO-8859-1 if not UTF-8
            $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
                .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194)
                .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202)
                .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
                .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218)
                .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227)
                .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235)
                .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243)
                .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251)
                .chr(252).chr(253).chr(255);

            $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";

            $string = strtr($string, $chars['in'], $chars['out']);
            $double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
            $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
            $string = str_replace($double_chars['in'], $double_chars['out'], $string);
        }

        return $string;
    }

    public static function removeNoAlphaNumericChars($string)
    {
        return ereg_replace("[^A-Za-z0-9]", "", $string); 
    }

    public static function encodeArray($args)
    {
      if(!is_array($args)) return false;
      $c = 0;
      $out = '';
      foreach($args as $name => $value)
      {
        if($c == 0) $out .= '?';

        if($c++ != 0) $out .= '&';
        $out .= urlencode("$name").'=';
        if(is_array($value))
        {
          $out .= urlencode(serialize($value));
        }else{
          $out .= urlencode("$value");
        }
      }
      return $out;
    }

}