création d'un moteur de template perso

Mammouth du PHP | 843 Messages

25 juin 2007, 23:16

Salut à tous :)
j'ai fait le tour du tuto PHPfrance et de quelques exemples de classes template sur le forum...

j'ai encore du mal a comprendre le principe à mettre en oeuvre mon propre moteur de template.
Si quelqu'un pourvait me montrer pour poser cette classes template tout en m'expliquant le principe de fonctionnement ;)

mon objectif sera d'y ajouter un tat de fonction pour y integrer l'alterate stylesheet ainsi que les template graphique du site et quelques info simple.... le tout en vue d'une POO

Merci d'avance :pouce:
:: contactez moi par MP ::
:non: NON au language SMS sur les forums :non:

Mammouth du PHP | 684 Messages

26 juin 2007, 00:24

Juste pour comprendre l'envi de refaire la roue, que ne trouve tu pas dans les moteurs de templates
actuels ?????
PHPSavant est développer en PHP5 a partir de la version 3. http://phpsavant.com.
Zigz4g

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

26 juin 2007, 00:53

Sinon, il y a un moteur de template super efficace qui est utilisé par quelques-uns des plus grands projets PHP comme Symfony et Joomla!, mais également dotClear2.

Il s'agit de PHP :)

Mammouth du PHP | 843 Messages

27 juin 2007, 11:15

@Naholyr: j'ai pô compris :langue:

@zigz4g: pas mal mais je veut du sur mesure pouur moi et compatible xhtml ;)

si quelqu'un pouvait m'expliquer le principe de base pour créé son propre moteur de template (classes, fonction, poo...)


merci d'avance ;)
:: contactez moi par MP ::
:non: NON au language SMS sur les forums :non:

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

27 juin 2007, 11:28

@Naholyr: j'ai pô compris :langue:
Je veux dire que PHP est un langage de template, plutôt que de t'amuser à créer un parseur compliqué qui va analyser des pages dans une syntaxe bizarre genre

Code : Tout sélectionner

<ul> {foreach from=$animaux item=animal} <li>{$animal.nom}</li> {/foreach} </ul>
On peut bien utiliser un langage de template que PHP comprendra directement
<ul>
  <?php foreach ($animaux as $animal): ?>
  <li><?php echo $animal['nom'] ?></li>
  <?php endforeach ?>
</ul>
Tu as ainsi un système très complet qui gère :
- les conditions (if/else/elseif/endif)
- les boucles (foreach/endforeach)
- les templates imbriqués (include)
- l'affichage de variable (echo)
- le formatage de date (date)
- le multilangue (_)
etc... virer la logique d'un template ne dépend pas du moteur de template, mais de la discipline du programmeur.

Ton moteur de template deviendra :
class Template {

  protected $vars = array(); // liste des variables

  function getVars() {
    return $vars;
  }

  function set($var, $val) {
    $this->vars[$var] = $val;
  }

  function get($var) {
    return $this->vars[$var];
  }

  function render($template) {
    extract($this->vars);
    include $template;
  }

}
À compléter après pour rajouter la compression gzip, le cache, la gestion des headers, probablement 2-3 options comme le répertoire où il trouvera les templates, et tu auras un petit Savant maison :)

Mammouth du PHP | 843 Messages

27 juin 2007, 11:43

je veut faire un moteur de template reactif qui puisse generer tant du html que du xhtml...

J'aimerai tout d'abords faire une truc simple qui soit une bonne base de depard ;)

si quelqu'un pouvai m'expliquer le principe de base d'un moteur de template ;)
genre qu'est ce qu'un fichier.tpl et comment fonctionne ces derniers :?

@naholyr: peut tu m'expliquer le fonctionnement de la classe template que tu m'a fournis
:: contactez moi par MP ::
:non: NON au language SMS sur les forums :non:

jed
Eléphant du PHP | 218 Messages

27 juin 2007, 12:52

Salut, si tu as déjà appris à programmer en objet, tu devrais déjà avoir une idée de la démarche à suivre. Sinon je te conseille d'apprendre avant les bases de l'objet avant de te lancer dans un projet de cette envergure. Les fonctions propres à la manipulation et au parsage de fichiers ne sont pas différentes de celles que tu utilises en programmant de manière classique. Après à toi de les assembler logiquement sous forme de méthodes. :wink:

Eléphant du PHP | 259 Messages

27 juin 2007, 13:33

Edit : Message supprimé par l'auteur -> echo du message de naholyr, qui n'apportait rien de plus :)
Modifié en dernier par Jules Petibidon le 27 juin 2007, 14:54, modifié 1 fois.

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

27 juin 2007, 14:06

