Création d'un nouveau package

De Sydonie

AugmentedImage : configuration et 1ère version

Modification des configurations du site

config/site/config_keys.php

Pour que le site retrouve le nouveau package, il faut rajouter les lignes de code suivante dans SYDONIE_SITE/config/site/config_keys.php, SYDONIE_SITE correspondant à la racine de votre site développé avec Sydonie.

Manager_Keys::getInstance()->addManyClasses(array(
  'SydonieDocument_AugmentedImage' => array('augmentedimage', 'AugmentedImage', 'augmentedImage', 'Augmentedimage')
));

Ainsi, les clefs "augmentedimage", "AugmentedImage", "augmentedImage" et "Augmentedimage" seront reconnues comme étant des classes utilisables par le site. Ceci permet entre autre d'enrichir la sémantique d'url telle que URL_SYDONIE_SITE/augmentedimage/new. Après que l'url ait été analysée, 'augmentedimage' sera reconnu comme désignant le package SydonieDocument_AugmentedImage (ici pour y déclencher l'action new).

todo

  • L'opération de définition de nouvelles clefs devrait être automatique en parcourant l'architecture du dossier SydonieSite/SydonieDocument/*.

Architecture du package

Le package est créé par la mise en place du dossier SYDONIE_SITE/SydonieDocument/PACKAGE_NAME, pour notre exemple PACKAGE_NAME est AugmentedImage

SydonieDocument
├── ...
├── AugmentedImage
│   ├── action
│   │   └── ... .php
│   ├── actions.xml
│   ├── AugmentedImage.php
│   ├── config.xml
│   ├── fields.xml
│   ├── labels.xml
│   └── templates
│       └── ... .tpl.php
└── ...

Les fichiers de configuration que nous utilisons sont les suivants :

  • actions.xml : description des actions utilisables sur ce package
  • PACKAGE_NAME.php (AugmentedImage.php) : description des méthodes que l'on peut utiliser sur l'objet représentant le package.
  • config.xml : description des attributs du package
  • fields.xml : description des champs de formulaire associés aux attributs décrits dans config.xml
  • labels.xml : description des labels (langues et texte associé à chaque langue)

Les dossiers suivants permettent d'architecturer les fonctionnalités que l'on adjoindre au package :

  • action/ : dossier regroupant les actions décrites dans actions.xml
  • templates/ : dossier regroupant les templates d'affichage du package.

todo

  • Fusionner les différents fichiers de configuration (config.xml + fields.xml).
  • Le fichier de configuration d'action actions.xml devrait être calculé dynamiquement à la lecture du dossier action/
  • Pour plus de cohérence, dans un package, le dossier action/ devrait être renommé en actions/

Définir des attributs

Attributs

Work

  • uniformTitle
  • firstPublished
  • rights
  • Expression
    • title : titre
    • description : texte explicatif à l'usage du public
    • notes : texte explicatif à l'usage des administrateurs du site
    • Manifestation
      • content

configs.xml

Le code ci-dessous décrit le fichier configs.xml répondant à la définition de notre package.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <class>
    <name>SydonieDocument_AugmentedImage</name>
    <extends>SydonieDocument_Article</extends>
    <mandatoryProp></mandatoryProp>
  </class>
 
  <attribute entityLevel="expression"
         minOccur="1"
         maxOccur="1"
         mandatory="0">
    <predicate>notes</predicate>
    <objectClass>AttributeType_Text</objectClass>
  </attribute>
</configuration>

fields.xml

<?xml version="1.0" encoding="utf-8"?>
<fields>
  <field propName="notes.text"
         uiMethod="Input_Textarea">
  </field>
</fields>

AugmentedImage.php

La classe SydonieDocument_AugmentedImage qui accueillera les fonctionnalités que l'on veut allouer à notre package :

<?php
class SydonieDocument_AugmentedImage extends Abstract_SydonieDocument{
 
}
?>

Pour le moment, la classe est vide car nous voulons juste récupérer les fonctionnalités prédéfinies dans Sydonie (en héritant de la classe Abstract_SydonieDocument).

todo

  • config.xml et fields.xml pourraient être fusionnés. Ainsi, l'exemple précédent ne nécessiterait pas deux fichiers de configuration distincts.
    <attribute entityLevel="expression"
           minOccur="1"
           maxOccur="1"
           mandatory="0">
        <predicate>notes</predicate>
        <objectClass>AttributeType_Text</objectClass>
        <field propName="notes.text" uiMethod="Input_Textarea" />
    </attribute>

labels.xml

<?xml version="1.0" encoding="utf-8" ?>
<!-- <!DOCTYPE tmx SYSTEM "../xml/tmx14.dtd"> -->
<tmx version="1.4">
   <header
      datatype="PlainText" segtype="sentence"
      creationtool="sydonie" creationtoolversion="1.0"
      srclang="en" o-encoding="utf-8" o-tmf="plaintext">
   </header>
 
  <body>
    <tu tuid="notes.text" srclang="fr">
        <tuv xml:lang="en">
        <seg>Notes</seg>
        </tuv>
        <tuv xml:lang="fr">
        <seg>Notes</seg>
        </tuv>
    </tu>
  </body>
</tmx>

modification et création d'actions

Notre package hérite directement des actions de SydonieDocument_Article (<extends>SydonieDocument_Article</extends> dans le fichier configs.xml).

Nous pouvons dors et déjà les exploiter, par exemple en tappant les url suivantes :

  • URL_SYDONIE_SITE/AugmentedImage/new
  • URL_SYDONIE_SITE/AugmentedImage/listItems
  • URL_SYDONIE_SITE/AugmentedImage/x32b.../edit

Ces urls peuvent être déparées en deux cas de figure.

  • url d'action de classe : URL_SYDONIE_SITE/SYDONIE_PACKAGE/SYDONIE_ACTION_CLASS
  • url d'action d'instance : URL_SYDONIE_SITE/SYDONIE_PACKAGE/PACKAGE_INSTANCE_ID/SYDONIE_ACTION_INSTANCE

Exemples d'actions de classe prédéfinies :

  • new
  • listItems

Exemples d'actions d'instance prédéfinies :

  • edit
  • view
  • update
  • viewValues

Modification du template associé à l'action view

Le template associé à l'action prédéfinie view peut être mdoifié en créant un nouveau template dédié SYDONIE_PACKAGE/templates/view.tpl.php. L'exemple ci-dessous montre comment afficher les attributs title, description et notes :

<div class="augmentedImage view">
  <p style="text-align:right;">
    <?php
      if(isloggedAsAdmin()){echo linkTo($obj, 'edit', 'edit', '', null, array());}
    ?>
  </p>
 
  <h4>
    <?php echo $ui->prop('title'); ?>
  </h4>
  <p style="padding-left : 3px; margin-bottom: 3px; border-left: solid #999999 1px;">
    <?php echo $ui->prop('description'); ?>
  </p>
  <p style="padding-left : 3px; border: dashed #BBBBBB 1px; font-style: italic; color: #AAAAAA;">
    <?php
      if (isloggedAsAdmin()) {
        echo $ui->prop('notes');
      }
    ?>
  </p>
</div>

Nous ne prenons pas en compte pour le moment qu'une instance d'AugmentedImage est reliée à une instance d'Image. Nous nous contentons d'afficher les attributs du package.

Modification du template associé à l'action edit

Le template associé à l'action edit peut être modifié de la même manière (SYDONIE_PACKAGE/templates/edit.tpl.php).

<div class="augmentedImage">
  <div>
    <h1>
      <?php echo "Nouvelle instance d'AugmentedImage"; ?>
    </h1>
    <fieldset>
      <legend>Informations publiques</legend>
      <?php echo $ui->input('title'); ?>
      <?php echo $ui->input('description'); ?>
    </fieldset>
    <fieldset>
      <legend>Image sélectionnée</legend>
      <?php  ?>
    </fieldset>
    <fieldset>
      <legend>Informations personnelles</legend>
      <?php echo $ui->input('notes'); ?>
    </fieldset>
  </div>
  <div class="clearer">&nbsp;</div>
  <?php echo $ui->submit(); ?>
</div>

Notes :

  • Nous laissons un emplacement dédié à l'ajout d'une relation entre une instance d'Image et d'AugmentedImage.

Déclaration et création d'actions/templates (snippet, lastFive)

actions.xml

<?xml version="1.0" encoding="UTF-8"?>
<actions class="SydonieDocument_AugmentedImage">
  <action name   = "lastFive"
          group  = "viewGroup"
          action = "lastFive">
  </action>
 
  <action name   = "snippet"
          group  = "viewSingle"
          action = "snippet">
  </action>
</actions>

action d'instance snippet

SYDONIE_PACKAGE/action/action_viewSingle.php SYDONIE_PACKAGE/templates/action_snippet.php
<?php
class SydonieDocument_AugmentedImage_action_viewSingle extends Abstract_Action {
  protected function options_snippet() {
    return array(
        'isClassAction' => false,
        'permissions' => 'read'
    );
  }
 
  protected function do_snippet() {
      return getUi($this->instance)->display('snippet');
  }
}
?>
<?php
  $title = $ui->prop('title');
  $content = $ui->prop('description');
  $prefix_title = cutPrefix($title, 30, '...');
  $prefix_content = cutPrefix($content, 60, '...');
?>
 
<div class="augmentedImage snippet">
  <span style='font-weight: bold;'>
    <?php echo $prefix_title; ?>
  </span>
  -
  <span style='font-style: italic; color:grey;'>
    <?php echo $prefix_content; ?>
  </span>
</div>

todo

  • L'action snippet devrait être disponible par défaut dans le package SYDONIE/SydonieDocument/Article

action de classe lastFive

SYDONIE_PACKAGE/action/action_viewGroup.php SYDONIE_PACKAGE/templates/action_lastFive.php
<?php
class SydonieDocument_AugmentedImage_action_viewGroup extends Abstract_Action {
 
  protected function options_lastFive() {
    return array(
        'isClassAction' => true,
        'permissions' => CONTROLLER_ACTION_PUBLIC
    );
  }
 
  protected function do_lastFive() {
    $query = new SydonieQuery_Query(
      array(
        new SydonieQuery_Entity($this->class, 'SydonieDocument_AugmentedImage'),
        new SydonieQuery_Rights($this->class, 'read'),
        new SydonieQuery_OrderByCreationDate($this->class, 'DESC'),
        new SydonieQuery_Limit(0, 5),
        new SydonieQuery_Return($this->class)
      )
    );
    $fetch_lastFive = $query->fetchAll();
    $params = array('fetch_lastFive'=>$fetch_lastFive);
    return getUi($this->class)->display('lastFive',$params);
  }
}
?>
<div class="augmentedImage lastfive">
  <?php foreach($fetch_lastFive as $i=>$augmentedImage) : ?>
    <?php
      $background_color = ($i%2 == 0) ? 'transparent' : '#EEEEEE';
    ?>
    <div class = "augmentedImage snippet"
         style = "padding-left:3px;
                  background-color:<?php echo $background_color; ?>;">
    <?php
      echo getUi($augmentedImage)->display('snippet');
      echo linkTo($augmentedImage, 'view');
    ?>
    </div>
  <?php endforeach;?>
</div>

Récapitulatif des todo pour cette section

La réalisation de ces fonctionnalités permettrait de simplifier la création d'un nouveau package.

  • L'opération de définition de nouvelles clefs devrait être automatique en parcourant l'architecture du dossier SydonieSite/SydonieDocument/*.
  • Fusionner les différents fichiers de configuration (config.xml+fields.xml).
    <attribute entityLevel="expression"
           minOccur="1"
           maxOccur="1"
           mandatory="0">
        <predicate>notes</predicate>
        <objectClass>AttributeType_Text</objectClass>
        <field propName="notes.text" uiMethod="Input_Textarea" />
    </attribute>
  • Le fichier de configuration d'action actions.xml devrait être calculé dynamiquement à la lecture du dossier action/
  • Pour plus de cohérence, dans un package, le dossier action/ devrait être renommé en actions/
  • L'action snippet devrait être disponible par défaut dans le package SYDONIE/SydonieDocument/Article

AugmentedImage : 2ème version (créer une relation avec une Image)

Il manque maintenant le lien entre un objet AugmentedImage et une Image. Pour se faire, nous devons établir les fonctionnalités suivantes :

  • Relier une Image à une instance AugmentedImage
  • Supprimer une Image à une instance AugmentedImage

Ces actions seront utilisées lors de l'action d'édition d'une instance d'AugmentedImage (action et template edit).

A partir de ces fonctionnalités, maintenant qu'à une instance d'AugmentedImage nous pouvons récupérer une Image associée, nous pouvons aussi modifier les templates déjà existant pour afficher correctement l'Image reliée.

  • view
  • snippet

Modification des configurations du site

config/site/config_statements.php

Nous allons avoir besoin de désigner le lien entre une instance d'AugmentedImage et d'Image. Pour ce faire, nous rajoutons dans les statements du site les noms des relations qui les unissent.

<?php
$statementManager->addPredicate('HAS_EXTERNAL_IMAGE', 'IS_EXTERNAL_IMAGE_OF');
?>

Avec :

  • HAS_EXTERNAL_IMAGE la relation (AugmentedImage, HAS_EXTERNAL_IMAGE, Image)
  • IS_EXTERNAL_IMAGE_OF la relation réciproque (Image, IS_EXTERNAL_IMAGE_OF, AugmentedImage)

Ces noms de relation sont définies pour le site, et non exclusivement pour l'objet AugmentedImage. Ils peuvent dont être réutilisés pour créer des relations entre d'autres Package du site.

todo

  • Supprimer ce fichier de configuration
  • Si l'on veut vraiment définir les relations qui peuvent unir deux Instances :
    • Alors ces relations doivent être définies entre deux instances de package spécifique (ne pas autoriser par exemple une relation (Chien, HAS_EXTERNAL_IMAGE, NavetteSpatiale).
    • Ceci passe par la déclaration des relations entre instances dans configs.xml, de la même manière que l'on déclare les attributs.
    • La relation entre deux packages n'est alors pas obligé d'être dans leurs deux config.xml respectifs ; dans un seul suffira.

Factoriser des fonctionnalités en modifiant AugmentedImage.php

Afin de pouvoir manipuler nos AugmentedImage en tout lieux (dans des actions ou encore des templates), nous pouvons l'enrichir de fonctionnalités supplémentaires en créant des méthodes adaptées aux besoins. Ci-dessous, l'ajout d'une méthode permettant de récupérer les Images liées à une AugmentedImage par des relations définies comme précédemment (HAS_EXTERNAL_IMAGE dans le fichier de configuration config_statements.php).

public function getImages() {
  $imagesExt = getManager('Statements')->getObjects($this, 'HAS_EXTERNAL_IMAGE');
  return $imagesExt;
}

Définition de nouvelles actions

actions sur les relations avec une Image

editExternalImage, addExternalImage et removeExternalImage

Nous définissons des nouvelles actions pour l'ajout, la suppression et l'édition de relation entre AugmentedImage et Image. Nous déclarons ces actions dans actions.xml.

  <!-- image relation -->
  <action name="editExternalImages"
          group="imageRelation"
          action="editExternalImages">
  </action>
  <action name="addExternalImage"
          group="imageRelation"
          action="addExternalImage">
  </action>
  <action name="removeExternalImage"
          group="imageRelation"
          action="removeExternalImage">
  </action>

Nous pouvons alors définir ces actions comme déclarées dans le fichier actions.xml en créant la nouvelle classe d'action SydonieDocument_AugmentedImage_action_imageRelation dans action/action_imageRelation.php.

<?php
 
class SydonieDocument_AugmentedImage_action_imageRelation extends Abstract_Action {
 
  /*
   * useful methods
   */
  protected function getImageFromId(){
    $imageId = $this->controllerData->getDataGetKey('imageId');
    if ($imageId === SYDONIE_NO_KEY) {
      return null;
    }
    $image = Registry::getEntity($imageId);
    return $image;
  }
 
  /*
   * editExternalImages
   */
  protected function options_editExternalImages() {
    return array(
      'isClassAction' => false,
      'permissions' => 'write'
    );
  }
 
  protected function do_editExternalImages() {
    return getUi($this->instance)->display('editExternalImages');
  }
 
  /*
   * addExternalImage
   */
  protected function options_addExternalImage() {
    return array(
      'isClassAction' => false,
      'permissions' => 'write'
    );
  }
 
  protected function do_addExternalImage() {
    $image = $this->getImageFromId();
    if($image !== null){
      getManager('Statements')->add($this->instance, 'HAS_EXTERNAL_IMAGE', $image);
    }
    return '';
  }
 
  /*
   * removeExternalImage
   */
  protected function options_removeExternalImage() {
    return array(
      'isClassAction' => false,
      'permissions' => 'write'
    );
  }
 
  protected function do_removeExternalImage() {
    $image = $this->getImageFromId();
    if($image !== null){
      getManager('Statements')->remove($this->instance, 'HAS_EXTERNAL_IMAGE', $image);
    }
    return '';
  }
}
?>

Notes :

  • Les actions addExternalImage et removeExternalImage ne nécessitent pas dans cette version d'afficher un template. En effet, elles servent juste aux opérations de stockage des relations.
  • L'action editExternalImage renvoie le résultat d'un template qui s'occupera d'appeler les actions que l'on veut effectuer pour l'édition de cette Image.

templates/editExternalImages.tpl.php

<div>
  <?php $images = $obj->getImages(); ?>
  <ul>
    <?php foreach ($images as $image) : ?>
    <li>
      <img src="<?php echo $image->getUrlPathUsingFormat('square') ?>"/>
      <?php echo linkTo($obj, 'removeExternalImage', 'removeExternalImage', '',
                        array('query'=>"imageId={$image->getId()}"));?>
    </li>
    <?php endforeach; ?>
  </ul>
</div>

Notes :

  • La variable $obj contient une instance du package en cours de traitement, ici AugmentedImage. Nous pouvons alors appeler la méthode que nous avons déclarée ultérieurement : getImages().

listItemsImages

Les opérations de base ont été définies ainsi que le template permettant de visualiser les instances d'Image reliées à une instance de AugmentedImage. Nous souhaitons maintenant liste les images présentes sur le site pour les proposer à l'utilisateur afin qu'il puisse relier celles de son choix.

actions.xml

  <action name="listItemsImages"
          group="listItemsImages"
          action="listItems">
  </action>

actions/action_listItemsImages.php

class SydonieDocument_AugmentedImage_action_listItemsImages extends Abstract_SydonieDocument_action_listItems {
 
  protected function getPagesOptions() {
    return array(
      'itemsPerPage' => 5,
      'pageRange' => 7,
    );
  }
 
  protected function getBasicQuery() {
    return new SydonieQuery_Query(array(
        new SydonieQuery_Entity('instance', 'SydonieDocument_Image'),
        new SydonieQuery_Rights('instance', 'read'),
        new SydonieQuery_Return('instance')
    ));
  }
 
  protected function getFilters() {
    return array();
  }
 
  protected function displayClassActions() {
    return false;
  }
 
  protected function getActionLinkList() {
    return array('view', 'edit', 'delete');
  }
 
  protected function getTemplateName() {
    return 'listItemsImages';
  }
 
  protected function options_listItems() {
    return array(
        'isClassAction' => false,
        'permissions' => 'write'
    );
  }
}

templates/listItemsImages.tpl.php

<div>
<?php
  echo '<table class="listItems">';
  $itemLabel = label('items');
  $actionsLabel = label('actions');
  echo "<tr><th>{$itemLabel}</th><th colspan=\"0\">{$actionsLabel}</th></tr>\n";
 
  foreach ($paginator->getCurrentItems() as $entity) {
    $item = $entity->getInstanceHeading();
    echo "<tr><td>{$item}</td>";
    echo "<td>" . linkTo($obj, 'addExternalImage', 'associateImage', '',
          array('query'=>"imageId={$entity->getId()}")) . "</td>";
    echo "</tr>\n";
  }
  echo '</table>';
?>
</div>

Modification d'actions/templates définis précédemment

Maintenant qu'une instance d'AugmentedImage possède les outils pour être reliée avec une Image, nous pouvons afficher ces dernières lorsque l'on désire afficher une instance d'AugmentedImage.

Modification de template/view.tpl.php

<div class="augmentedImage view">
  <p style="text-align:right;">
  <?php
  if (isloggedAsAdmin()) {
    echo linkTo($obj, 'edit', 'edit', '', null, array());
  }
  ?>
  </p>
 
  <h4>
    <?php echo $ui->prop('title'); ?>
  </h4>
 
  <div>
  <?php
    $images = $obj->getImages();
    foreach($images as $image){
      echo getUi($image)->display('snippet');
    }
  ?>
 
  <p style="padding-left: 3px; margin-bottom: 3px; border-left: solid #999999 1px; color:black;">
    <?php
      echo $ui->prop('description');
    ?>
  </p>
  <p style="padding-left: 3px; border: dashed #BBBBBB 1px; font-style:italic; color:#AAAAAA;">
    <?php
      if (isloggedAsAdmin()) {
        echo $ui->prop('notes');
      }
    ?>
  </p>
</div>

Modification de edit.tpl.php, listItemsImages.tpl.php et editExternalImages.tpl.php

