My Developpement Blog

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

mardi, janvier 12 2010

La mission Zelnik - 2ere partie - La taxe Google

Ce billet fait suite à celui ci parlant de la carte musique pré-payée rapporté par la mission Zelnik

vendredi, janvier 8 2010

La mission Zelnik - 1ere partie - La carte prépayée

La carte prepayé pour acheter la musique.

Descriptif de la carte

Cette carte est co-financée par

  • les sociétés vendant de la musique en ligne et participant à l’opération;
  • l’acheteur de musique;
  • l’Etat.

Son but serait de changer le comportement des jeunes enclin à télécharger gratuitement de la musique vers l’achat de musique en ligne.

Quelques interrogations concernant cette carte.

  1. Pourquoi limité cette carte à la musique, qu’en est il de la vidéo et des autres média tel que les écrits ?
  2. Pourquoi l’Etat (donc nous les contribuables) doit-il encore mettre la main à la poche ?
  3. Pourquoi les sociétés qui propose de la musique choisissent ce type de financement alors que d’autres choix s’offrent à eux ?

Mes réponses à ces questions.

Concernant le fait que cette carte soit uniquement fait pour le téléchargement de la musique.

Les personnes de la mission sont essentiellement issue de ce monde audio, serait-ce du nombrilisme ou alors les retranscriptions du compte-rendu qui se focalise que sur l’audio. J’espère cependant que cela simplement une manière de voir si le fonctionnement d’une telle carte peut être adopté et que ce modèle est efficace.

Concernant la prise en charge de l’Etat de cette carte.

Je ne comprends pas encore la raison pour laquelle l’Etat dépense autant de ressource dans cette problèmatique ainsi que dans la manière avec laquelle, il essaye de la solutionner.
Je conçois que l’Etat perd des revenus (la fameuse TVA) qui pourrait être issue d’un téléchargement légal ou encore de l’achat du bien physique. Mais pourquoi encore rajouter une perte financière en finançant en partie (20€ sur les 50€ de la carte). En effet, avec une TVA à 19.6%, celle ci rapporte environ 20€ pour 100€ d’achat hors ici l’Etat finance 40€ pour 100€ d’achat soit le double de ce que peut lui rapporter cette carte. La dette française ne risque pas d’être reduite.
Je veux bien croire que l’Etat prévoit que la carte ne soit pas le seul facteur déclenchant d’achat et que ceux ci repartiront, mais mes différentes lectures me font dire que le prix élevé des oeuvres audio est le frein majeure à l’acte d’achat. Cependant, je ne suis pas sûr que les jeunes à qui s’adressent cette carte s’aperçoivent que la carte leur permet de payer seulement 40% du prix du morceau acheté. Car pour eux, le morceau de musique restera au même prix.
L’Etat cherche t’il par ce biais à relancer l’économie locale, je me permet d’avoir quelques doutes. D’une part, je ne pense pas que les plateformes de téléchargement soit située chez nous ou quelles aient un fort potentiel d’emploi en France. De plus, l’argent dégagé par ces plateformes ne risque pas d’être réinvesti en France, les sociétés les exploitant n’étant pas ici. Pour moi, cela reste un financement à perte, une subvention qu’il va falloir faire payer aux contribuables et donc faut il croire encore à une hausse des impôts à moins que ce coût soit financé par ce qui va être énoncé dans le 2ème billet traitant de la mission Zelnik

Concernant le choix d’une carte prépayée financée en partie par les commerçant de musique en ligne.

Croient ils que les jeunes augmenteront leur achat via la carte ? Cela est fort probable.
Faîtes faire une commission par des gens partisan et ceux ci vous proposeront le meilleur modèle économique pour eux. En effet, au lieu de réduire de 10 à 20% le prix de ventes, ce qui correspond environ à ce qu’ils risquent de co-financer soit de 10 à 20 centimes d’euro par morceau, Ceux ci veulent, en plus, que l’Etat finance, on l’a vue 20% de leur vente déduction faite de la TVA, la musique achetés sur le web. Autrement dit, l’état donne à ces entreprises l’équivalent de 20% de leur CA. J’ai largement exagérer ces chiffres car leur revenu ne provient pas seulement de la vente via les cartes, mais seule l’idée d’entreprises privées correctement rémunérées par l’Etat reste intéressante.

