S'abonner au Flux RSS

Tag - zend framework

Fil des billets - Fil des commentaires

jeudi 7 janvier 2010

Test de VS.PHP 2010

Bonjour à tous.

Dans le but de créer un petit projet perso en PHP + ZF, j'ai décidé de tester pour de bon VS.PHP 2010 actuellement en développement. Le test est réalisé sur le build 2.8.1.6090.

VS.PHP est une extension pour Microsoft Visual Studio conçue pour écrire des applis PHP. Je m'attend globalement à la même expérience qu'avec Netbeans 6.5+. VS.PHP 2008 coûte $99.99 ou €73.99. Notez que Visual Studio existe sous une forme gratuite ; si vous n'êtes pas développeur .NET, VS.PHP ne nécessitera pas de version payante de VS.

A noter que je ne connais presque pas le logiciel, je pars à sa découverte.

Installation

Depuis le site de dev, récupérez l'installateur le plus récemment compilé. L'installateur est un web install.

Installation...

Première utilisation

Quelle surprise de voir qu'un projet de type 'Zend MVC Project' m'est proposé ! Effectivement, dans le fenêtre de nouveau projet, on peut créer un projet classique ou un projet ZF. Ca tombe bien, c'est mon framework préféré !

New project window

En plus de tout ça, je vais utiliser AnkhSVN pour versionner mon projet...

Voilà mon projet PHP+ZF créé. La structure de fichiers proposée ne me convient déjà pas. Le template de projet crée quelques malheureux fichiers. Rien de transcendant... De plus, la colorisation syntaxique est très mal intégrée...

Ma colorisation C# PHP colors and ZF structure

Impossible de trouver les options de colorisation pour le code PHP. Une recherche sur le web m'indique qu'elles devraient s'afficher avec VS démarré en administrateur... Même pas... Petite restructuration de l'appli :

The application is ready to run Built-in web server displays an error

Un mini server web de debug est inclus. J'imagine que le but est de fournir un debug pas-à-pas. Très bon point.

Malheureusement, de nombreux bugs surviennent avec cette version beta. Actuellement VS a gardé un lock sur le fichier .phpproj et n'arrive pas à sauvegarder la structure du projet (cette action est nécessaire pour démarrer l'appli).

Néanmoins, l'IntelliSense est au rendez-vous. Vous pouvez dans un premier temps définir un include_path pour spécifier l'emplacement de votre framework.

PHP include path

Par la suite, l'IDE affichera un IntelliSense digne de celui que l'on a en developpement .NET : le meilleur.

PHP IntelliSense

Conclusion

Le bug cité ayant détruit mon projet ; considérons qu'il est trop tôt pour tester cette version. D'ici quelques jours je ferai un test avec VS 2008 si j'arrive à négocier l'extension de la durée d'évaluation...

Bug bug bug bug bug bug

dimanche 8 février 2009

Nouvel Helper qui change la vie

Vous connaissez tous Zend_View_Helper_Url qui permet de créer une url rapidement dans une view. La syntaxe est la suivante : $this->url(array('controller' => 'index', 'action' => 'about', 'arg0' => 'value'));. Il faut avouer que c'est assez sympatique. Mais il est laborieux d'écrire systématiquement la balise <a />. Voici donc un helper très basique reprennant les arguments de url(). La seule modification est l'ajout du premier argument. Celui-ci contiendra la texte à mettre dans la balise <a />

  1. <?php
  2.  
  3. /**
  4.  * An helper to create xhtml links quickly
  5.  *
  6.  * This program is free software: you can redistribute it and/or modify
  7.  * it under the terms of the GNU Lesser General Public License as published by
  8.  * the Free Software Foundation, either version 3 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14.  * GNU Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public License
  17.  * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  * @author SandRock <antoine.sottiau@gmail.com>
  20.  * @see Zend_View_Helper_Url
  21.  */
  22. class App_View_Helper_Link extends Zend_View_Helper_Abstract {
  23.  
  24. /**
  25. *
  26. * @param string $text the contents of the link
  27. * @param array $urlOptions Options passed to the assemble method of the Route object.
  28. * @param mixed $name The name of a Route to use. If null it will use the current Route
  29. * @param bool $reset Whether or not to reset the route defaults with those provided
  30. * @param boolean $encode
  31. * @return string a xhtml link like '<a href="url">text</a>"
  32. */
  33. public function link($text, array $urlOptions = array(), $name = null, $reset = false, $encode = true) {
  34. $router = Zend_Controller_Front::getInstance()->getRouter();
  35. $url = $router->assemble($urlOptions, $name, $reset, $encode);
  36. return '<a href="'.$url.'">'.$text.'</a>';
  37. }
  38.  
  39. }

