Aller au contenu

Archive de juillet, 2011

2
juil

Création d’un datatype (1ère partie)

Tout comme en POO, les classes de contenu sous eZ sont composées d’attributs typés, on les appelle les datatypes. Il faut savoir que la plateforme en propose nativement un certain nombre qui répondront dans près de 90% des cas à vos besoins. Lorsqu’il devient nécessaire de créer un contenu à l’aide d’une classe eZ, on parle d’objet eZ, nos datatypes deviennent alors des champs à remplir ou des utilitaires beaucoup plus complex (éditeurs de texte riche wysiwyg, matrices etc…).

Pour plus de clarté dans mon article, les classes et objets créés depuis la plateforme seront suivis par un eZ, en revanche, lorsque je parlerai de classe ou d’objet PHP, il n’y aura pas de distinction particulière.

Pour la création d’un datatype, il est donc important de dissocier ce principe de classes/objets eZ, car en PHP, un datatype c’est une classe composée de plusieurs méthodes regroupant tous les traitements qu’il pourra rencontrer tout au long de son utilisation aussi bien coté classe que objet eZ.

Pour illustrer cet article, j’ai décidé de développer un exemple vraiment très basique utilisant la Google Map. Lors de la création d’un objet eZ, l’utilisateur pourra choisir un point à positionner sur la carte, les coordonnées seront enregistrées en base pour une utilisation coté front (pas développée dans cette première partie).

Création de l’arborescence de l’extension

Tout d’abord, nous devons créer l’arborescence de notre extension, à suivre scrupuleusement pour éviter tout problème d’exécution! Attention au nom que vous donnerai à votre extension, il faut absoluement éviter qu’il entre en conflit avec celui d’une autre extension. Le mieux est de choisir un préfixe que vous utiliserez dans toutes celles que vous développerez à l’avenir. Pour notre exemple j’ai choisi gmapv3.

Les dossiers ne sont volontairement pas dépliés, comme vous pouvez le constater, on trouve à une exception près les mêmes répertoires que vous avez très certainement déjà rencontrés lors du développement d’un projet lambda. Et pour cause, une extension peut nécessiter l’utilisation de CSS, de JavaScript et même d’images, alors pourquoi changer la logique organisationnelle quand elle marche si bien.

Les fichiers de configuration

Il faut commencer par créer les fichiers content.ini.append.php et design.ini.append.php dans le repertoire settings, ajoutez-y respectivement les lignes suivantes:

content.ini.append.php

<?php /* #?ini charset="utf-8"?

[DataTypeSettings]
ExtensionDirectories[]=gmapv3
AvailableDataTypes[]=gmapv3

*/ ?>

Ici on indique à la plateforme le chemin vers notre extension, en précisant que dans notre cas, elle contiendra un datatype. Et oui, une extension n’est pas qu’un datatype, elle peut contenir des modules, des template operators et bien plus encore!

design.ini.append.php

<?php /* #?ini charset="utf-8"?

[ExtensionSettings]
DesignExtensions[]=gmapv3

[StylesheetSettings]
CSSFileList[]=gmapv3.css

[JavaScriptSettings]
JavaScriptList[]=jquery-1.6.1.js
JavaScriptList[]=gmapv3.js

*/ ?>

Dans ce fichier, on informe eZ que notre extension va nécessité l’utilisation de templates, et de surcroît qu’elle aura besoin de charger des feuilles de style et du JavaScript pour fonctionner correctement.

Pour terminer, il suffira de créer deux fichiers PHP dans le répertoire datatypes/gmapv3: gmapv3.php et gmapv3type.php. La classe CGmapv3Type (gmapv3type.php) doit impérativement dérivée de eZDataType, de ce fait, elle sera utilisée comme un datatype grâce à la surcharge de certaines méthodes. Pour ce qui est de CGmapv3, elle nous permettra d’interagir coté template (en frontend), pour en extraire aisément les valeurs stockées (latitude et longitude), nous verrons un peu plus en détail son fonctionnement dans la suite de cet article.

Un peu d’intégration