L'idée est maintenant de réactualiser le contenu de l'édition d'un AugmentedImage en fonction des modifications des relations avec des instances d'Image. Donc, chaque image rajoutée en passant par le formulaire du template listItemsImages.tpl.php sera actualisé à la visualisation du template template/edit.tpl.php.

template/edit.tpl.php

<div class="augmentedImage" >
  <div>
  <h1><?php echo 'AugmentedImage' ?></h1>
    <fieldset>
      <legend>Informations publiques</legend>
      <?php echo $ui->input('title'); ?>
      <?php echo $ui->input('description'); ?>
    </fieldset>
 
    <fieldset>
      <legend>Image sélectionnée</legend>
        <h4>editExternalImage</h4>
        <div data-majax="majaxListenTo_modalclosing" data-url="<?php echo urlTo($obj, 'editExternalImages/majax')?>">
          <?php echo $ui->display('editExternalImages'); ?>
        </div>
        <h4>addExistingImage</h4>
        <div>
          <?php echo linkTo($obj, 'listItemsImages', 'addExistingImage', '', null, array("data-majax"=>'majaxModal majaxFire_modalclosing'));?>
       </div>
    </fieldset>
 
    <fieldset>
      <legend>Informations personnelles</legend>
      <?php echo $ui->input('notes'); ?>
    </fieldset>
 
  </div>
  <div class="clearer">&nbsp;</div>
  <?php echo $ui->submit(); ?>
</div>

template/listItemsImages.tpl.php

<div>
<?php
  echo '<table class="listItems">';
  $itemLabel = label('items');
  $actionsLabel = label('actions');
  echo "<tr><th>{$itemLabel}</th><th colspan=\"0\">{$actionsLabel}</th></tr>\n";
 
  foreach ($paginator->getCurrentItems() as $entity) {
    $item = $entity->getInstanceHeading();
    echo "<tr><td>{$item}</td>";
    echo "<td>" . linkTo($obj, 'addExternalImage', 'associateImage', '',
                         array('query'=>"imageId={$entity->getId()}")) . "</td>";
    echo "</tr>\n";
  }
  echo '</table>';
?>
</div>

template/editExternalImages.tpl.php

<div>
  <?php $images = $obj->getImages(); ?>
  <ul>
    <?php foreach ($images as $image) : ?>
    <li>
      <img src="<?php echo $image->getUrlPathUsingFormat('square') ?>"/>
      <?php echo linkTo($obj, 'removeExternalImage', 'removeExternalImage', '',
                        array('query'=>"imageId={$image->getId()}"),
                        array('data-majax'=>'majaxLink majaxFire_removeExternalImage'));?>
    </li>
    <?php endforeach; ?>
  </ul>
</div>