Exemple :

  1. <?php
  2. echo $this->link('A propos de...', array('controller' => 'index', 'action' => 'about', 'arg0' => 'value'));?>
  3. <a href="/index/about/arg0/value">A propos de...</a>

jeudi 25 septembre 2008

Zend_View_Helper_HeadStyle amélioré

Le Zend_View_Helper_HeadStyle de Zend Framework a un bug non corrigé depuis très longtemps, à savoir ZF-3406. Le bug en question empèche la création d'une balise <style> avec un attribut media contenant une liste de différents médias.

  1. $this->headStyle()->captureStart(Zend_View_Helper_Placeholder_Container_Abstract::APPEND, array('media' => 'screen'))
  2. // Displays <style type="text/css" media="screen">
  3.  
  4. $this->headStyle()->captureStart(Zend_View_Helper_Placeholder_Container_Abstract::APPEND, array('media' => array('screen', 'projection', 'tv')))
  5. // Should display <style type="text/css" media="screen projection tv">
  6. // But displays <style type="text/css">

Donc, voici un nouvel helper modifié qui fait son job :

  1. <?php
  2.  
  3. require_once 'Zend/View/Helper/HeadStyle.php';
  4.  
  5. /**
  6.  * HeadStyle helper
  7.  *
  8.  * @uses helper Zend_View_Helper
  9.  */
  10. class App_View_Helper_HeadStyle extends Zend_View_Helper_HeadStyle {
  11.  
  12. /**
  13. * Convert content and attributes into valid style tag
  14. *
  15. * @param stdClass $item Item to render
  16. * @param string $indent Indentation to use
  17. * @return string
  18. */
  19. public function itemToString(stdClass $item, $indent) {
  20. $attrString = '';
  21. if (!empty($item->attributes)) {
  22. foreach($item->attributes as $key => $value) {
  23. if (!in_array($key, $this->_optionalAttributes)) {
  24. continue;
  25. }
  26. if ('media' == $key) {
  27. if (is_string($value) && preg_match('/^[\w ]+$/', $value)) {
  28. $value = explode(' ', $value);
  29. }
  30. if (is_array($value)) {
  31. $stringValue = '';
  32. $separator = '';
  33. foreach ($value as $mediaType) {
  34. if (!in_array($mediaType, $this->_mediaTypes)) {
  35. continue;
  36. }
  37. $stringValue .= $separator.$mediaType;
  38. $separator = ' ';
  39. }
  40. $value = $stringValue;
  41. } else {
  42. if (!in_array($value, $this->_mediaTypes)) {
  43. continue;
  44. }
  45. }
  46. }
  47. $attrString .= sprintf(' %s="%s"', $key, htmlspecialchars($value));
  48. }
  49. }
  50.  
  51. $html = '<style type="text/css"' . $attrString . '>' . PHP_EOL
  52. . $indent . '<!--' . PHP_EOL . $indent . $item->content . PHP_EOL . $indent . '-->' . PHP_EOL
  53. . '</style>';
  54.  
  55. return $html;
  56. }
  57.  
  58. }

On spécifier au Broker de le charger de préférence à celui de zf :

  1. $this->view->setHelperPath(Zend_Registry::get('conf')->paths->views.'helpers/', 'App_View_Helper');

Et ça s'utilise de cette façon :

  1. $this->headStyle()->captureStart(Zend_View_Helper_Placeholder_Container_Abstract::APPEND, array('media' => array('screen', 'print', 'projection', 'tv')));
  2. $this->headStyle()->captureStart(Zend_View_Helper_Placeholder_Container_Abstract::APPEND, array('media' => 'screen print projection tv'));

mercredi 6 août 2008

Codes PHP en vrac...

App_Form_Element_DateWithJdatepicker

