SandRock.getBlog();

Aller au contenu | Aller au menu | Aller à la recherche

samedi 17 janvier 2009

Comparaison IDE PHP

Bienvenue sur ce nouvel épisode de la Grotte de SandRock. Aujourd'hui, nous allons tenter de comparer différents IDE (Environnement de Développement Intégré) pour coder en PHP. Pour chacun des éditeurs, on tentera de lister les fonctionnalités indispensables (auto-complétion objet, colorisation...), et les accessoires sympa comme l'intégration d'outils de versionning. Les logiciels seront présentés dans l'ordre dans lequel je les ai découvert.

Pour raison de sécurité, les screenshots seront légèrement censurés pour protéger certains projets top secrets :-)

Zend Studio 5 (payant, non maintenu)

Le premier éditeur sympa que j'ai testé était Zend Studio 5, qui ne semble plus être disponible sur le site de l'éditeur.

Une auto complétion puissante (malgrès quelques bugs), des fonctionnaltiés bizzares liées aux produits Zend. C'était sympa mais c'est mort, merci, à bientôt.

Zend Studio for Eclipse 6 (payant)

Voilà un logiciel plus sérieux, développé par Zend. Il existe en 2 version (99€ ou 400€), j'utilisais encore récemment la pro en démo. On y trouve la surpuissance de l'IDE bien connu Eclipse, couplé à un moteur PHP très avancé. La précomplétion est très efficace, autant pour le php, les fonctions, les objets mais aussi pour l'xml et l'xhtml.

Zend Studio for Eclipse 6 - précomplétion

Cet IDE comprend un outil très sympa qui permet d'ouvrir n'importe quel fichier en cherchant une class ou une function par son nom. C'est vraiment génial pour ne pas se tapper des recherches dans le filesystem local (vous remarquerez que j'utilise du vocabulaire technique anglais dans mes articles en français, mais c'est normal, je le trouve plus précis).

Zend Studio for Eclipse 6 - class search

Comme c'est basé sur eclipse, il y a des perspectives disponibles ; entendre par là des sorte d'outils. La perspective MVC Outline semble sympa dans le cas d'un développement ZF mais je n'ai jamais réussit à l'utiliser. De même que la perspective SVN Repository Exploring qui ne propose pas d'intégration concrète à un projet.

Zend Studio for Eclipse 6 - svn explorer

Un très bon IDE donc mais qui ne semble pas intégrer correctement le versionning. Je pense cependant que des plugin peuvent être trouvés sur internet.

Zend Studio Standard
Zend Studio Pro

Netbeans 6.5 (libre)

Netbeans 6.5 - Types de projets

J'ai remarqué cet IDE pour la première fois lors de mes cours Java à SUPINFO. Voyant qu'ils avaient intégré des projets de type PHP, RoR (Ruby on Rails), et C++, cela a attiré ma curiosité mais pas assez. C'est mon ami Ajite qui m'a dit de tester car ça en vallait le coup. J'ai donc tenté et découvert cet éditeur suprême. Tentons un petit coup de précomplétion :

Netbeans 6.5 - Source

On trouve une précomplétion bien au dessus de celle de ZSE avec plus d'infos/docs. La touche tab permet même de passer d'un argument à un autre d'une fonction.

Du coté versionning, j'ai été très impressionné par toutes les fonctionnalités. Pour commencer, Netbeans supporte 4 moteurs de versionning, à savoir : Local, CVS, Subversion et Mercurial. Mais le plus intéressant reste l'intégration du versionning qui est très aboutie ; en effet, on la retrouve partout. Dans l'explorateur de fichiers, une colorisation est appliquée aux noms de fichiers (vert = nouveau fichier, bleu = fichier modifié, rouge = conflit). Mais voici le meilleur : dans l'éditeur de code, des petits rectangles colorés affichent les modifications apportées localement aux fichiers. Un outil de diff est même intégré.

Netbeans 6.5 - Live Diff Netbeans 6.5 - Diff Netbeans 6.5 - Menu Versionning

Un outil de recherche est disponible comme dans ZSE, peut être bien qu'il est plus complet, je viens seulement de le trouver.

Netbeans 6.5 - Recherche

Si vous cherchez plus d'outils, un système de plugin existe tout comme dans eclipse (mais c'est beaucoup plus user-friendly).

Netbeans 6.5 - Plugins

Bref, un IDE très prometteur, et libre !

Site officiel de Netbeans

MS Visual Studio / PHP (cher)

Non, j'installerai pas ça sur mon pc. Peut être d'ici quelques mois je lui reserverai un article.

Aurais-je oublié un IDE ? Vous utilisez lequel ?

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'));

mardi 26 août 2008

CSS, medias, IE...

Un petit article pour résumer les bonnes pratiques rapides à mettre en place sur un site web au niveau des CSS adaptés aux différents médias existants.

Pour rappel, il est possible (et même fortement recommandé) de créer des feuilles de styles CSS pour différentes médias tels que les ordinateurs (screen), les appareils mobiles (handheld), les vidéoprojecteurs (projection) et les imprimantes (print). Pour cela, 2 méthodes sont possibles.

  1. <style type="text/css" media="all">
  2. @import "/css/global.css";
  3. </style>
  4. <style type="text/css" media="print">
  5. @import "/css/print.css";
  6. </style>
  7. <style type="text/css" media="handheld">
  8. @import "/css/handheld.css";
  9. </style>

Dans cet exemple, on définit un css général (mise en page, couleurs) pour tous les médias et on surcharge ensuite 2 fichiers pour l'impression et les appareils mobiles. Dans certains cas, il est aussi intéressant de ne pas utiliser de fichier global pour certains médias :

  1. <style type="text/css" media="screen print projection tv">
  2. @import "/css/global.css";
  3. </style>
  4. <style type="text/css" media="print">
  5. @import "/css/print.css";
  6. </style>
  7. <style type="text/css" media="handheld">
  8. @import "/css/handheld.css";
  9. </style>

Dans ce cas, le CSS pour appareils mobiles peut être indépendant des autres fichiers pour un controlle plus important. A noter que dans cette configuration, le media all n'apparait pas ; d'après les normes, cela n'est pas grave mais MS Internet Explorer 6 et 7 ne reconnaitront pas le media screen. Il faudra donc recourrir à des commentaires conditionnels (merci Microsoft :D).

  1. <style type="text/css" media="screen print projection tv">
  2. @import "/css/global.css";
  3. </style>
  4. <style type="text/css" media="print">
  5. @import "/css/print.css";
  6. </style>
  7. <style type="text/css" media="handheld">
  8. @import "/css/handheld.css";
  9. </style>
  10. <!--[if IE]>
  11. <style type="text/css" media="all">
  12. @import "/css/global.css";
  13. </style>
  14. <![endif]-->

Il est aussi possible d'utiliser des selecteurs à l'intérieur d'un fichier css :

  1. @media print {
  2. body{font-size:10pt;}
  3. }
  4. @media screen {
  5. body{font-size:12pt;}
  6. }
  7. @media screen, print {
  8. body{line-height:1.2;}
  9. }

Référence : http://www.yoyodesign.org/doc/w3c/css2/media.html

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.

page 2 de 2 -