Outils pour utilisateurs

Outils du site


Panneau latéral

ref:blocs:bean

Utilisation des beans

Un bean est une instance d'une classe, instanciable par constructeur simple (sans argument), aux propriétés accessibles par mutateurs et accesseurs. Le nom bean vient de JavaBean, bien que la définition et l'usage soient détournés de l'original.

Dans Change, le bean (f_mvc_Bean) est associé à un model (f_mvc_BeanModel) qui renseigne le code le manipulant sur ses propriétés : existence, type, contraintes et libellé, et possède en général un unique identifiant géré par la propriété id.

Le bean est notamment utilisé dans le processus de peuplement des formulaires et comme raccourci fonctionnel dans la récupération des données d'une requête :

  • Un formulaire utilisant un bean pourra à partir d'un seul nom de propriété déterminer quel contrôle utiliser et quelle valeur lui affecter : le développeur n'aura qu'à décider du placement de la propriété dans le gabarit,
  • Une action de bloc utilisant un bean récupérera les paramètres de requête dans un objet spécialisé, dont les données sont validées et typées.

Les documents Change sont des beans et peuvent être utilisés en tant que tel ; c'est d'ailleurs le cas le plus courant. Parfois cependant, il pourra générer un bean à partir de rien en générant du code PHP ou en utilisant un “Beans dynamiques”.

Associer un bean à une action d'un bloc

Associer un bean à une action d'un bloc se fait :

  • En déclarant un troisième paramètre typé en plus des deux paramètres obligatoires ($request et $response),
  • Ou en implémentant getXXXBeanInfo(), qui doit retourner un tableau associatif contenant des valeurs pour les clefs className et beanName. Cette méthode est préférée dans les cas plus dynamiques où la classe du bean n'est pas déterminée “en dur” dans le code du bloc.

Une fois le bean associé à une action d'un bloc, celle-ci reçoit l'objet en question en paramètre, proprement peuplé en fonction des paramètres de la requête.

Dans l'extrait de code suivant, le bean nommé “mydoc” et de classe mymodule_persistentdocument_mydoc a été associé à l'action “save” du bloc :

/**
 * @param f_mvc_Request $request
 * @param f_mvc_Response $response
 * @return String
 */
function executeSave($request, $response, mymodule_persistentdocument_mydoc $mydoc)
{
   // ... do something with $mydoc
}

La même association aurait pu se faire implémentant getSaveBeanInfo() :

function executeSave($request, $response, $mydoc)
{
   // ... do something with $mydoc
}
 
function getSaveBeanInfo()
{
  return array("className" => "mymodule_persistentdocument_mydoc", "beanName" => "mydoc");
}

Une fois l'association faite, tout appel à executeSave() par le contrôleur de blocs sera précédé d'une instanciation d'un objet de la classe mymodule_persistentdocument_mydoc et du peuplement de l'objet avec les paramètres de la requête.

Le processus de peuplement d'un bean

Le processus de peuplement d'un bean intervient juste avant l'appel à la méthode associée et repose par défaut sur la méthode BeanUtils::populate() à laquelle sont transmis les paramètres de requête ($request→getParameters()).

Il s'agit d'initialiser correctement les propriétés typées d'un objet étant données des valeurs de type String en entrée, ce qui peut impliquer des conversions de type.

Le peuplement standard d'un bean de type mymodule_persistentdocument_mydoc est équivalent au code suivant :

$mydoc = BeanUtils::getNewBeanInstance("mymodule_persistentdocument_mydoc");
BeanUtils::populate($mydoc, $request->getParameters());

BeanUtils::populate() peuple le bean avec les valeurs du tableau en cherchant les propriétés correspondant aux clefs du tableau.

Ainsi, si la requête contient les paramètres “label” et “description”, correspondant à des propriétés du document mymodule_persistentdocument_mydoc, le controlleur executera un code équivalent à :

$mydoc = mymodule_MydocService::getInstance()->getNewDocumentInstance();
$mydoc->setLabel($request->getParameter("label"));
$mydoc->setDescription($request->getParameter("description"));

De plus, si beanId est un paramètre de la requête, celui-ci sera utilisé pour instancier l'objet mymodule_persistentdocument_mydoc ayant l'identifiant en question :

$mydoc = BeanUtils::getBeanInstance("mymodule_persistentdocument_mydoc", $request->getParameter("beanId"));
BeanUtils::populate($mydoc, $request->getParameters());

Code équivalent à :

$mydoc = mymodule_MydocService::getInstance()->getDocumentInstance($request->getParameter("beanId"));
$mydoc->setLabel($request->getParameter("label"));
$mydoc->setDescription($request->getParameter("description"));

Ainsi, si la requête contient suffisamment d'informations et que validateSaveInput() est bien implémentée, le bloc pourra se contenter d'appeler save() sur l'objet qui lui aura été transmis pour créer ou mettre à jour un document “projet”.

De cette manière, toute propriété du bean ayant une valeur dans la requête sera automatiquement affectée. Ceci est raisonnable dans le cas où le bean a été défini explicitement pour ce bloc et ne contient que les propriétés dont ce bloc est censé permettre l'édition. Par contre, le plus souvent on utilise directement un document dont on ne permet pas l'édition de toutes les propriétés. Il est alors indispensable de filtrer explicitement les propriétés dont on autorise la mise à jour.

À partir de la version 3.6.5, le mode de peuplement "strict" impose ce filtrage explicite pour les documents.

À noter également que pour des raisons de sécurité, les utilisateurs backoffice ne sont pas “peuplables” automatiquement, de même que les propriétés critiques des utilisateurs frontoffice autres que l'utilisateur connecté (mot de passe, email, login). En cas de besoin, ces mises à jour devront donc être faites à la main plutôt que par peuplement automatique.

BeanConverters

Renseigner une propriété d'un bean implique parfois des conversions : du simple “cast” de chaine vers entier à la récupération de documents à partir d'une collection d'identifiants.

A cet effet, une propriété peut déclarer un convertisseur (Cf. BeanPropertyInfo::getConverter()). Le convertisseur est alors utilisé dans les deux sens : de la requête vers le bean (lors du peuplement d'un bean à partir de la requête) ou du bean vers la requête (lors du peuplement d'un formulaire à partir d'un bean par ex.). Un convertisseur implémente l'interface BeanValueConverter :

interface BeanValueConverter
{
        /**
         * @param Mixed $value
         * @return Mixed
         */
        public function convertFromRequestToBeanValue($value);
 
        /**
         * @param Mixed $value
         * @return Mixed
         */
        public function convertFromBeanToRequestValue($value);
}

Le framework fournit des convertisseurs de base, disponibles dans le dossier f_mvc/bean/converters/ :

  • BooleanConverter,
  • DateTimeConverter,
  • DecimalConverter,
  • DocumentConverter,
  • EditableListConverter,
  • XHTMLFragmentConverter.

Agir sur le processus de peuplement des beans

Restreindre l'ensemble de propriétés "peuplables"

Par défaut, l'ensemble des propriétés du bean sont peuplées si un paramètre correctement nommé à une valeur compatible. Cet ensemble peut être restreint :

  • En déclarant explicitement les propriétés (recommandé) : implémenter get<NomBean>BeanInclude().
  • En excluant certaines propriétés : implémenter get<NomBean>BeanExclude().

Restreindre l'ensemble de propriétés “peuplables” est essentiel pour des raisons de sécurité : en effet, un utilisateur malveillant pourrait facilement mettre à jour une propriété censé ne pas être éditée en renseignant un paramètre de requête…

Mode de peuplement "strict"

À partir de la version 3.6.5.

À partir de la version 3.6.5, un mode de peuplement dit “strict” est activé par défaut. Il impose que pour tout bean de type document, la liste des liste des propriétés “peuplables” soit donnée explicitement (dans le cas contraire une exception est lancée).

Ce mode impose de respecter les précautions essentielles de sécurité. Il est cependant désactivable par configuration projet (essentiellement afin de permettre les migrations automatiques depuis les version 3.6.x antérieures) via la configuration projet en définissant la clé modules/website/useBeanPopulateStrictMode à false.

Implémenter ''populate<BeanName>Bean()''

Pour maîtriser complètement le processus de peuplement, implémenter populate<BeanName>Bean() : array<String, String>.

Important : cette méthode reçoit une instance du bean, agit dessus pour le peupler et renvoie les valeurs qui n'ont pas pu être affectées sous la forme d'un tableau associatif “nom de propriété ⇒ valeur invalide”. BeanUtils::populate() renvoie ce tableau et BeantUtils::setProperty() renvoie false si la propriété existe et qu'elle n'a pu être remplie avec la valeur fournie.

Exemple : le bean mydoc attaché à executeSave() est peuplé avec la méthode populateMydocBean() qui utilise le processus standard et effectue des traitements spécifiques

/**
 * @param f_mvc_Request $request
 * @param f_mvc_Response $response
 * @return String
*/
function executeSave($request, $response, mymodule_persistentdocument_mydoc $mydoc)
{
  // here the ticket bean was populated using populateMydocBean() method
}
 
/**
 * @param mymodule_persistentdocument_mydoc $mydoc
 * @param f_mvc_Request $request
 * @return array<String, String>
 */
function populateMydocBean(mymodule_persistentdocument_mydoc $mydoc, $request)
{
  // standard population process, excluding some properties
  $excludedProperties = array("privPropName1", "privPropName2");
  $invalidProperties = BeanUtils::populate($mydoc, $request->getParameters(), null, $excludedProperties);
 
  // custom things
  ...
  return $invalidProperties;
}

BeanPopulateFilter

Il est possible d'agir sur le bean pour différents traitements en fin de processus de peuplement en déclarant un “BeanPopulateFilter”. Ce mécanisme agit sur le peuplement du bean, que la méthode populate<BeanName>Bean ait été spécialisée ou non :

  • La requête renseigne le paramètre multiple WEBSITE_POST_POPULATE_FILTERS avec des noms de classes implémentant website_BeanPopulateFilter
  • Le contrôleur peuple le bean de manière standard puis instancie les filtres et les exécute
interface website_BeanPopulateFilter
{
        /**
         * @param f_mvc_Bean $bean
         * @param website_BlockActionRequest $request
         */
        function execute($bean, $request);
}

Ce mécanisme est notamment utilisé par l'extension PHPTal change:uploadfield qui permet de peupler un bean avec des documents media_persistentdocument_tmpfile à partir de fichier téléchargés vers le serveur :

  • L'extension déclare pour la propriété considérée (<propName>) le postfilter media_FileBeanPopulateFilter : WEBSITE_POST_POPULATE_FILTERS[<propName>] = media_FileBeanPopulateFilter,
  • Une fois le bean peuplé de manière standard avec les paramètres de requête, le contrôleur instancie media_FileBeanPopulateFilter en lui donnant <propName>,
  • media_FileBeanPopulateFilter récupère les fichiers depuis $_FILES, les transforme en media_persistentdocument_tmpfile et peuple la propriété <propName> du bean avec.

Le développeur pourra placer dans un formulaire un champ caché définissant des valeurs de WEBSITE_POST_POPULATE_FILTERS, en “dur” dans le gabarit ou au travers une extension PHPTal spécifique.

Liens avec les formulaires

Les beans sont utilisés pour peupler des formulaires :

  • choix du contrôle HTML approprié pour un champ,
  • formatage des valeurs en fonction du type du champ,
  • trouver les libellés localisés des champs,
  • trouver les textes d'aide localisés des champs.

Générer un formulaire à partir d'un bean

L'outil ligne de commande changedev.php permet de générer rapidement un formulaire basique à partir d'un bean grâce à la commande generate-bean-frontoffice-form :

Usage: changedev.php generate-bean-frontoffice-form <className> <outputFileName> [options]
where options in:
  --stdout: output the generated html to standard output

Ainsi, pour le bean news_persistentdocument_news :

intsimoa@srbswebrd:~/change4/change$ changedev.php generate-bean-frontoffice-form news_persistentdocument_news --stdout

La commande generate-bean-frontoffice-form génère le formulaire suivant :

<form change:form="beanClass news_persistentdocument_news; beanName news">
        <div change:errors=""></div>
        <tal change:field="name beanId" hidden="true" />
        <ol>
                <li><input change:field="name label" /></li>
                <li><input change:field="name startpublicationdate" /></li>
                <li><input change:field="name metastring" /></li>
                <li><input change:field="name date" /></li>
                <li><input change:field="name summary" /></li>
                <li><input change:field="name text" /></li>
                <li><input change:field="name linkedpage" /></li>
                <li><input change:field="name listvisual" /></li>
                <li><input change:field="name detailvisual" /></li>
                <li><input change:field="name datetimeinfo" /></li>
                <li><input change:field="name place" /></li>
                <li><input change:field="name accessmap" /></li>
                <li><input change:field="name contact" /></li>
                <li><input change:field="name attachment" /></li>
                <li><input change:field="name priority" /></li>
                <li><input change:field="name publicationyear" /></li>
                <li><input change:field="name publicationmonth" /></li>
                <li><input change:field="name publicationweek" /></li>
                <li><input change:field="name archiveyear" /></li>
                <li><input change:field="name archivemonth" /></li>
                <li><input change:field="name archiveweek" /></li>
                <li><input change:field="name startarchivedate" /></li>
        </ol>
        <p>
                <input change:submit="label &modules.website.frontoffice.form.Submit;"/>
        </p>
</form>

Le formulaire généré place l'ensemble des propriétés du document les unes en dessous des autres et ne fixe aucunement les contrôles HTML utilisés. Le contrôle par défaut déterminé par le type de la propriété sera utilisé.

Reste alors au développeur de déplacer, supprimer des champs, d'éventuellement fixer le contrôle utilisé pour un champ donné ou encore de régler des paramètres de mise en forme (nombre de colonnes ou de lignes pour une propriété de type LongString ou XHTMLFragment par exemple).

Choix automatique du contrôle

L'extension PHPTal change:field permet la sélection d'un contrôle en fonction du type de la propriété. Le tableau suivant montre l'association “type de propriété ⇒ type de contrôle” :

Type de propriété Type de contrôle Equivalent HTML
Boolean change:booleaninput input[@type = 'radio'], value = {oui, non}
Lob change:textarea <textarea />
LongString change:textarea -
XHTMLFragment change:richtextinput <textarea /> + éditeur js wysiwyg (fckeditor)
DateTime change:dateinput input[@type = 'text'] + contrôle js date
Date change:dateinput -
Document change:documentinput <select />
Champ associé à une liste change:selectinput ou ensemble de change:checkboxinput si @display = “checkbox” <select />
String change:textinput input[@type = 'text']
Autres change:textinput -

L'attribut beanName de change:form

L'attribut beanName de change:form indique le nom de l'objet à utiliser. Dans l'exemple suivant, un bloc transmet un bean sous le nom “mydoc” :

class mymodule_SomeBlockAction
{
  function execute($request, $response)
  {
    $somebean = ...;
    $somebean->setSomeProperty($somePropertyValue);
    $request->setAttribute("mydoc", $somebean);
  }
}

et la vue utilise l'objet transmis,

<form change:form="beanName mydoc">
  <input change:field="name someProperty" />
  ...
</form>

L'attribut beanClass de change:form

L'attribut beanClass permet à change:form d'instancier un bean et de l'utiliser si celui-ci n'est pas disponible dans la requête. Le cas d'utilisation typique est l'affichage d'un formulaire d'insertion, cas où l'objet n'existe pas encore :

<form change:form="beanClass mymodule_persistentdocument_mydoc">
  <input change:field="name label" />
  ...
</form>

Si beanClass est défini et beanName non, change:form utilise le nom de la classe pour déterminer beanName. Ainsi “beanClass=mymodule_persistentdocument_mydoc” implique “beanName=mydoc”.

Libellé des champs

Le libellé des champs est déterminé par la méthode BeanPropertyInfo::getLabelKey()

  • Dans le cas d'un Document, cette clef est modules.<moduleName>.document.<documentName>.<PropertyName>,
  • Dans le cas d'un bean dynamique (f_mvc_DynBean), cette clef est modules.<moduleName>.document.<shortclassname>.<PropertyName>

Propriétés pointées

Dans le cas de bean aggrégeant d'autres bean, la notation pointée “<nomSousObject>.<nomPropriété>” permet de désigner

Dans l'exemple suivant, le bean mymodule_Mydynbean déclare une propriété subBean de type mymodule_MySubBean :

class mymodule_Mydynbean
{
  private $label;
  private $subBean;
 
  /**
   * @return String
   */
  function getLabel()
  {
    return $this->label;
  }
  /**
   * @param String $value
   */
  function setLabel($value)
  {
    $this->label = $value;
  }
  /**
   * @return mymodule_MySubBean
   */
  function getSubBean()
  {
    return $this->subBean;
  }
  /**
   * @param mymodule_MySubBean $value
   */
  function setSubBean($value)
  {
    $this->subBean = $value;
  }
}
 
class mymodule_MySubBean
{
  private $stringProperty;
  private $intProperty;
 
  /**
   * @return String
   */
  function getStringProperty()
  {
    return $this->stringProperty;
  }
  /**
   * @param String $value
   */
  function setStringProperty($value)
  {
    $this->stringProperty = $value;
  }
  /**
   * @return Integer
   */
  function getIntegerProperty()
  {
    return $this->intProperty;
  }
  /**
   * @param Integer $value
   */
  function setIntegerProperty($value)
  {
    $this->intProperty = $value;
  }
}

Le formulaire suivant utilise les propriétés stringProperty et integerProperty du bean subBean :

<form change:form="beanClass mymodule_Mydynbean">
  <input change:field="name label" />
  <input change:field="subBean.stringProperty" />
  <input change:field="subBean.integerProperty" />
</form>

Beans dynamiques

La classe f_mvc_DynBean permet des implémentations rapides de f_mvc_Bean et f_mvc_BeanModel à partir de classes simples. f_mvc_DynBean inspecte la classe et retient les propriétés typées (par commentaire phpdoc) comme éléments du modèle.

Une propriété est retenue comme élément du modèle :

  • Si un accesseur (get<PropertyName>()) et un mutateur (setPropertyName()) publics sont définis. Si oui, les annotations des éléments suivants sont inspectés (dans l'ordre) pour déterminer le type de la propriété :
    • Mutateur : type du paramètre de la méthode (@param <Type> $nomParam)
    • Accesseur : type du retour de la méthode (@return <Type>)
    • Propriété : type déclaré de la propriété
  • Ou si la propriété est publique et correctement annotée (@var <Type>)

De la classe suivante seront retenue les propriétés “aString”, de type String et “anInteger”, de type Integer ; la propriété “nonAnnotated” ne sera pas retenue :

class mymodule_Mybean
{
  private $aString;
 
  /**
   * @var Integer
   */
  public $anInteger;
 
  private $nonAnnotated;
 
  /**
   * @param String $value
   */
  public function setAString($value)
  {
    $this->aString = $value;
  }
 
  /**
   * @return String
   */
  public function getAString()
  {
    return $this->aString;
  }
 
  public function setNonAnnoted($nonAnnotated)
  {
    $this->nonAnnotated = $nonAnnotated;
  }
 
  public function getNonAnnoted()
  {
    return $this->nonAnnotated;
  }
}

Le tableau suivant résume les annotations de type supportées :

Annotation de type (insensible à la casse) Equivalent Change Annotation spécifique
int ou integer Integer N.A.
float ou double Double N.A.
boolean Boolean N.A.
string Dépend de l'annotation @type, String par défaut @type{XHTMLFRAGMENT, LONGSTRNG, LOB}
date_datetime DateTime N.A.
date_date DateTime N.A.
<MODULE>_persistentdocument_<DOCUMENT>, <MODULE>_persistentdocument_<DOCUMENT>[] modules_<MODULE>/<DOCUMENT> N.A.
<UN_NOM_DE_CLASSE>, <UN_NOM_DE_CLASSE>[] N.A. N.A.

Les éléments de la classes (accesseurs, mutateurs et propriétés) peuvent être annotés :

Nom Signification Valeurs Exemple
@constraint Les contraintes à appliquer à la propriété (en plus de la conversion de type) Noms de validateurs + paramètres séparés par ';' @constraints(min:0;max:100)
@required Marque une propriété comme obligatoire N.A. @required
@listId Lie la propriété à une liste (du module list), qui définit les valeurs possibles de la propriété Un identifiant de liste @listId(modules_website/templates)

Issu du module blocksdemo, la classe blocksdemo_AnObject montre l'utilisation de la plupart des annotations :

class blocksdemo_AnObject
{
    /**
     * @required
     * @var Integer
     */
    public $anInteger;
 
    /**
     * @var String
     */
    public $aString;
 
    /**
     * @constraints(min:0;max:100)
     * @var Float
     */
    public $aDecimal;
 
    /**
     * @required
     * @var Boolean
     */
    public $aBoolean;
 
    /**
     * @var date_Date
     */
    public $aDate;
 
    /**
     * @var date_DateTime
     */
    public $aDateTime;
 
    /**
     * @var news_persistentdocument_news
     */
    public $news;
 
    /**
     * @constraints(minSize:2;maxSize:3)
     * @var news_persistentdocument_news[]
     */
    public $newsArray;
 
    /**
     * @required
     * @listId(modules_blocksdemo/documentarray)
     * @var news_persistentdocument_news[]
     */
    public $news2Array;
 
    /**
     * @type(LONGSTRING)
     * @var String
     */
    public $aLongString;
 
    /**
     * @type(XHTMLFRAGMENT)
     * @var String
     */
    public $anXHTMLFragment;
 
    /**
     * @listId(modules_website/templates)
     * @var String
     */
    public $anEnumeratedString;
 
    /**
     * @var media_persistentdocument_media
     */
    public $aMedia;
 
    /**
     * @var media_persistentdocument_media[]
     */
    public $medias;
 
    /**
     * @var website_persistentdocument_page
     */
    public $aPage;
 
    /**
     * @var media_persistentdocument_file
     */
    public $aFile;
 
    /**
     * @constraints(mimetype:image/*)
     * @var media_persistentdocument_file
     */
    public $anImage;
 
    /**
     * @var media_persistentdocument_file[]
     */
    public $files;
}

Et le gabarit suivant :

<form change:form="beanClass blocksdemo_AnObject; id anObjectForm">
<ul change:errors="" />
<ol>
        <li><input change:field="name aString" labeled="true" /></li>
        <li><input change:field="name aDecimal" labeled="true" /></li>
        <li><input change:field="name anInteger" labeled="true" /></li>
        <li><input change:field="name aBoolean" labeled="true" /></li>
        <li><input change:field="name aDate" labeled="true" /></li>
        <li><input change:field="name aDateTime" labeled="true" /></li>
        <li><input change:field="name anEnumeratedString" labeled="true" nopreamble="true" /></li>
        <li><input change:field="name news" labeled="true" /></li>
        <li><input change:field="name news.label" labeled="true" /></li>
        <li><input change:field="name newsArray" labeled="true" /></li>
        <li><input change:field="name news2Array" labeled="true" /></li>
        <li><input change:field="name aLongString" labeled="true" /></li>
        <li><input change:field="name anXHTMLFragment" labeled="true" /></li>
        <li><input change:documentpicker="name aMedia" labeled="true" /></li>
        <li><input change:documentpicker="name aPage" labeled="true" /></li>
        <li><input change:documentpicker="name medias" labeled="true" /></li>
        <li><input change:uploadfield="name aFile" labeled="true" /></li>
        <li><input change:uploadfield="name anImage" labeled="true" /></li>
        <li><input change:uploadfield="name files" labeled="true" accept="png,gif,jpg,jpeg" /></li>
        <li><input change:submit="" /></li>
</ol>
</form>

Donne le formulaire suivant :

Aggrégation

L'aggréation de beans est simplifiée par l'usage des DynBean. La classe blocksdemo_Userbean aggrège un document users_persistentdocument_user et les propriétés password et confirmPassword permettant d'assoir l'édition de l'utilisateur et de son mot de passe simplement 1) :

/**
 * @constraints(propEq:password,confirmPassword)
 */
class blocksdemo_UserBean
{
        /**
         * @var users_persistentdocument_user
         */
        public $user;
 
        /**
         * @var String
         */
        public $password;
 
        /**
         * @requiredIf(password)
         * @var String
         */
        public $confirmPassword;
 
        function getId()
        {
                if ($this->user !== null)
                {
                        return $this->user->getId();
                }
                return null;
        }
 
        static function getInstanceById($userId)
        {
                $bean = new self();
                $bean->user = DocumentHelper::getDocumentInstance($userId);
                return $bean;
        }
}

Le formulaire utilise la notation pointée “user.*” pour les propriétés de l'utlisateur :

<form change:form="beanClass blocksdemo_UserBean; id userForm" tal:condition="beanId">
        <ul change:errors="" />
        <ol>
                <li>
                        <input change:field="name beanId" />
                        <input change:field="name user.title" labeled="true" />
                </li>
                <li><input change:field="name user.firstname" labeled="true" /></li>
                <li><input change:field="name user.lastname" labeled="true" /></li>
                <li><input change:field="name user.email" labeled="true" size="30" /></li>
                <li><input change:passwordinput="name password" labeled="true" /></li>
                <li><input change:passwordinput="name confirmPassword" labeled="true" /></li>
                <li><input change:submit="" /></li>
        </ol>
</form>

Et le bloc blocksdemo_BlockDynbeanuserAction d'utiliser le bean blocksdemo_UserBean. Notez l'utilisation de BeanUtils::getSubBeanValidationRules() pour récupérer les règles de validation du document users_persistentdocument_user :

/**
 * blocksdemo_BlockDynbeanuserAction
 * @package modules.blocksdemo.lib.blocks
 */
class blocksdemo_BlockDynbeanuserAction extends website_BlockAction
{
        /**
         * @see website_BlockAction::execute()
         *
         * @param f_mvc_Request $request
         * @param f_mvc_Response $response
         * @return String
         */
        function execute($request, $response)
        {
                return $this->getSubmitInputViewName();
        }
 
        function getSubmitInputViewName()
        {
                return "Form";
        }
 
        function getSubmitInputValidationRules()
        {
                $rules = BeanUtils::getBeanValidationRules("blocksdemo_UserBean");
                $rules = array_merge($rules, BeanUtils::getSubBeanValidationRules("blocksdemo_UserBean", "user", array("firstname", "lastname", "email")));
                return $rules;
        }
 
        /**
         * @see website_BlockAction::execute()
         *
         * @param f_mvc_Request $request
         * @param f_mvc_Response $response
         * @return String
         */
        function executeSubmit($request, $response, blocksdemo_UserBean $userBean)
        {
                $request->setAttribute("anObjectVarExport", var_export($userBean, true));
                return website_BlockView::SUCCESS;
        }
}
1)
notez au passage l'utlisation de l'annotation de classe @contraints permettant et du validateur propEq qui permet de forcer deux propriétés à être égales (ici password et confirmPassword)
ref/blocs/bean.txt · Dernière modification: 2017/01/19 14:54 (modification externe)