Le template utilisé par l’objet eZ sera à placer dans le répertoire template/content/datatype/edit/ et devra porter le nom du datatype en cours de développement (gmapv3.tpl). Ce dernier se compose de deux champs de saisie de type hidden qui contiendront les coordonnées qui seront mises à jour lorsque l’utiliseur positionnera son pointeur sur la carte, et d’un morceau de code JavaScript nécessaire pour instancier et utiliser la Google Map dans un conteneur HTML. Je ne vais pas aborder le déroulement du code, mais j’invite les plus curieux d’entre-vous à jeter un coup d’œil au script (au sens figuré) même s’il n’a rien de bien extraordinaire (merci à l’API de Google très bien documentée et illustrée d’exemples!).

Les deux champs de saisi doivent porter un nom correctement composé, sans quoi, il deviendrait impossible d’en récupérer les valeurs surtout si nous souhaitons créer une classe de contenu eZ avec deux attributs de type gmapv3. La meilleure méthode reste celle proposée par la plateforme dans tous ses datatypes, en ajoutant préfixe et suffixe à la valeur des noms que nous souhaitons donner à nos input:

<input type="hidden" name="{$attribute_base}_gmapv3_lat_{$attribute.id}" ... />
<input type="hidden" name="{$attribute_base}_gmapv3_lng_{$attribute.id}" ... />

De la sorte, on s’assure de garder une unicité avec le reste des attributs de l’objet eZ.

Développement du datatype

La classe CGmapv3Type

Puisque notre classe hérite de eZDataType, vous vous doutez bien qu’il y aura des méthodes à surcharger qui seront utilisées par le système. Pour ce tutoriel, nous allons uniquement nous interesser à son développement coté objet eZ. Pour ce faire, nous aurons besoin d’utiliser les méthodes suivantes:

public function objectAttributeContent ($contentAttribute);

Le paramètre $contentAttribute est un objet de type eZContentObjectAttribute, et comme sous eZ tout est objet, tous sont identifiés par un ID, l’objet est automatiquement passé par la plateforme, il nous appartient de l’utiliser correctement pour nos besoins. Notez que l’objet PHP $contentAttribute correspond à l’attribut de l’objet eZ de type gmapv3 en cours d’utilisation.

Cette méthode doit retourner un objet ou directement le contenu stocké. Pour un eZString, c’est la chaine de caractères qui sera retournée, pour des datatypes légèrement plus compliqués, il est préférable d’utiliser un objet que nous verrons plus loin dans le tutoriel, il s’agit de la classe CGmapv3.

Cette méthode sera appelée à divers moment du code, notamment lorsque vous ferez appel à $contentAttribute->content (); mais aussi dans vos templates coté front par exemple où {$node.data_map[gmapv3].content} retournera l’objet CGmapv3 instancié avec les bonnes valeurs (latitude et longitude).

public function validateObjectAttributeHTTPInput ($http, $base, $contentAttribute);

  • $http va nous permettre de récupérer les valeurs passées par le fomulaire à l’aide de la méthode POST ;
  • $base contient le début de l’attribute name qu’il faudra utiliser dans le template ;
  • $contentAttribute, tout comme la méthode objectAttributeContent correspondra à un objet PHP de l’attribut de type gmapv3 de l’objet eZ courant.

Cette méthode a pour unique but de retourner un état de validation des valeurs qui ont été transmises par le formulaire. Dans notre cas, les données à enregistrer doivent impérativement être des flottants. Le cas échéant, l’utilisateur en sera informé par un message d’erreur, et aucune donnée ne sera enregistrée pour être publiée. Elle est donc appelée avant fetchObjectAttributeHTTPInput que nous utiliserons pour la sauvegarde des données en base.

public function fetchObjectAttributeHTTPInput ($http, $base, $contentAttribute);

Les paramètres sont identiques à ceux de la méthode validateObjectAttributeHTTPInput. Dans notre exemple, elle est appelée en dernier par le système même si la méthode de validation retourne une erreur.

C’est ici que nous allons récupérer les valeurs du formulaire pour les enregistrer en base, et pour cela eZ met à notre disposition le champ data_text. Je ne vais pas expliquer de quelle façon tout est stocké et ni-même dans quelle table, tout d’abord parce que ce n’est pas l’objet de cet article, mais surtout parce qu’il serait trop long de le faire ici. Pour information, sachez que vous disposez en réalité de 3 champs: data_int, data_float et data_text. Il n’est pas nécessaire de les utiliser tous les trois, mais il est important de souligner leur existance, car si vous êtes curieux et que vous avez déjà parcouru le code de certains datatypes natifs du système, vous vous apercevrez très vite que eZString utilise data_text, eZInteger data_int, et d’autres peuvent utiliser 2 voire 3 de ces champs, ça dépend donc de ce que vous aurez besoin de stocker et surtout de quelle manière vous souhaiterez le faire… alors comment stocker une latitude et une longitude ? En structurant vos données avant de les enregistrer dans le champ data_text. Je ne sais pas réellement pourquoi, mais chez eZ, c’est le XML qui est utilisé dans je pense 100% des cas (je ne suis pas allé vérifier), mais rien ne vous empêche de sérialiser un tableau! Et c’est précisément ce que je vais faire dans mon exemple. Du coup, notre champ data_text contiendra des données facilement exploitables!

Avant d’enregistrer quoi que ce soit, il est d’abord nécessaire de récupérer les valeurs transmises par le formulaire:

$id = $contentAttribute->attribute ('id');

$gmapv3 = $contentAttribute->content ();
$gmapv3->setLat ($http->postVariable ($base.'_gmapv3_lat_'.$id));
$gmapv3->setLng ($http->postVariable ($base.'_gmapv3_lng_'.$id));

Comme je l’expliquais plus tôt dans l’article, $contentAttribute contient tout ce dont nous avons besoin pour interagir avec les différentes couches du système.

  • $contentAttribute->attribute (‘id’) retourne l’identifiant de l’attribut de l’objet eZ de type gmapv3 courant;
  • $contentAttribute->content () retourne un objet de type CGmapv3 (voir la méthode objectAttributeContent).

Pour terminer il ne nous reste plus qu’a sérialiser le tout pour le stocker en base dans le champ data_text:

$contentAttribute->setAttribute ('data_text', $gmapv3->encode ());

La classe CGmapv3

class CGmapv3 {

  private $lat, $lng;

  public function attributes ();
  public function hasAttribute ($name);
  public function attribute ($name);

  public function encode ();
  public function decode ($str);

  public function getLat ();
  public function getLng ();

  public function setLat ($lat);
  public function setLng ($lng);

}; // CGmapv3;

Les 3 méthodes suivantes seront nécessaires pour le moteur de template, en effet, comment connaitre le nom des propriétés à récupérer depuis un template si on ne l’indique pas à la plateforme.

  • public function attributes ();
  • public function hasAttribute ($name);
  • public function attribute ($name);

La méthode attribute nécessite une attention particulière. En effet, c’est elle qui aura pour lourde tâche de retourner une valeur lorsque cela sera nécessaire, notamment dans nos templates. Pour récupérer par exemple la latitude, vous aurez besoin de faire {$node.data_map[gmpav3].content.lat}. Rappelez-vous, content est un objet de type CGmapv3 et eZ peut retourner l’attribut lat uniquement parce qu’il en a eu connaissance à un moment du code, tout dabord parce que vous le lui avez indiqué via la méthode attributes qui retourne un tableau contenant le nom des attributs potentiellement accessibles, et ensuite parce que vous retournez une valeur depuis la méthode attribute:

public function attribute ($name) {
  switch ($name) {
    case 'lat': return $this->getLat ();
    case 'lng': return $this->getLng ();
  }
  eZDebug::writeError (
    "Attribute '$name' does not exist",
    'CGmapv3::attribute'
  );
  return null;
} // attribute ();

Pour conclure

Le développement d’un datatype nécessite de bonnes bases en POO sans quoi il serait difficile de comprendre le mécanisme d’héritage et de surcharge. Cela dit, ce type de développement mérite une attention particulière sur le déroulement du processus où il est important de comprendre pourquoi et à qu’elle moment les méthodes sont susceptibles d’être appelées. Pour le moment, je me suis attaqué uniquement à la partie objet eZ du datatype. Dans un prochain article, nous traiterons la partie classe eZ, où nous pourrons paramétrer certaines fonctionnalités de la Google Map comme le niveau de zoom, le type d’affichage etc…

N’oubliez pas d’activer l’extension en l’indiquant dans votre fichier settings/overrides/site.ini.append.php en ajoutant la ligne suivante à la section [ExtensionSettings]:

ActiveExtensions[]=gmapv3

sans oublier de régénérer l’autoload pour qu’elle soit correctement prise en compte:

./bin/php/ezpgenerateautoloads.php -e

Télécharger les sources

content.ini.append.php