vendredi, octobre 23 2009

Affaire Jean Sarkozy : Un coup de com bien orchestré

Juste une petite réflexion en passant.

1ere hypothèse

Aucune gronde concernant la candidature de J. Sarkozy au poste de président de l’EPAD => Un beau poste de prestige pour un jeune de 23 ans commençant la politique.

2ème hypothèse

Gronde de la population (politique ou non) => retrait de la candidature et un J. Sarkozy magnanime et un regain de popularité.

Dans tout les cas, il ressortait gagnant. Je pense que rien n’a été laissé au hasard dans cette affaire et l’UMP prépare la route au dauphin.

Edit

Je me sens moins seul

Morale

La communication, le développement, même combat : il ne faut pas prendre les gens pour des cons mais ne pas oublier qu’ils le sont. Et apparement, c’est plus facile pour la communication

mercredi, octobre 21 2009

Atelier sur la sécurité web

Cela fait maintenant 15 jours que les ateliers Paris Web 2009, et le premier atelier que j’ai suivi concerné la sécurité des sites webs.

L’atelier avait un fort potentiel mais les différences de niveau des différents publics (intégrateurs, développeurs, décideurs, …) ont empêché de pousser un peu plus loin la réflexion. Cet atelier a donc été, pour moi, qu’une piqûre de rappel.

La sécurité

  1. Elle doit être prise en compte à toutes les étapes de la création, en gros la sécurité n’est pas une surcouche
  2. Il faut minimiser la surface d’attaque (ex: les plugins/modules supplémentaire d’un programme sont autant de nouvelles portes d’entrée pour le cracker)
  3. Limiter la portée des erreurs.
  4. Utiliser une gestion restrictive des droits
  5. Permettre une maintenance facile, ca permet de faciliter la correction d’un bug
  6. Choisir un niveau intermédiaire dans la verbosité des logs (trop -> illisible, trop peu -> inutilisable)
  7. Ne jamais croire les données non maitrisée (provenant de l’utilisateur, du navigateur et de la base de donnée en autre)

L’exploit

  1. Détection de faille, elle peut être automatiser
  2. Utilisation de la faille critique (injection SQL/ XSS / CSRF / RFI)†
  3. But : Prendre le contrôle du serveur, récuperer des données, DOS

Solution (liste non exhaustive)

  1. Valider toutes les données
  2. N’afficher les erreurs applicatifs (SQL/PHP/…) qu’en phase de développement
  3. Utiliser au max les procédures stockées ou paramétrées
  4. Pour contrer les XSS, utiliser des white-list
  5. Utilisation des tokens pour les CSRF

Le gros rappel important est surtout à ce niveau. MM. les décideurs

  • veuillez former vos développeurs de manière continue, les techniques d’exploit évolues
  • faites des audits de sécurité

Complément d’information :

ND_Template : Un moteur de template

ND_Template est un moteur de gabarit ou template engine pour les anglophones. Ce développement avait pour contrainte d’être fonctionnel et avoir un code court et clair.

Je n’ai pas encore tester le code en production donc il peut y avoir des problèmes d’utilisabilité ou de performance.

Je rajouterai un How to dès que j’aurais un peu plus de temps pour le rédiger

jeudi, octobre 15 2009

Le paradoxe de ZendX_JQuery et Zend_Dojo

On parle beaucoup de découplage que ce soit niveau front-end ( HTML + CSS + Javascript ), chacun ayant une utilité propre. Je développerai cela dans un prochain billet.
mais aussi coté serveur et en particulier lors de l’utilisation du design pattern MVC

Et là, nous voyons apparaître Zend_Dojo et ZendX_JQuery, qui permet de coupler du javascript et du PHP.

Que l’on m’explique l’intérêt de faire cela ?

Je vais pour ma part vous expliquer les inconvénients que j’entrevois :

  • Du code PHP mort dans le cas d’un client n’ayant pas javascript activé. Pour moi, c’est une perte de temps serveur, des calculs inutiles même si on peut utiliser des caches à plusieurs niveau (opcode ou autres)
  • Une modification fonctionnelle du javascript doit faire intervenir le développeur PHP voire potentiellement remettre en cause le développement d’une partie du back-end,
  • Le développeur back-end et le développeur front-end ont 2 métiers différents, complémentaires mais différents.

