S'abonner au Flux RSS

samedi 12 juin 2010

Deletion confirmation with ASP.NET MVC

Here is my approach for deleting stuff with ASP.NET MVC 2.

As mentioned here, the default Delete view isn't quite correct. What I wanted is a deletion solution that:

  • is powered with Ajax for a better user experience
    • we will make a HTTP DELETE on /Items/Delete/12 to delete item #12
  • is accessible for non-JS enabled browsers (we need a confirmation form)
    • when confirmed, the deletion occurs with HTTP POST on /Items/Delete/12 to delete item #12

With those specifications, we can write the following (wrong) controller code:

  1. public class ItemsController : Controller
  2. {
  3. [HttpGet]
  4. public ActionResult Delete(int id) {
  5.  
  6. ViewData.Model = new ConfirmFormModel {
  7. Id = id.ToString(),
  8. BackAction = "Index"
  9. };
  10.  
  11. return View();
  12. }
  13.  
  14. [HttpDelete]
  15. [HttpPost]
  16. public ActionResult Delete(ConfirmFormModel model) {
  17. ViewData.Model = model;
  18.  
  19. // business action here
  20.  
  21. // if we use Ajax, backaction will be null and have
  22. // to prevent a secondary GET request
  23. return model.BackAction == null ? null : RedirectToAction(model.BackAction);
  24. }
  25.  
  26. }
  1. /// <summary>
  2. /// Simple model class to store the Id for a confirmation form.
  3. /// </summary>
  4. public class ConfirmFormModel {
  5.  
  6. /// <summary>
  7. /// Item's ID
  8. /// </summary>
  9. public string Id { get; set; }
  10.  
  11. /// <summary>
  12. /// Confirmation message.
  13. /// </summary>
  14. public string Message { get; set; }
  15.  
  16. /// <summary>
  17. /// The controller action to redirect to if the user wants to cancel.
  18. /// </summary>
  19. public string BackAction { get; set; }
  20.  
  21. }

A created a little model class to store the confirmation message and the item ID; this way I can use it all over my project. You can notice the [HttpDelete] and [HttpPost] on the second Delete() method. Obviously this won't work as asked here. You have to create your own attribute.

So I created the related views with (not-included) javascript. Here is the index:

  1. <!-- Index page -->
  2.  
  3. <ul>
  4. <% for (int i = 0; i < 10; i++) { %>
  5. <li><%= Html.ActionLink("Delete #" + i, "Delete", new { id = i }, new { @class = "deleteLink" })%></li>
  6. <% } %>
  7. </ul>

The delete page where I include a generic partial-view:

  1. <!-- Delete page -->
  2.  
  3. <h3>Confirmation</h3>
  4.  
  5. <% Html.RenderPartial("ConfirmForm", Model); %>

Finally, the partial view:

  1. <!-- Delete form in a partial view -->
  2.  
  3. <% Html.BeginForm(); %>
  4. <fieldset>
  5. <legend>Confirmation</legend>
  6.  
  7. <p><%= Html.Encode(Model.Message ?? "Are you sure you want to delete this?")%></p>
  8.  
  9. <p>
  10. <%= Html.HiddenFor(m => m.Id) %>
  11. <%= Html.HiddenFor(m => m.BackAction) %>
  12. <%= Html.ActionLink("Cancel", Model.BackAction ?? "Index") %>
  13. <input type="submit" name="Continue" value="Continue" />
  14. </p>
  15. </fieldset>
  16. <% Html.EndForm(); %>

Now we have a working solution to confirm some action on a website. Sources attached...

mardi 21 juillet 2009

Nouveautées de Silverlight 3

Silverlight 3 étant sortit il y a quelques jours, je vais vous en parler un petit peu.

Je vous rapelle que Silverlight est un plugin pour navigateur ressemblant (du point de vu utilisateur) à Adobe Flash et est développé par Microsoft. Les principaux atouts de Silverlight sont les suivants :

  • C'est un format ouvert (XAML) donc théoriquement compatible avec n'importe quel OS et toutes architectures (x86, x64...).
  • Des logiciels de développement gratuits existent (Visual Studio Express). Le XAML étant un format XML, un éditeur de texte suffit presque à créer un composant.
  • L'utilisation du XAML permet à l'application d'être portée sous forme de fenêtre grâce à WPF. (Flash le permet via Adobe Air mais il est difficile de trouver une version x64 pour GNU/Linux... (en fait, il n'y en a pas))

Je vous invite à consulter le web pour plus de détails.

Au passage, voici un White paper édité par Julien Dollon regrouppant les nouveautées de la version 3.

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>

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

- page 1 de 2