Un Zend_Form_Element utilisant le datepicker de jQuery françisé :

  1. class App_Form_Element_DateWithJdatepicker extends Zend_Form_Element_Xhtml {
  2.  
  3. public function init() {
  4. $this->addValidator('Date')
  5. ->setAttrib('class', 'datepicker');
  6. }
  7.  
  8. }
  1. $(".datepicker").datepicker({
  2. clearText: 'Effacer', clearStatus: '', closeText: 'Fermer', closeStatus: 'Fermer sans modifier', prevText: '&lt;Préc', prevStatus: 'Voir le mois précédent', nextText: 'Suiv&gt;', nextStatus: 'Voir le mois suivant', currentText: 'Courant', currentStatus: 'Voir le mois courant', monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun', 'Jul','Aoû','Sep','Oct','Nov','Déc'], monthStatus: 'Voir un autre mois', yearStatus: 'Voir un autre année', weekHeader: 'Sm', weekStatus: '', dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'], dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'], dayStatus: 'Utiliser DD comme premier jour de la semaine', dateStatus: 'Choisir le DD d MM', dateFormat: 'dd/mm/yy', firstDay: 0, initStatus: 'Choisir la date', isRTL: false,
  3. dateFormat: "yy-mm-dd",
  4. firstDay: 1,
  5. showStatus: true,
  6. showOn: "both",
  7. buttonImage: "<?php echo $front->getBaseUrl() ?>/js/lib/jquery-ui-1.5.2/images/calendar.gif",
  8. buttonImageOnly: true
  9. }
  10. );

Un FlashMessenger personnalisé

...Pour inclure un type aux messages (typiquement une class css pour un affichage personnalisé pour les erreurs, les confirmations, les alertes...).

  1. class App_Controller_Action_Helper_FlashMessenger extends Zend_Controller_Action_Helper_FlashMessenger implements IteratorAggregate, Countable {
  2.  
  3. /**
  4.   * addMessage() - Add a message to flash message
  5.   *
  6.   * @param string $message
  7.   * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface
  8.   */
  9. public function addMessage($message, $class)
  10. {
  11. $message = array(
  12. 'message' => $message,
  13. 'class' => $class);
  14.  
  15. if (self::$_messageAdded === false) {
  16. self::$_session->setExpirationHops(1, null, true);
  17. }
  18.  
  19. if (!is_array(self::$_session->{$this->_namespace})) {
  20. self::$_session->{$this->_namespace} = array();
  21. }
  22.  
  23. self::$_session->{$this->_namespace}[] = $message;
  24.  
  25. return $this;
  26. }
  27.  
  28. }
  29.  
  30. // Un Zend_Controller_Action personnalisé
  31.  
  32. class App_Controller_Action extends Zend_Controller_Action {
  33.  
  34.  
  35.  
  36. /**
  37. * FlashMessenger
  38. *
  39. * @var Zend_Controller_Action_Helper_FlashMessenger
  40. */
  41. protected $_flashMessenger = null;
  42.  
  43. /**
  44. * Class constructor
  45. *
  46. * @param Zend_Controller_Request_Abstract $request
  47. * @param Zend_Controller_Response_Abstract $response
  48. * @param array $invokeArgs Any additional invocation arguments
  49. * @return void
  50. */
  51. public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array()) {
  52. $this->setRequest($request)
  53. ->setResponse($response)
  54. ->_setInvokeArgs($invokeArgs);
  55. $this->_helper = new Zend_Controller_Action_HelperBroker($this);
  56.  
  57. //$this->_flashMessenger = $this->_helper->getHelper('FlashMessenger');
  58. $this->_flashMessenger = new App_Controller_Action_Helper_FlashMessenger();
  59. $this->view->flashMessenger = $this->_flashMessenger;
  60.  
  61. $this->init();
  62. }
  63.  
  64. }

