• Billet écrit dans : Découverte PHP, Symfony 03.10.2009 4 Réactions !!

    J’ai (re)découvert un truc vraiment sympathique au boulot c’est le système de behavior doctrine intégré à symfony.

    Hein ? Mais à quoi ça sert ?

    Ce que j’en retiens c’est que cela peut permettre d’automatiser certaines actions (répétitives) à l’enregistrement en base, et donc d’enrichir son modèle et deux coup de cuillère à pot.

    Prenons un exemple, vous devez faire un site basé sur la créations de contenus par vos utilisateurs. Ils peuvent écrire des billets, commenter, s’envoyer des messages privés, gérer un annuaire .. bref un site où l’on doit quasiment tout relié à un utilisateur. Chaques tables auraient donc au moins un « user_id » comme clée étrangère ce qui implique dans vos actions d’associer l’utilisateur courant à l’objet pour le sauvegarder .. et ce pour chaque table … lourd non ?

    Hé bien grâce aux behaviors vous pouvez sortir ce comportement générique dans des classes et avec seulement de la configuration au niveau de votre schéma, vous pouvez associer ce comportement à n’importe quel table. L’exemple que j’ai pris est tiré du behavior « Signable » du plugin sfDoctrineActAsSignablePlugin.

    Configuration

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Item:
      actAs:
        Signable:
      columns:
        id:
          type:             integer
          primary:          true
          autoincrement:    true
        champ1:             string(255

    Comment ça marche ?

    Donc si on résume, il faut dire à Doctrineque l’on va rajouter des colonnes .. et que l’on veut être prévénu lors de l’insertion en base pour associé nos actions. Donc avec seulement 2 classes, une de définition et une d’écoute, on peut s’en sortir et crée notre behavior.

    Lors de la configuration, en rajoutant « actAs : Signable », Doctrine va chercher une classe de définition qui ira  étendre une classe Doctrine_Template. Par convention il ira chercher une classe nommé Doctrine_Template_Signable. Le rôle de cette classe est de déclarer ses colonnes et de rajouter une écoute, un listener, vers l’autre classe d’actions.

    Pour mon exemple, je vais volontairement raccourcir les classes du sfDoctrineActAsSignablePlugin et prendre pour acquis que vos utilisateurs sont gérés via sfGuardDoctrinePlugin.

    Doctrine_Template

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    class Doctrine_Template_Signable extends Doctrine_Template {
     
      // Définitions des relations
      public function setUp() {
      // Bim rajoute une clée étrangère sur sfGuard
      $this->hasOne('sfGuardUser as Author', array(
                'local' => 'created_by',
                'foreign' => 'id'
                )
                );
      }
     
     public function setTableDefinition() {
     
      // Bim une colonne en plus
      $this->hasColumn('created_by', 'integer', 4, array(
              'type' => 'integer',
              'length' => '4',
         ));
     
      // Lien avec notre 2eme classe .. on passe le nom de la colonnette rajouté
      $this->addListener(new Doctrine_Template_Listener_Signable('created_by));
      }
    }

    Là pour l’exemple aucune configuration au niveau du schéma n’est possible mais c’est facile à rajouter via d’un tableau d’options et le constructeur suivant :

    1
    2
    3
    
      public function __construct(array $options = array()) {
        $this->_options = Doctrine_Lib::arrayDeepMerge($this->_options, $options);
      }

    Doctrine_Template_Listener

    Nous avons vu que notre Template rajoute un listener vers notre 2e classe en lui passant la colonne à surveiller (dans la vrai vie, un tableau d’options ..). Le rôle de notre listener de pouvoir agir avant/après l’insertion/édition d’un objet .. facile :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    
    class Doctrine_Template_Listener_Signable extends Doctrine_Record_Listener {
     
      protected $_colonette = "created_by";
     
      public function __construct($colonne) {
        $this->_colonette = $colonne;
      }
     
      public function preInsert(Doctrine_Event $event) {
          $createdName = $this->_colonette;
     
          // recupère l'objet appellant :
          $objet = $event->getInvoker();
     
          // Affectation de valeur
           $objet->$createdName = $this->getUserId();
      }
     
      public function getUserId() {
         // Echappe le mode cli
         if (0 != strncasecmp(PHP_SAPI, 'cli', 3)) {
           // L'user courant
           return sfContext::getInstance()->getUser()->getAttribute('user_id', null, 'sfGuardSecurityUser');
         } else {
          return null;
         }
      }
     
      public function preUpdate(Doctrine_Event $event) {
      }
     
      public function postUpdate(Doctrine_Event $event) {
      }
     
      public function postInsert(Doctrine_Event $event) {
      }
     
      // A tester : public function Delete(Doctrine_Event $event) ..
    }

    Vous n’avez plus qu’a rebuilder votre model et magie ça doit marcher !!

    Vu que l’on a fait une relation de type One-to-many sur sfGuard vous pouvez accéder à l’utilisateur sfGuard via la propriété Author sur n’importr quel table marqué comme « Signable »

    1
    
      echo $objet->Author->id;

    Voilà .. simple au final non ? Ah vous de créez le votre, :p

    Comme on dirait au boulot « Amaaziiiing !! »

    Billet écrit dans : Découverte PHP, Symfony 03.10.2009 4 Réactions !!
  • Billet écrit dans : Découverte PHP, Flex Flash Floush 30.01.2009 4 Réactions !!

    Pour un cours de Flex, il nous avait été demandé de créer une application très simple constitué de deux écrans pour nous apprendre à manipuler les « states », les composants personnalisés, le « data binding » etc.

    Le sujet de l’application était d’afficher des images en fonction d’une ville – en vue de faire du data binding sur un XML « statique » de villes – et de récupérer des images issues d’un XML dynamique via l’objet HTTPService.

    Alors quitte à faire du dynamique, autant interroger directement un web service existant en vue de récupérer pleins d’images sans se prendre la tête. Et là j’ai pensé à FlickR et sa monstrueuse API. Après 5mn montre en main j’ai eu ma clé pour accèder à l’API et 4mn après je découvrait phpFlickR.

    Upload de la librairie et voici mon bout de script qui me renvoit suivant deux paramètres en $_GET un joli XML près à être utilisé en Flex.

    • $_GET['town'] est le terme rechercher dans l’api FlickR sur les tags et le text qui commente une photo.
    • $_GET['max'] est le nombre de photos qu’il faudra retourner.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    require_once("phpFlickr.php");
    $flickR = new phpFlickr("ta_cle_de_connection_flickR");
     
    // 10 résultat par défaut ..
    if(isset($_GET['max']))
    $max = $_GET['max'];
    else $max=10;
     
    $search = array("tags"=>$_GET['town'],'per_page'=>$max, "tag_mode"=>"any",'text' => $_GET['town']);
    $tab = $flickR->photos_search($search);
     
    // On renvoit un XML à Flex
    header("content-type: application/xml");
     
    // La balise qui va bien
    echo "<?xml version="1.0" encoding="utf-8" ?>";
     
    for ($i = 0; $i != $max; $i++)
    {
            // on s'assure d'avoir des photos valides
    	if($tab['photo'][$i]['id'] != "")
    	{
    	// Simple de créer des urls FlickR non ?
    	$url = $flickR->buildPhotoURL($tab['photo'][$i],"thumbnail");
    	$link = $flickR->buildPhotoURL($tab['photo'][$i],"medium");
     
    	echo "<image><url>".$url."</url><urlLarge>".$link."</urlLarge></image>";
    	}
    }

    La partie Flex est tout aussi simple, voici la partie essentielle qui nous intéresse :

    ?View Code ACTIONSCRIPT
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    
    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="searchPhoto('france',20)">
     
    <mx:Script>
    <![CDATA[
    import mx.rpc.http.HTTPService;
    import mx.rpc.events.ResultEvent;
    import mx.collections.ArrayCollection;
     
    [Bindable]
    private var servicePhoto:ArrayCollection = new ArrayCollection(); 
     
     
    private function searchPhoto(search:String,max:int):void
    {
    	var modService:HTTPService = new HTTPService();
    	modService.method = "get";
    	modService.url = "http://oni-ecchi.info/labo/FlexPhotos/service.php";
     
    	var parameters:Object = new Object();
    	parameters.town = search;
    	parameters.max = max;
    	modService.request = parameters;                
    	modService.send();
    	modService.addEventListener(ResultEvent.RESULT,onDataCharged);                
    }
     
    private function onDataCharged(e:ResultEvent):void
    {
    	servicePhoto = new ArrayCollection();
    	servicePhoto = e.result.root.image as ArrayCollection;		
    	vignettes.dataProvider = e.result.root.image as ArrayCollection;
    }
     
    ]]>
    </mx:Script>
    <mx:TileList id="vignettes" dataProvider="{servicePhoto}" width="481" height="279" columnWidth="110" rowHeight="110" columnCount="4" horizontalCenter="0" paddingRight="5" verticalCenter="0">
        <mx:itemRenderer>
       		<mx:Component>
       			<mx:Image  source="{data.url}" verticalAlign="middle" horizontalAlign="center" />
       		</mx:Component>
        </mx:itemRenderer>       
    </mx:TileList>
     
     
    </mx:Application>

    Ce n’est qu’un exemple très simple. Dans le fichier source qui va suivre, j’ai un peu plus travaillé la chose en utilisant un composant de chargement d’image sympathique, un spinner de chargement 2.0 et enfin la gestion des states (très simple).

    Voilà, c’est tout pour aujourd’hui

    Billet écrit dans : Découverte PHP, Flex Flash Floush 30.01.2009 4 Réactions !!
  • Billet écrit dans : Découverte PHP 12.12.2008 Aucune réponse à cet article.

    Aller sur http://blog.jaysalvat.com/articles/model-baker-une-interface-graphique-a-la-creation-dapplications-cakephp.php ou regarder simplement son screencast :

    Model Baker in action from Jay Salvat on Vimeo.

    Ca a l’air génial :) Dommage que ça soit seulement pour mac pour l’instant, mais c’est très prometteurs ! Apres un tour sur Symfony, sur Zend, faudrait que j’aille voir CakePHP donc :)

    Billet écrit dans : Découverte PHP 12.12.2008 Aucune réponse à cet article.
CV Guillaume chave