Je pensais que tu avais déjà utilisé un moteur de template, c'est pourquoi je n'ai pas commandé mon code plus que ça.
Un moteur de template va simplement gérer des "vues" (cf. modèle MVC) :
- on instancie le moteur
- on lui fournit des variables
- on lui donne la vue à gérer
- il nous donne le résultat
En reprenant le code que je t'ai donné, tu as :
- le moteur de template, c'est la classe Template que j'ai donnée.
- le template (ou vue), c'est le code que j'ai fourni avec les foreach/endforeach & co (que tu vas par exemple enregistrer en "montemplate.tpl", le fichier n'a pas besoin de se nommer .php pour fonctionner).
L'utilisation sera de ce genre, très classique et conforme à la plupart des moteurs existant :
// Traitements, définitions de mes variables
$animaux = array(
  array('nom'=>'Tigre'),
  array('nom'=>'Lion'),
  array('nom'=>'Panthère')
);

// Instanciation de mon moteur
$template = new Template;

// Passage des variables au moteur
$template->set('animaux', $animaux);

// Affichage du résultat
$template->render('montemplate.tpl');
Crois-moi, c'est une excellente base de départ.
En reprenant exactement le même principe, et en ajoutant quelques idées d'options, on arrive vite à un système beaucoup plus complet. Tiens si tu veux j'ai retrouvé une version "à trous" du moteur que j'utilise personnellement pour les petits projets (pour les gros j'utilise smarty parce que sinon ça défrise les graphistes de voir des balises PHP) :
<?php
class Template {

    /**
     * Variables passées à la vue
     */
    protected $vars = array ();

    /**
     * Options du moteur
     */
    protected $options = array (
        'template_dir' => null,             // Dossier où aller chercher les vues (ne pas oublier le slash de fin, exemple : '/path/to/templates/')
        'cache' => false,                   // TODO : Activer le cache ?
        'cache_dir' => 'cache',             // TODO : Dossier de stockage des fichiers de cache
        'cache_timeout' => 3600,            // TODO : Expiration des fichiers de cache
        'content_type' => 'text/html',      // Type MIME de la page
        'charset' => null,                  // Encodage de la page (il est conseillé de le définir)
        'compress' => false,                // TODO : Activer la compression Gzip
        'automatic_headers' => true         // Envoyer automatiquement les entêtes à l'appel de render()
    );

    /**
     * Entêtes HTTP définies
     */
    protected $headers = array ();

    /**
     * Dernière instance créée
     */
    protected static $lastInstance = null;

    /**
     * Constructeur
     */
    public function __construct($options = array ()) {
        $this->options = array_merge($this->options, $options);
        $this->checkOptions();
        self :: $lastInstance = $this;
    }

    /**
     * @todo Template::checkOptions()
     */
    protected function checkOptions() {

    }

    /**
     * Rappelle la dernière instance créée. Ce n'est pas tout-à-fait du singleton, mais permet de l'utiliser
     * comme tel selon l'application.
     */
    public static function instance() {
        return self :: $lastInstance;
    }

    /**
     * Valeur d'une option
     */
    public function getOption($option, $default = null) {
        $value = @ $this->options[$option];
        if (is_null($value)) {
            return $default;
        } else {
            return $value;
        }
    }

    /**
     * Redéfinit une option
     */
    public function setOption($option, $value) {
        $this->options[$option] = $value;
    }

    /**
     * Renvoie la liste des noms des variables passées
     */
    public function getVars() {
        return array_keys($this->vars);
    }

    /**
     * Passe une variable à la vue
     */
    public function set($var, $val) {
        $this->vars[$var] = $val;
    }

    /**
     * Récupère la valeur d'une variable passée à la vue
     */
    public function get($var, $default = null) {
        return isset ($this->vars[$var]) ? $this->vars[$var] : $default;
    }

    /**
     * Renvoie la liste des entêtes HTTP (inclut le content-type défini via les options)
     */
    public function getHeaders() {
        $headers = $this->headers();
        $content_type = $this->getOption('content_type', 'text/html');
        if ($charset = $this->getOption('charset')) {
            $content_type .= '; charset=' . $charset;
        }
        $headers['Content-Type'] = $content_type;
        return $headers;
    }

    /**
     * Ajoute une entête HTTP
     */
    public function addHeader($header, $value) {
        if (strtolower($header) == 'content-type') {
            list ($mime, $charset) = explode(';', $value, 2);
            $this->setOption('content_type', trim($mime));
            $this->setOption('charset', trim($charset));
        } else {
            $this->headers[$header] = $value;
        }
    }

    /**
     * Envoie les entêtes HTTP (nécessaire si vous avez désactivé l'option 'automatic_headers')
     */
    public function sendHeaders() {
        $headers = $this->getHeaders();
        foreach ($headers as $header => $value) {
            header($header . ': ' . $value);
        }
    }

    /**
     * @todo Template::isCached()
     */
    protected function isCached($template, $cache_key = null) {
        return false;
    }

    /**
     * @todo Template::cache()
     */
    protected function doCache($template, $cache_key = null) {

    }

    /**
     * @todo Template::getFromCache()
     */
    protected function getFromCache($template, $cache_key = null) {

    }