Exemple d'utilisation :

  1. $this->_flashMessenger->addMessage('Les calculs ont été mis à jour.', 'notice');
  2. $this->_flashMessenger->addMessage('Impossible d\'effectuer l'opération demandée.', 'error');
  1. <!-- layout.phtml -->
  2. <div id="messenger">
  3. <?php
  4. if (is_object($this->flashMessenger)) :
  5. $messages = $this->flashMessenger->getMessages();
  6. foreach ($messages as $m) {
  7. if (is_array($m)) {
  8. echo "\t",'<p class="',$m['class'],'">',$m['message'],'</p>',"\n";
  9. } else {
  10. echo "\t",$m,"\n";
  11. }
  12. }
  13. endif;
  14. ?>
  15. </div>

vendredi 25 juillet 2008

Zend Framework placeholders

Cela fait maintenant 5 mois que je travaille avec Zend Framework. J'ai des idées d'articles intéressants dont voici le premier : les placeholders utilisés avec Zend_Layout et Zend_View.

Pour information : Zend_View est une class permettant d'afficher une view dans un contexte MVC, elle est directement liée à une Zend_Controller_Action et permet d'afficher des données à l'utilisateur final. Zend_Layout est le système de template natif de ZF, il permet de définir un layout (application/views/scripts/layout.phtml) dans lequel la view principale sera affichée. Exemple :

  1. <?php echo '<?' ?>xml version="1.0" encoding="utf-8" ?>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
  4. <head>
  5. <title>My Website</title>
  6. </head>
  7. <body>
  8. <div id="header"></div>
  9. <div id="nav"></div>
  10. <div id="content">
  11.  
  12. <?php echo $this->layout()->content; ?>
  13.  
  14. </div>
  15. <div id="footer"></div>
  16.  
  17. </body>
  18. </html>

Ceci est un layout comprennant les élements XHTML de base et présente 4 block : header, nav, content, footer qui serviront à la mise en page. Le problème qui se pose est celui-ci : . C'est là que les placeholders interviennent (traduire par "emplacements réservés").

De base, ZF propose un placeholder de base accessible depuis une view ou depuis un layout par <?php $this->placeholder('myPlaceholder') ?>. Il y a aussi les placeholders prédéfinis HeadLink, HeadMeta, HeadScript, HeadStyle, HeadTitle. Voici le layout précédent adapté :

  1. <?php
  2. // application/views/scripts/layout.phtml
  3. $this->headTitle()->prepend('My Website');
  4. $this->headTitle()->setSeparator(' - ');
  5.  
  6. echo '<?' ?>xml version="1.0" encoding="utf-8" ?>
  7. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
  8. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
  9. <head>
  10. <title><?php echo $this->headTitle() ?></title>
  11.  
  12. <?php echo $this->headStyle() ?>
  13.  
  14. <?php echo $this->headScript() ?>
  15.  
  16. </head>
  17. <body>
  18. <div id="header"></div>
  19. <div id="nav"><?php echo $this->placeholder('nav') ?></div>
  20. <div id="content">
  21.  
  22. <?php echo $this->layout()->content; ?>
  23.  
  24. </div>
  25. <div id="footer"></div>
  26.  
  27. </body>
  28. </html>

On remarque l'ajout de 4 placeholders. Voici comment y accéder depuis une view :

  • Définition directe du contenu via les méthodes :
    • $this->headTitle('My Title');
    • $this->headTitle->prepend('text');
    • $this->headTitle->append('text');
  • Enregistrement :
    • $this->placeholder('myPlacerholder')->captureStart('APPEND');
    • $this->placeholder('myPlaceholder')->captureEnd();
  1. <?php
  2. // application/views/scripts/articles/show.phtml
  3. $this->headTitle("Showing article");
  4. $this->placeholder('nav')->captureStart();
  5. ?>
  6.  
  7. <a href="...">Index</a> - <a href="...">Articles</a> - <a href="">Visualisation</a>
  8.  
  9. <?php
  10. $this->placeholder('nav')->captureEnd();
  11. $this->headScript()->captureStart();
  12. ?>
  13.  
  14. /* Some javascripts specifics to this page... */
  15.  
  16. <?php
  17. $this->headScript()->captureEnd();
  18. ?>

Ce que l'on a fait dans cette view :

  • On a définit un titre pour la page, comme spécifié dans le layout le titre final de la page sera : "My Website - Showing article"
  • Le placeholder de navigation sera complété par quelques liens.
  • Le placeholder pour les scripts contiendra des petits scripts spécifiques à la page

Je tiens à préciser que les placeholders prédéfinis ajouteront automatiquement les balises xhtml. Pour terminer : un layout utilisant headStyle d'un façon très pratique (utilisation de 2 types de médias css : print et screen) :

  1. <?php $this->headStyle()->captureStart() ?>
  2.  
  3. @import url(<?php echo $front->getBaseUrl() ?>/css/generic.css);
  4. @import url(<?php echo $front->getBaseUrl() ?>/css/global.css);
  5. @import url(<?php echo $front->getBaseUrl() ?>/js/lib/jquery-ui-1.5.2/jquery-ui-themeroller.css);
  6. img.ui-datepicker-trigger{position:relative; left:-21px; top:2px;}
  7.  
  8. <?php
  9. $this->headStyle()->captureEnd();
  10. $this->headStyle()->captureStart(Zend_View_Helper_Placeholder_Container_Abstract::APPEND, array('media' => 'print')) ?>
  11.  
  12. @import url(<?php echo $front->getBaseUrl() ?>/css/generic.css);
  13. @import url(<?php echo $front->getBaseUrl() ?>/css/print.css);
  14.  
  15. <?php
  16. $this->headStyle()->captureEnd();
  17. echo $this->headStyle();
  18. ?>

Convaincu ? Vous utilisez une autre technique ? J'espère que cet article vous aura été profitable, 2 autres sont en préparation.