mercredi, octobre 14 2009

ND_CMS : Réflexions concernant le module User

Le Module User

Ce module doit permettre la création/modification/suppression de comptes utilisateurs ainsi que leur identification. Personnellement, je pense que ce module ne doit gérer que peu de données : - Login (doit être unique) - Mot de passe (enregistré sous forme de Hash) - Date de création - Date d’activation - Email (doit être unique)

Pourquoi ces choix

Email + Login

J’ai décidé de ne pas prendre l’email en tant qu’identifiant du compte, car cela permet à l’utilisateur de choisir son propre identifiant qui peut être plus court que son email.

Mot de passe hashé

Pourquoi choisir de hasher le mot de passe.

Pour 2 raisons :

  • le système n’a pas besoin de connaître le mot de passe de l’utilisateur, il doit simplement savoir si le mot de passe est le valide. Cela évite une faille de sécurité en cas d’intrusion dans la base. Le mot n’étant pas “en clair”, celui-ci n’a que peu d’intérêt.
  • pour sécuriser les utilisateurs, beaucoup de gens gardent le même mot de passe, quelque soit l’application qu’ils utilisent.
Comment sera hashé le mot de passe.

Le hashage sera obligatoire mais l’administrateur de l’application aura la possibilité de choisir la manière dont il veut gérer cela.

Le grain de sel sera paramétrable

  • choix du champs permettant de faire le générer ( Login / Date de création / email )
  • choix de la méthode de hash ( md5 / sha1 / autre ) du champ
  • choix dans la taille du grain de sel

Le hash se fera ensuite

  • position du grain de sel (avant ou après le mot de passe)
  • choix de la méthode de hash ( md5 / sha1 / autre )

Ce système empêche qu’un même mot de passe est le même hash.

Pourquoi avoir une date de création et une date de validation

Ce choix se justifie par le simple fait de purge de la base, un compte n’ayant pas été validé X jours après sa création est probablement un compte mort, donc un espace perdu.

Comment gérer les autres données

A ce système d’identification peut se greffer 2 autres tables permettant de gérer un nombre infini de données utilisateurs supplémentaires. Cela permet une malléabilité a l’administrateur d’une instance du CMS dans le choix des données utilisateurs qu’il souhaite. Le système n’ayant besoin à la base que de pouvoir identifier l’utilisateur

la table User_Field

Cette table permet à l’administrateur de choisir les informations de l’utilisateur qu’il souhaite La table contiendrait 3 voire 4 champs hors identifiant.

  • name, nom pour l’administrateur
  • i18n_name, variable que remplacera le système d’internationalisation
  • required, permet de rendre obligatoire un champ
  • validator, devrait permettre de valider ou non l’information saisie (Peut être externaliser cela dans un autre table afin de pré créer des règles de validation)

la table User_Data

Cette table permet d’associer un utilisateur, une donnée et sa valeur.

Voilà, je pense que tout est dit, si vous avez des remarques à faire, n’hésitez pas

ND_CMS : mes réflexions concernant l'arborescence

ND_CMS doit être, pour moi, une base me permettant de développer facilement un site web.

Je pars du principe que j’utiliserai le Zend Framework pour le réaliser, Cependant l’architecture proposée ne me semble pas la plus pertinente.

Proposition d’arborescence

Libraries
   Zend
   ND
Htdocs  // Seul répertoire accessible par le Web 
   index.php
   .htaccess // potentiellement externalisée dans la configuration apache
Application // Répertoire ou sont stockées les informations propres aux applications
     MonAppli1
         Config  // fichiers de configuration propre à l'application=         
         Cache  // Répertoire parent des différents caches de l'application
             Db     
             Page             
         Datas  // Données propres à l'application (c'est le SEUL répertoire accessible par FTP pour le client)
             Layout  // fichiers concernant la présentation 
             Js
             Css
             Files
          I18n   // Fichiers concernant l'internationalisation propre à l'application
          Session // Répertoire permettant de stocker les informations de session, si les sessions ne sont pas gérer en base de données
          Log // Répertoire ou se situe les logs de l'application
     MonAppli2
         Config
         Cache
             Db     
             Page        
         Datas
             Js
             Css
             Files
          I18n
          Session
Common  // Stockage des informations communes à toutes les applications (les données peuvent être surchargées par les données applications)
     I18n // fichiers d'internationalisation transversaux message d'erreur applicatifs (ex:Erreur 404 ou des validateurs de formulaire)
     JS    // répertoire où sera stocké le(s) framework(s) JS utilisé(s) probablement jquery
     CSS // répertoire où sera stocké le(s) framework(s) CSS utilisé(s) probablement blueprint
Modules // Répertoire où seront stockés les différents modules
    Module
        Controllers
        Views
             Scripts
             Helpers
        Data
             I18n
             Db
             Js
        Models
             DbTable
             Mapper
         Forms
         Services

Cette architecture permet

  • de n’avoir qu’un point d’entré Web non corruptible par le client
  • de compartimenter les bibliothèques, les modules, les données d’applications
* les données d'applications sont compartimentées afin d'empêcher au mieux les interactions entres elles 
* seul l'accès au répertoire Data est faisable via FTP (enfin selon configuration de celui-ci), les autres dossiers n'étant modifiable que par les interfaces web dédiés hors cache

L’inconvénient de cette architecture est que la mise à jour d’un module ne doit pas agir sur la BDD ou alors cette modification de la BDD ne doit pas être bloquant pour l’utilisation du module

Et vous, comment feriez vous ? Que pensez vous d’une telle architecture ?

jeudi, août 27 2009

Microsoft et l'open source

Voila ce que donne Microsoft quand celui ci s’adonne à l’open source

vendredi, août 21 2009

ND_Form

ND_Form est une classe héritant de Zend_Form permettant de ne s’attarder que sur la configuration du formulaire via fichier Ini.

vendredi, juin 26 2009

A garder sous le coude

Quelques liens qui peuvent être utiles :

* http://www.tripwiremagazine.com/tools/design/40-must-have-cheat-sheets-for-effective-web-designers.html
* http://www.tripwiremagazine.com/design/css-techniques/20-css-data-visualization-techniques.html

vendredi, avril 17 2009

TODO List

A lire :

  • http://www.w3.org/TR/xmlschema-0/

A faire :

  • modifier ma classe de gestion d’arborescence avec représentation intervallaire
  • mettre en place un CMS avec le Zend Framework
  • faire une application pour Mac de gestion de Film et une de gestion de Livre avec une portabilité prévue vers Ipod/Iphone voire un site web

jeudi, avril 16 2009

Classe ZF permettant de faire des representations intervallaire

Si vous utilisez le Zend Framework et que vous cherchez à représenter une arborescence type Menu, Organigramme, …

C’est juste une simple mise en forme de cet article concernant la représentation intervallaire d’une arborescence

Il me reste la gestion des niveaux à prendre en compte, histoire de faire des filtres supplémentaire. Mais bon, chaque chose en son temps.

Comme toujours, je suis tout ouïe aux remarques voire même aux critiques

Appel de la classe

  1. <?php
  2.  
  3. class Kernel_Models_Data_Role_Table extends ND_Db_Table_Hierarchical_Table{
  4.  
  5. protected $_name = 'role';
  6. protected $_rowClass = 'Kernel_Models_Data_Role_Row';
  7. protected $_left = 'bg'; // defini la borne gauche (obligatoire)
  8. protected $_right = 'bd'; // defini la borne droite (obligatoire)
  9. protected $_level = 'level' // defini la profondeur de l'arborescence (obligatoire)
  10.  
  11.  
  12. }

Et pour ceux qui ont la flemme de télécharger le fichier

  1. <?php
  2. /**
  3.  *
  4.  * @author ndesaleux
  5.  * @package ND
  6.  * @subpackage Db
  7.  *
  8.  */
  9.  
  10. class ND_Db_Table_Hierarchical_Table extends Zend_Db_Table{
  11.  
  12. protected $_left = null ;
  13. protected $_right = null ;
  14. protected $_level = null ;
  15.  
  16. /**
  17.   *
  18.   * @param (array) $config
  19.   * @return null
  20.   */
  21. public function __construct($config = array()){
  22. parent::__construct($config);
  23. if (null == $this->_left) throw new ND_Db_Table_Hierarchical_Exception(ND_Db_Table_Hierarchical_Exception::NO_LEFT_BORDER_FIELD_DEFINED);
  24. if (null == $this->_right) throw new ND_Db_Table_Hierarchical_Exception(ND_Db_Table_Hierarchical_Exception::NO_RIGHT_BORDER_FIELD_DEFINED);
  25. if (null == $this->_level) throw new ND_Db_Table_Hierarchical_Exception(ND_Db_Table_Hierarchical_Exception::NO_LEVEL_FIELD_DEFINED);
  26. }
  27.  
  28. /**
  29.   *
  30.   * @param (int) $id
  31.   * @return (mixed) false|Zend_Db_Table_Row_Abstract
  32.   */
  33. public function getById($id) {
  34. $rows = $this->find($id);
  35. if ($rows) {
  36. return $rows->current();
  37. }
  38. return false;
  39. }
  40.  
  41. /**
  42.   * Delete an element get by id (this delete also node and leaf)
  43.   * Update bor
  44.   * @param (int) $id
  45.   * @return (boolean)
  46.   */
  47. public function deleteById($id){
  48.  
  49. $elt = $this->getById($id) ;
  50. if ($elt instanceof Zend_Db_Table_Row_Abstract ){
  51.  
  52. $left = $this->_left;
  53. $right = $this->_right;
  54. $dif = $elt->$right- $elt->$left + 1;
  55. // on supprime les elements noeuds et feuilles
  56. $dlElt = 'DELETE FROM '.$this->_name.'
  57. WHERE '.$this->_left.' >= '.$elt->$left.'
  58. AND '.$this->_right.' <= '.$elt->$right ;
  59. // MAJ des bornes droites
  60. $upRb = 'UPDATE '.$this->_name.'
  61. SET '.$this->_right.' = '.$this->_right.' - '.$dif.'
  62. WHERE '.$this->_right.' >= '.$elt->$left ;
  63. // MAj des bornes gauches
  64. $upLb = 'UPDATE '.$this->_name.'
  65. SET '.$this->_left.' = '.$this->_left.' - '.$dif.'
  66. WHERE '.$this->_left.' > '.$elt->$left ;
  67.  
  68. try{
  69. $this->_db->beginTransaction();
  70. $this->_db->prepare($dlElt)->execute();
  71. $this->_db->prepare($upRb)->execute();
  72. $this->_db->prepare($upLb)->execute();
  73. $this->_db->commit();
  74. return true;
  75. }catch(Exception $e){
  76. $this->_db->rollBack();
  77. return false ;
  78. }
  79. }
  80.  
  81.  
  82. }
  83.  
  84. /**
  85.   * Add a leaf at the node $id
  86.   *
  87.   * @param (array) $data
  88.   * @param (int) $id
  89.   * @return (mixed) false|int
  90.   */
  91. public function insertByParent(array $data, $id){
  92. $elt = $this->getById($id);
  93. if ($elt instanceof Zend_Db_Table_Row_Abstract ){
  94. $right = $this->_right;
  95. $level = $this->_level;
  96.  
  97. // MAJ des bornes droites
  98. $upRb = 'UPDATE '.$this->_name.'
  99. SET '.$this->_right.' = '.$this->_right.' + 2
  100. WHERE '.$this->_right.' >= '.$elt->$right ;
  101. // MAj des bornes gauches
  102. $upLb = 'UPDATE '.$this->_name.'
  103. SET '.$this->_left.' = '.$this->_left.' + 2
  104. WHERE '.$this->_left.' >= '.$elt->$right ;
  105.  
  106. $inElt = 'INSERT INTO '.$this->_name.'
  107. ( '.$this->_left.', '.$this->_right.', '.$this->_level.' )
  108. VALUES ( '.$elt->$right.', '.($elt->$right+1).', '.($elt->$level+1).' ) ';
  109.  
  110. try{
  111. $this->_db->beginTransaction();
  112. $this->_db->prepare($upRb)->execute();
  113. $this->_db->prepare($upLb)->execute();
  114. $this->_db->prepare($inElt)->execute();
  115. $this->_db->commit();
  116.  
  117. $oElt = $this->fetchRow($this->_left.' = '.$elt->$right.' AND '.$this->_right.' = '.($elt->$right+1));
  118.  
  119. // clean data
  120. foreach( $this->_primary as $primaryK ){
  121. unset( $data[$primaryK] );
  122. }
  123. unset( $data[$this->_left] );
  124. unset( $data[$this->_right] );
  125. unset( $data[$this->_level] );
  126. $oElt->setFromArray($data);
  127. Zend_Debug::dump($data);
  128. return $oElt->save();
  129.  
  130. }catch(Exception $e){
  131. $this->_db->rollBack();
  132. }
  133. }
  134. return false ;
  135. }
  136.  
  137. /**
  138.   * Update a node or a leaf, left and right border can not be update
  139.   *
  140.   * @param (array) $data
  141.   * @param (int) $id
  142.   * @return boolean
  143.   */
  144. public function updateById(array $data, $id){
  145. unset( $data[$this->_left] );
  146. unset( $data[$this->_right] );
  147. unset( $data[$this->_level] );
  148. $elt = $this->getById($id);
  149. if ( $elt instanceof Zend_Db_Table_Row_Abstract ){
  150. try{
  151. $elt->setFromArray($data);
  152. $elt->save();
  153. return true;
  154. }catch(Zend_Db_Exception $e){
  155. //@todo
  156. }
  157. }
  158. return false;
  159. }
  160.  
  161.  
  162. /**
  163.   * Get node and leaf come from node identified by $id
  164.   * @param (int) $id
  165.   * @param (int) $level optional
  166.   * @return (mixed) array|false
  167.   */
  168. public function getChildren($id, $lvl = null){
  169. $elt = $this->getById($id);
  170. if ( $elt instanceof Zend_Db_Table_Row_Abstract ){
  171. $left = $this->_left;
  172. $right = $this->_right;
  173. $select = $this->select()->from($this->_name)
  174. ->where($this->_left.' > ? ', $elt->$left )
  175. ->where($this->_right.' < ? ', $elt->$right );
  176. if ( $lvl !== null && (int) $lvl > 0 ){
  177. $level = $this->_level ;
  178. $select->where($this->_level.' <= ? ', $elt->$level + (int) $lvl );
  179. }
  180. return $select->query()->fetchAll();
  181. }else{
  182. return false;
  183. }
  184. }
  185.  
  186.  
  187. /**
  188.   * get parent of the element
  189.   * @param (int) $id
  190.   * @return (mixed) Zend_Db_Table_Row_Abstract|false
  191.   */
  192. public function getParent($id){
  193. $elt = $this->getById($id);
  194. if ( $elt instanceof Zend_Db_Table_Row_Abstract ){
  195. $left = $this->_left ;
  196. $level = $this->_level ;
  197. $select = $this->select()->from($this->_name)
  198. ->where($this->_left.' < ?',$elt->$left )
  199. ->where($this->_level.' = ?',$elt->$level-1)
  200. ->order($this->_left.' DESC' )
  201. ->limit(1);
  202. return $select->query()->fetchAll();
  203. }else{
  204. return false;
  205. }
  206. }
  207.  
  208.  
  209. /**
  210.   * count children of an element
  211.   * @param $id
  212.   * @return (mixed) false|int
  213.   */
  214. public function countChildren($id){
  215. $return = $this->getChildren($id) ;
  216. return $return === false ? false : count($return) ;
  217. }
  218.  
  219. /**
  220.   * return number of node of the element $id
  221.   * @param (int) $id
  222.   * @return (mixed) false|int
  223.   */
  224. public function countNode($id){
  225. $oElt = $this->getById($id);
  226. if ( $oElt instanceof Zend_Db_Table_Row_Abstract ){
  227. $left = $this->_left ;
  228. $right = $this->_right ;
  229. $select = $this->select()
  230. ->from($this->_name, array('count(id) as nb') )
  231. ->where($this->_right.' - '.$this->_left.' <> 1 ')
  232. ->where($this->_left.' > ? ' , $oElt->$left )
  233. ->where($this->_right.' < ? ', $oElt->$right );
  234. return $select->query()->fetchColumn(0);
  235. }
  236. return false ;
  237. }
  238.  
  239. /**
  240.   *
  241.   * @param (int) $id
  242.   * @return (mixed) false|int
  243.   */
  244. public function countLeaf($id){
  245. $oElt = $this->getById($id);
  246. if ( $oElt instanceof Zend_Db_Table_Row_Abstract ){
  247. $left = $this->_left ;
  248. $right = $this->_right ;
  249. $select = $this->select()
  250. ->from($this->_name, array('count(id) as nb') )
  251. ->where($this->_right.' - '.$this->_left.' = 1 ')
  252. ->where($this->_left.' > ? ' , $oElt->$left )
  253. ->where($this->_right.' < ? ', $oElt->$right );
  254. return $select->query()->fetchColumn(0);
  255. }
  256. return false ;
  257. }
  258.  
  259. /**
  260.   * Move a subtree (node or leaf are allowed to move)
  261.   *
  262.   * @param (int) $id
  263.   * @param (int) $newParentId
  264.   * @return (boolean)
  265.   */
  266.  
  267. public function moveTree($id, $newParentId){
  268. $oEltToMove = $this->getById($id);
  269. $oEltToReceive = $this->getById($newParentId);
  270.  
  271. if ( $oEltToMove instanceof Zend_Db_Table_Row_Abstract &&
  272. $oEltToReceive instanceof Zend_Db_Table_Row_Abstract ){
  273. $left = $this->_left ;
  274. $right = $this->_right ;
  275.  
  276. if ( $this->countChildren($id) >= 0 ){
  277. $data = $oEltToMove->toArray();
  278. $newId = $this->insertByParent($data, $newParentId);
  279. $children = $this->getChildren($id, 1);
  280. foreach( $children as $child ){
  281. $this->moveTree($child['id'], $newId );
  282. }
  283. $this->deleteById($id);
  284. }
  285.  
  286. }
  287. return false;
  288.  
  289. }
  290.  
  291. }

NB: moveTree est une fonction récursive elle fonctionne de manière atomique mais il peut potentiellement avoir des données orphelines si la procédure est interrompue pour X raisons :’(. Il faut que je regardes comment je pourrais gérer ca de manière transactionnelle, histoire qu’une interruption ne cause aucun soucis.

mercredi, avril 15 2009

Un petit view_helper pour les formulaire

Je recherchais a afficher un récapitulatif des erreurs en début de formulaire. Et ce en sus, de l’affichage classique du formulaire.

Hadopi, article à lire

Je mettrai ici les différentes articles ne semblant pas être de la propagande pro/anti Hadopi mais me semblant être neutre

jeudi, avril 9 2009

In the navy

Je me permet de détourné un peu les mots de Roger Karoutchi (voir article du figaro)  :

Le secrétaire d’Etat aux Relations avec le parlement, Roger Karoutchi, a dénoncé «des actes de flibuste» de la gauche

Il aurait plutôt du dire :
Cette manoeuvre de la gauche est de la flibusterie en vue d’aider ces pirates

Au moins, il y aurait eu un peu d’esprit. Ce que je ne comprends pas, c’est pourquoi, le gouvernement s’entête à vouloir placer une loi :

  1. inapplicable techniquement
  2. contraire à législation européenne
  3. obsolète
  4. cache misère

mardi, mars 3 2009

Bibliotheques JS utiles

http://www.smashingmagazine.com/2009/03/02/40-stand-alone-javascript-libraries-for-specific-purposes/

Il me reste plus qu’a les analyser et faire un petit point dessus

mardi, février 24 2009

Ca arrive aux informaticiens d'avoir de l'humour

http://t37.net/13-citations-droles-l-histoire-programmation.html

Ma préférée reste celle ci.

Aujourd’hui, la programmation est devenue une course entre le développeur, qui s’efforce de produire de meilleures applications à l’épreuve des imbéciles et l’univers, qui s’efforce de produire de meilleurs imbéciles. Pour l’instant, l’univers a une bonne longueur d’avance - Rich Cook

lundi, février 9 2009

A garder sous le coude

Utilitaire JS http://www.smashingmagazine.com/2009/02/08/50-extremely-useful-javascript-tools/

Subversion http://www.simpleentrepreneur.com/2009/03/18/les-operations-de-base-dans-subversion/

lundi, février 2 2009

Aide de vue pour un listing de caractère

Cette aide de vue permet de créer facilement une liste de lien avec 1 lettre en paramètre. Très utile pour réaliser un filtre sur la 1ere lettre d’un listing de personne.

- page 1 de 2