    /**
     * Affiche le résultat de l'injection des variables passées dans la vue donnée
     * Si l'option 'automatic_headers' n'est pas désactivée, les entêtes sont envoyées
     */
    public function render($template, $cache_key = null) {
        if ($this->getOption('automatic_headers')) {
            $this->sendHeaders();
        }
        $result = $this->fetch($template, $cache_key);
        if (false === $result) {
            return false;
        } else {
            echo $result;
            return true;
        }
    }

    /**
     * Renvoie le résultat de l'injection des variables passées dans la vue donnée
     * N'envoie aucune entête
     */
    public function fetch($template, $cache_key = null) {
        if ($dir = $this->getOption('template_dir')) {
            $template = $dir . $template;
        }
        if (!is_file($template)) {
            return false;
        }
        $cache_enabled = $this->getOption('cache');
        $get_from_cache = $cache_enabled && $this->isCached($template, $cache_key);
        if ($get_from_cache) {
            return $this->getFromCache($template, $cache_key);
        } else {
            extract($this->vars);
            ob_start();
            include $template;
            $contents = ob_get_contents();
            ob_end_clean();
            if ($cache_enabled) {
                $this->doCache($template, $cache_key);
            }
            return $contents;
        }
    }

}
?>
Il n'y a que la base qui fonctionne, reste à remplir les trous pour activer le support du cache, de la compression Gzip, la gestion des erreurs, et toutes les fonctionnalités qui pourraient te passer par la tête :)
Il est bon de noter que dans le template (le fichier .tpl) on est également dans la méthode Template::fetch(), ce qui signifie que l'on a accès à... $this :) C'est très intéressant parce que ça veut dire que :
- on peut récupérer les options avec $this->getOption().
- on peut récupérer les headers de la même façon.
- on a accès aux variables $template et $cache_key (si elles n'ont pas été écrasées par extract($this->vars), auquel cas on pourra faire suivre l'extract() d'un $func_args = func_get_args() pour en récupérer l'accès).
- on peut tout à fait définir des "fonctions spécial template" sous forme de méthode de la classe Template que l'on pourra simplement appeler $this->maFonction().
Modifié en dernier par naholyr le 28 juin 2007, 07:48, modifié 1 fois.

Mammouth du PHP | 843 Messages

27 juin 2007, 22:26

merci les gars :)

je regarde un peu et je reviendrai une fois que j'aurrai muri ma reflexion ;)
:: contactez moi par MP ::
:non: NON au language SMS sur les forums :non:

Mammouth du PHP | 843 Messages

08 juil. 2007, 17:15

ok j'ai bien muris le sujet et je revient avec une questions :)

quel language pour les fichier .tpl :-k (c'est pour faire des templates avec utilisation des fonction existante de php dedant. des truc genre date(); ...) Du php je suppose :?
:: contactez moi par MP ::
:non: NON au language SMS sur les forums :non:

Mammouth du PHP | 505 Messages

08 juil. 2007, 20:31

Bah soit tu suis ce que naholir a indiqué, a savoir tu utilises php en tant que moteur de template et donc tu utilises php pour les .tpl aussi(plus classiquement phtml) , soit tu te créer ton propres langage comme on peut trouver dans les moteurs de templates classique. mais pour moi, créer un langage pour l'occasion n'apporte pas grand chose de plus. php a une syntaxe a coup de foreach : endforeach, if : endif qui est largement aussi compréhensible que ce qu'on peut voir ailleur, et tout aussi accessible par un non developper. Après, il faut voir avec les gens avec lesquels tu vas travailler si ils connaissent déjà un langage de template, ou si il sont habitué a tel ou tel truc. La résistance au changement est parfois dur a surmonter.

Mammouth du PHP | 843 Messages

08 juil. 2007, 21:31

je vais comme vous me le conseiller utiliser tout le power de PHP :langue:

1°)par contre mon fichier php va avoir une extention .tpl à la place de .php... C'est ça?

2°) si je comprend bien aussi, quand naholyr parle de gestion des headers, c'est un controle de l'envoi des headers http. c'est ça?

3°)et pour ce qui est du contenu même de la page: peut on passer par un template assicier au template de base ou doit on tout faire dans le même template (squellette de base + contenu de la page)?

merci d'avance ;)
:: contactez moi par MP ::
:non: NON au language SMS sur les forums :non:

jed
Eléphant du PHP | 218 Messages

09 juil. 2007, 09:02

Je comprend pas trop cette histoire de "langage" pour des templates. Il est évident que si tu développe ton application en php, tu vas introduire du php dans tes templates! Mais l'un des principes de base d'un template est d'y trouver le moins de php possible pour isoloer la partie code de la partie design. Donc si ton moteur est bien conçu, tu ne devrais trouver quasiment aucune fonction dans tes templates, juste les variables devant être intégrées au design.

Mammouth du PHP | 843 Messages

10 juil. 2007, 00:58

et pour ce qui est des autres question, une idée :-k
:: contactez moi par MP ::
:non: NON au language SMS sur les forums :non: