Les formulaires - Zend Framework 1.12 partie 4

Tutorial Application Facebook PHP/JS : Les formulaires

Publié le 02/10/2013

Création d'un formulaire avec pièce jointe

  • - Mise en place d’une class de filtre
  • - Création d’un modèle de base de formulaire
  • - Création d'un modèle de formulaire avec la class Zend_Form héritant du modèle de base
  • - Création du controller gérant le formulaire
  • - Récupération du formulaire dans la vue
  • - Mise en place des décorateurs personnalisés
  • - Cas d’un formulaire avec deux champs de type file

1 - Mise en place d’une class de filtre

Nous allons mettre en place une class filtre de type Zend_Filter_Interface pour mettre en oeuvre le filtre stripeslashes. Pour ce faire nous allons créer dans le dossier Filter dans le dossier "APPLICATION_PATH"/library/Next/ et dans celui-ci nous allons créer un fichier StripeSlashes.php :


<?php
class Next_Filter_StripSlashes implements Zend_Filter_Interface {

    public function filter($value)
    {
        return get_magic_quotes_gpc() ? $this->_clean($value) : $value;
    }

    protected function _clean($value)
    {
        return is_array($value) ? array_map(array($this, '_clean'), $value) : stripslashes($value);
    }
}

Ceux deux méthodes vont se charger d’employer la fonction get_magic_quotes_gpc() qui appliquera le traitement voulu en fonction de l’activation des magic quotes dans l’environnement de production.

2 - Création d’un modèle de base de formulaire

Nous allons créer un modèle de formulaire de base dans notre librairie, qui effectuera un filtre stripslashes pour nettoyer les champs de tous les modèles de formulaire héritant de ce dernier.

Nous allons créer un dossier Next dans la library qui sera destinées aux classes spécifiques à notre application :

cd /Application/MAMP/htdocs/next/library/ mkdir Next

Et dans ce dossier on va crée un dossier Form pour les modèles de formulaires :

cd /Next/ mkdir Form

Le dossier Next sera celui dans lequel reposera la librairie de classes génériques créées pour notre application.

Dans ce dossier nous allons créer le fichier Base.php :


<?php

class Next_Form_Base extends Zend_Form {

    // Configure path to custom plugins
    public $elementPrefixPaths = array('filter' => array(
        'prefix' => 'Next_Filter',
        'path' => 'Next/Filter'
        ));
    // Shortcut to default element filters
    public $elementFilters = array(
        'StripSlashes'
        );

    public function __construct($options = null) {
        parent::__construct($options);
        $this->addElementPrefixPaths($this->elementPrefixPaths);
        $this->setElementFilters($this->elementFilters);
    }
}

3 - Création d'un modèle de formulaire avec la class Zend_Form

Nous allons maintenant créer un modèle de formulaire Contact.php qui sera exploitable dans le controller et qui héritera de la class Zend_Form dans "APPLICATION_PATH"/library/Next/Form/ :


<?php
class Next_Form_Contact extends Next_Form_Base
{
    public function init()
    {
        // initialize form
        $this->setAction('/contact/index')
             ->setEnctype('multipart/form-data')
             ->setMethod('post');

        // create select input for subject
        $subject = new Zend_Form_Element_Select('subject');
        $subject->setLabel('Objet')
                ->setMultiOptions(array('Commercial' => 'Commercial', 'Recrutement' => 'Recrutement', 'Presse' => 'Presse', 'Autres' => 'Autres'))
                ->setDecorators(array(
                    'ViewHelper',
                    array(array('data' => 'HtmlTag'), array('tag' => 'span', 'class' => 'select')),
                    array('Label', array('tag' => 'span', 'class' => 'element')),
                    array(array('field' => 'HtmlTag'), array('tag' => 'p', 'class' => 'select_field_01'))
                ));

        // create input text for lastname
        $lastname = new Zend_Form_Element_Text('lastname');
        $lastname->setLabel('Nom : ')
                 ->setOptions(array('size' => '50'))
                 ->setRequired(true)
                 ->addValidator('NotEmpty', true, array(
                        'messages' => array(
                            Zend_Validate_NotEmpty::IS_EMPTY => "Erreur : Le champ nom ne peut être vide."
                        )
                    ))
                 ->addFilter('StringTrim')
                 ->setDecorators(array(
                     'ViewHelper',
                     array(array('data' => 'HtmlTag'), array('tag' => 'span', 'class' => 'input')),
                     array('Label', array('tag' => 'span', 'class' => 'label')),
                     array(array('field' => 'HtmlTag'), array('tag' => 'p', 'class' => 'text_field_01')),
                     'Errors'
                 ));

        // create input text for surname
        $firstname = new Zend_Form_Element_Text('firstname');
        $firstname->setLabel('Prénom : ')
                  ->setOptions(array('size' => '50'))
                  ->setRequired(true)
                  ->addValidator('NotEmpty', true, array(
                  'messages' => array(
                          Zend_Validate_NotEmpty::IS_EMPTY => "Erreur : Le champ prénom ne peut être vide."
                      )
                  ))
                  ->addFilter('StringTrim')
                  ->setDecorators(array(
                      'ViewHelper',
                      array(array('data' => 'HtmlTag'), array('tag' => 'span', 'class' => 'input')),
                      array('Label', array('tag' => 'span', 'class' => 'label')),
                      array(array('field' => 'HtmlTag'), array('tag' => 'p', 'class' => 'text_field_01')),
                      'Errors'
                  ));

        // create input text for email
        $email = new Zend_Form_Element_Text('email');
        $email->setLabel('Mail : ')
              ->setOptions(array('size' => '50'))
              ->setRequired(true)
              ->addValidator('NotEmpty', true, array(
                  'messages' => array(
                      Zend_Validate_NotEmpty::IS_EMPTY => "Erreur : Le champ mail ne peut être vide."
                  )
              ))
              ->addValidator('EmailAddress', true, array(
                  'messages' => array(
                      Zend_Validate_EmailAddress::INVALID_FORMAT => "Erreur : l'adresse mail n'est pas valide."
                  )
              ))
              ->addFilter('StringToLower')
              ->addFilter('StringTrim')
              ->setDecorators(array(
                  'ViewHelper',
                  array(array('data' => 'HtmlTag'), array('tag' => 'span', 'class' => 'input')),
                  array('Label', array('tag' => 'span', 'class' => 'label')),
                  array(array('field' => 'HtmlTag'), array('tag' => 'p', 'class' => 'text_field_01')),
                  'Errors'
              ));

        // create input textarea for message
        $message = new Zend_Form_Element_Textarea('message');
        $message->setLabel('Message : ')
                ->setOptions(array('rows' => '8', 'cols' => '40'))
                ->setRequired(true)
                ->addValidator('NotEmpty', true, array(
                    'messages' => array(
                        Zend_Validate_NotEmpty::IS_EMPTY => "Erreur : Le champ message ne peut être vide."
                    )
                ))
                ->addFilter('StringTrim')
                ->setDecorators(array(
                    'ViewHelper',
                    array(array('data' => 'HtmlTag'), array('tag' => 'span', 'class' => 'input')),
                    array(array('field' => 'HtmlTag'), array('tag' => 'p', 'class' => 'textarea_field_01')),
                    'Errors'
                ));

        // create input file for attached document
        $document = new Zend_Form_Element_File('document');
        $document->setLabel('Pièce jointe : ')
                 ->addValidator('Size', false, array(
                        2000000,
                        'messages' => 'Erreur : la taille du fichier est ne peut être supérieure à 2 Mo.'
                 ))
                 ->addValidator('Extension', true, array(
                        'pdf,doc,docx,txt,rtf,zip,jpg,ppt,xls,xlsx,vcf',
                        'messages' => 'Erreur : le type de fichier n\'est pas valide.'
                 ))
                ->setDecorators(array(
                    'Label',
                    'File',
                    array(array('data' => 'HtmlTag'), array('tag' => 'p', 'class' => 'document_field_01')),
                    'Errors'
                ));

        // create submit button
        $submit = new Zend_Form_Element_Image('submit');
        $submit->setImageValue('Envoyer')
            ->setImage('/pict/general/submit.gif')
            ->removeDecorator('Label')
            ->removeDecorator('id')
            ->setDecorators(array(
            'ViewHelper',
            array(array('data' => 'HtmlTag'), array('tag' => 'p', 'class' => 'submit'))
        ));

        // attach elements to form
        $this->addElement($subject)
             ->addElement($lastname)
             ->addElement($firstname)
             ->addElement($email)
             ->addElement($message)
             ->addElement($document)
             ->addElement($submit);

        // set decorators form
        $this->setDecorators(array(
            'FormElements',
            array('Form', array('class' => 'form_01'))
        ));
    }
}

Détails du code du modèle du formulaire contact :

La partie du code s’occupant de l’initialisation du formulaire, comportera un setEnctype pour l’envoie de pièce jointes et un setMethod pour l’envoi des données en POST :

Les filtres et validateurs vont faire les contrôles voulus sur les champs du formulaire.

Les validateurs vont afficher les messages d'erreurs.


// initialize form
$this->setAction('/contact/index')
     ->setEnctype('multipart/form-data')
     ->setMethod('post')
     ->addValidator('NotEmpty', true, array(
        'messages' => array(
            Zend_Validate_NotEmpty::IS_EMPTY => "Erreur : le champ message ne peut être vide."
        )
     ));

Détails du champ document :


// create input file for attached document
$document = new Zend_Form_Element_File('document');
$document->setLabel('Pièce jointe : ')
         ->addValidator('Size', false, array(
                2000000,
                'messages' => 'Erreur : la taille du fichier est ne peut être supérieure à 2 Mo.'
         ))
         ->addValidator('Extension', true, array(
                'pdf, doc, docx, txt, rtf, zip, jpg, ppt, xls, xlsx, vcf',
                'messages' => 'Erreur : le type de fichier n\'est pas valide.'
         ));

Ressources en ligne sur les Zend_Form_Element : http://framework.zend.com/manual/fr/zend.form.standardElements.html

4 - Création du controller gérant le formulaire

Dans le controller ContactController.php du module default, ajouter les méthodes indexAction() et successAction(). Ne pas oublier de créer la route dans application.ini :


public function indexAction()
{
    $form = new Next_Form_Contact();
    $this->view->form = $form;
    if($this->getRequest()->isPost())
    {
        if($form->isValid($this->getRequest()->getPost()))
        {
            $values = $form->getValues();
            $mail = new Zend_Mail();
            $mail->setBodyText($values['message']);
            $mail->setFrom($values['email'], $values['lastname']);
            $mail->addTo('pierre-antoine.foulquier@next.com');
            $mail->setSubject('CONTACT NEXT.COM :');
            if ($form->document->isUploaded() && $form->document->receive())
            {
               $attachment = new Zend_Mime_Part(file_get_contents($form->document->getFileName()));
               $attachment->type = $form->document->getMimeType();
               $attachment->disposition = Zend_Mime::DISPOSITION_ATTACHMENT;
               $attachment->encoding = Zend_Mime::ENCODING_BASE64;
               $attachment->filename = $form->document->getFileName(null, false);
               $mail->addAttachment($attachment);
            }
            $mail->send();
            $this->view->message = 'Votre message a été envoyé';
        }
    }
}
public function successAction()
{
    if($this->_helper->getHelper('FlashMessenger')->getMessages())
    {
        $this->view->messages = $this->_helper->getHelper('FlashMessenger')->getMessages();
    }
    else
    {
        $this->_redirect('/');
    }
}

5 - Récupération du formulaire dans la vue

Nous allons créer une vue index.phtml pour notre rubrique contact qui contiendra le formulaire dans :

"APPLICATION_PATH"/application/modules/default/views/script/contact/

Dans la vue, ajouter la ligne suivante pour appeler le formulaire :

<?php echo $this->form; ?>

Et pour le message de succès pour l'envoie du formulaire :

<?php echo $this->message; ?>

6 - Mise en place des décorateurs personnalisés

A l’aide des ressources suivantes nous allons créer des Decorators personnalisés pour les balises html de notre formulaire :

Les liens suivants m’ont aidé à comprendre le comportement de chaque type de de Zend_Form_Element :

Dans le modèle de formulaire "APPLICATION_PATH"/library/Next/Form/Contact.php, le code suivant va définir la première balise

de notre formulaire :


// set decorators form
$this->setDecorators(array(
  'FormElements',
  array('Form', array('class' => 'form_01'))
));

Notre formulaire comporte plusieurs types de champs :

select input type="text" textarea input type="file" input type="image"

A chaque type de champ de formulaire va correspondre des décorateurs.

Le décorateur select :


->setDecorators(array(
    'ViewHelper',
    array(array('data' => 'HtmlTag'), array('tag' => 'span', 'class' => 'select')),
    array('Label', array('tag' => 'span', 'class' => 'element')),
    array(array('field' => 'HtmlTag'), array('tag' => 'p', 'class' => 'select_field_01'))
));

La méthode setDecorators reçoit comme argument, un tableau contant les valeurs qui vont générer nos décorateurs d’éléments de formulaire. Le tableau est constitué des données suivante :

La valeur ‘ViewHelper’ indiquant quel élément nous allons redéfinir (les décorateurs disposent de valeurs par défaut).

Les suivantes seront des tableaux qui vont définir la structure et la composition de nos balises :

- La première ligne va définir la balise du ViewHelper englobant le select, ici un span.select :

array(array('data' => 'HtmlTag'), array('tag' => 'span', 'class' => 'select')),

- La seconde ligne va définir la balise du Label englobant le label, ici un span.element :

array('Label', array('tag' => 'span', 'class' => 'element')),

- La dernière ligne va définir la balise englobant le la label et le select, ici un p.select_field_01 :

array(array('field' => 'HtmlTag'), array('tag' => 'p', 'class' => 'select_field_01'))

- Le décorateur input type="text" :


->setDecorators(array(
    'ViewHelper',
    array(array('data' => 'HtmlTag'), array('tag' => 'span', 'class' => 'input')),
    array('Label', array('tag' => 'span', 'class' => 'label')),
    array(array('field' => 'HtmlTag'), array('tag' => 'p', 'class' => 'text_field_01')),
    'Errors'
));

La méthode setDecorators reçoit comme argument, un tableau contant les valeurs qui vont générer nos décorateurs d’éléments de formulaire. Le tableau est constitué des données suivante :

La valeur ‘ViewHelper’ indiquant quel élément nous allons redéfinir (les décorateurs disposent de valeurs par défaut).

Les suivantes seront des tableaux qui vont définir la structure et la composition de nos balises :

- La première ligne va définir la balise du ViewHelper englobant le input, ici un span.input :

array(array('data' => 'HtmlTag'), array('tag' => 'span', 'class' => 'input')),

- La seconde ligne va définir la balise du Label englobant le label, ici un span.element :

array('Label', array('tag' => 'span', 'class' => 'label')),

- La troisème ligne va définir la balise englobant le la label et le select, ici un p.text_field_01 :

array(array('field' => 'HtmlTag'), array('tag' => 'p', 'class' => 'text_field_01'))

La dernière valeur ‘Errors’ fera apparaître les messages d’erreur du form. On laisse par défaut, elle génère les message dans un ul.-Le décorateur textarea :


->setDecorators(array(
    'ViewHelper',
    array(array('data' => 'HtmlTag'), array('tag' => 'span', 'class' => 'input')),
    array(array('field' => 'HtmlTag'), array('tag' => 'p', 'class' => 'textarea_field_01')),
    'Errors'
));

On définira son décorateur de la même façon qu’avec la balise input type="text". Ici on ne souhaitera pas avoir de label, donc pas de tableau de ce dernier.

Le décorateur input type="file" :


->setDecorators(array(
    'Label',
    'File',
    array(array('data' => 'HtmlTag'), array('tag' => 'p', 'class' => 'document_field_01')),
    'Errors'
));

La balise input type="file" aura les valeurs ‘Label’ et ‘File’.

- Le décorateur input type="image" :


    ->removeDecorator('Label')
    ->removeDecorator('id')
    ->setDecorators(array(
    'ViewHelper',
    array(array('data' => 'HtmlTag'), array('tag' => 'p', 'class' => 'submit'))
));

Les méthodes removeDecorator() vont permettre de supprimer des décorateurs affectés par défaut.

Le décorateur fieldset :


// display group organization
$form->addDisplayGroup(array(
        'id_sector',
        'name_sector'
), 'sector')
     ->addDisplayGroup(array(
        'id_customer',
        'name_customer',
), 'customer')
     ->addDisplayGroup(array(
         'id_project',
         'name_project',
         'url_project'
), 'project')
     ->addDisplayGroup(array(
         'id_realisation',
         'position',
         'title',
         'description',
         'text',
         'subtitle',
         'year',
         'type',
         'status',
         'thumbnail',
         'url',
         'id_propre',
         'video',
         'video_width',
         'video_height'
), 'realisation')
    ->addDisplayGroup(array(
        'picture'
), 'document')
    ->setDisplayGroupDecorators(array(
        'FormElements',
        'Fieldset',
));

Le décorateur sera appliqué dans notre controller après avoir créer le formulaire.

7 - Cas d’un formulaire avec deux champs de type file

Dans le formulaire RealisationFullCreate.php du module admin de notre application, nous allons employer deux champs de formulaire de type file. Il s’est avéré que le fichier du deuxième champs ne reussi se copier dans le dossier de destination sur le serveur.

Pour cela nous allons tester dans le controller si la réception a bien eut lieu :


// test if picture file is received
if (!$form->picture->receive())
{
    print "Erreur de réception de fichier picture";
}

Code du formulaire "APPLICATION_PATH"/library/Next/Form/RealisationFullCreate.php :


<?php
class Next_Form_RealisationFullCreate extends Next_Form_Base
{
    public function init()
    {
         // initialize form
        $this->setAction('/admin/realisation-full/create')
             ->setAttrib('enctype', 'multipart/form-data')
             ->setMethod('post');

        /* SECTOR INPUT ELEMENTS */

        // create select input for id_sector/sector name
        $id_sector = new Zend_Form_Element_Select('id_sector');
        $id_sector->setLabel('Secteur d\'activité :')
                  ->setRequired(true)
                  ->addValidator('Int')
                  ->addFilter('StringTrim')
                  ->addFilter('StringToUpper');
        foreach (Next_Model_Sectors::getSectors() as $s)
        {
            $id_sector->addMultiOption($s['id'], $s['name']);
        }
        $id_sector->addMultiOption('0', 'nouveau secteur');

        // create text input for sector
        $name_sector = new Zend_Form_Element_Text('name_sector');
        $name_sector->setLabel('Secteur d\'activité :')
                    ->setOptions(array('size' => '50'))
                    ->setRequired(true)
                    ->addValidator('NotEmpty', true, array(
                    'messages' => array(
                        Zend_Validate_NotEmpty::IS_EMPTY => "Erreur : Le champ secteur ne peut être vide."
                    )
        ))
                    ->addFilter('StringTrim');

        /* CUSTOMER INPUT ELEMENTS */

        // create select input for id_customer/customer name
        $id_customer = new Zend_Form_Element_Select('id_customer');
        $id_customer ->setLabel('Client : ')
            ->setRequired(true)
            ->addValidator('Int')
            ->addFilter('StringTrim')
            ->addFilter('StringToUpper');
        foreach (Next_Model_Customers::getCustomers() as $c)
        {
            $id_customer->addMultiOption($c['id'], $c['name']);
        }
        $id_customer->addMultiOption('0', 'nouveau client');

        // create text input for customer name
        $name_customer = new Zend_Form_Element_Text('name_customer');
        $name_customer->setLabel('Client : ')
                      ->setOptions(array('size'=> '50'))
                      ->setRequired(true)
                      ->addValidator('NotEmpty', true, array(
                          'messages' => array(
                          Zend_Validate_NotEmpty::IS_EMPTY => 'Erreur : Le champ clients ne peut être vide.'
                      )
        ))
            ->addFilter('StringTrim');

        /* PROJECT INPUT ELEMENTS */

        // create select input for id_project/project name
        $id_project = new Zend_Form_Element_Select('id_project');
        $id_project ->setLabel('Projet : ')
                    ->setRequired(true)
                    ->addValidator('Int')
                    ->addFilter('StringTrim')
                    ->addFilter('StringToUpper');
        foreach (Next_Model_Projects::getProjects() as $project)
        {
            $id_project->addMultiOption($project['id'], $project['name']);
        }
        $id_project->addMultiOption('0', 'nouveau projet');

        // create input for project name
        $name_project = new Zend_Form_Element_Text('name');
        $name_project->setLabel('Nom du projet : ')
                     ->setOptions(array('size' => '50'))
                     ->setRequired(true)
                     ->addValidator('NotEmpty', true, array(
                         'messages' => array(
                             Zend_Validate_NotEmpty::IS_EMPTY => 'Erreur : Le champ ne peut être vide.'
                         )
                     ))
                     ->addFilter('StringTrim');

        // create input for project url
        $url_project = new Zend_Form_Element_Text('url_project');
        $url_project->setLabel('Url projet : ')
                    ->setOptions(array('size' => '50'))
                    ->addFilter('StringTrim');

        /* REALISATION INPUT ELEMENTS */

        // create input for title
        $title_realisation = new Zend_Form_Element_Text('title');
        $title_realisation->setLabel('Titre réalisation :')
                          ->setRequired(true)
                          ->setOptions(array('size' => '50'))
                          ->addFilter('StringTrim');

        // create input for position
        $position = new Zend_Form_Element_Text('position');
        $position->setLabel('Position :')
                 ->setRequired(true)
                 ->addValidator('Int')
                 ->setOptions(array('size' => '50'))
                 ->addFilter('StringTrim');

        // create input for description
        $description = new Zend_Form_Element_Text('description');
        $description->setLabel('Description :')
                    ->setRequired(true)
                    ->setOptions(array('size' => '50'))
                    ->addFilter('StringTrim');

        // create input for text
        $text = new Zend_Form_Element_Textarea('text');
        $text->setLabel('Texte : ')
             ->setRequired(true)
             ->addFilter('StringTrim');

        // create input for subtitle
        $subtitle = new Zend_Form_Element_Text('subtitle');
        $subtitle->setLabel('Sous-titre : ')
                 ->setRequired(true)
                 ->addFilter('StringTrim');

        // create input for year
        $year = new Zend_Form_Element_Text('year');
        $year->setLabel('Année : ')
             ->setRequired(true)
             ->addValidator('Int')
             ->addFilter('StringTrim');

        // create input for type
        $type = new Zend_Form_Element_Text('type');
        $type->setLabel('Type :')
            ->setRequired(true)
            ->addFilter('StringTrim');

        // create input for status
        $status = new Zend_Form_Element_Text('status');
        $status->setLabel('status')
            ->setRequired(true)
            ->addValidator('Int')
            ->addFilter('StringTrim');

        // create input for thumbnail
        $thumbnail = new Zend_Form_Element_File('thumbnail');
        $thumbnail->setLabel('Vignette : ')
            ->setDestination(PUBLIC_PATH . '/img/portfolio/')
            ->addValidator('Count', false, 1)
            ->addValidator('Size', false, array(
            2000000,
            'message' => 'la taille du fichier est ne peut être supérieure à 2 Mo.'
        ))
            ->addValidator('Extension', true, array(
            'jpg',
            'messages' => 'Erreur : le type de fichier n\'est pas valide : Doit être .jpg'
        ));

        // create input for url
        $url_realisation = new Zend_Form_Element_Text('url');
        $url_realisation->setLabel('Url realisation : ')
                        ->setRequired(true)
                        ->addFilter('StringTrim');

        // create input for id_propre
        $id_propre = new Zend_Form_Element_Text('id_propre');
        $id_propre->setLabel('Id propre')
                  ->setRequired(true)
                  ->addFilter('StringTrim');

        // create input for video
        $video = new Zend_Form_Element_Text('video');
        $video->setLabel('Video')
              ->addFilter('StringTrim');

        // create input for video_width
        $video_width = new Zend_Form_Element_Text('video_width');
        $video_width->setLabel('Video largeur : ')
                    ->addValidator('Int')
                    ->addFilter('StringTrim');

        // create input for video_height
        $video_height = new Zend_Form_Element_Text('video_height');
        $video_height->setLabel('Video hauteur : ')
                     ->addValidator('Int')
                     ->addFilter('StringTrim');


        /* DOCUMENT INPUT ELEMENTS */

        // create input for picture
        $picture = new Zend_Form_Element_File('picture');
        $picture->setLabel('Image : ')
                ->setDestination(PUBLIC_PATH . '/img/portfolio/details/')
                ->addValidator('Count', false, 1)
                ->addValidator('Size', false, array(
                    2000000,
                    'message' => 'la taille du fichier est ne peut être supérieure à 2 Mo.'
                ))
                ->addValidator('Extension', true, array(
                    'jpg',
                    'messages' => 'Erreur : le type de fichier n\'est pas valide : Doit être .jpg'
                ));


        /* SUBMIT BUTTON */

        // create submit button
        $submit= new Zend_Form_Element_Submit('submit');
        $submit->setLabel('Submit Entry')
               ->setOrder(100)
               ->setOptions(array('class' => 'submit'));

        // attach element to form
        $this->addElement($id_project)
             ->addElement($name_project)
             ->addElement($id_customer)
             ->addElement($name_customer)
             ->addElement($id_sector)
             ->addElement($name_sector)
             ->addElement($url_project)
             ->addElement($title_realisation)
             ->addElement($position)
             ->addElement($description)
             ->addElement($text)
             ->addElement($subtitle)
             ->addElement($year)
             ->addElement($type)
             ->addElement($status)
             ->addElement($thumbnail)
             ->addElement($url_realisation)
             ->addElement($id_propre)
             ->addElement($video)
             ->addElement($video_width)
             ->addElement($video_height)
             ->addElement($picture)
             ->addElement($submit);
    }
}

Détails du champ thumbnail dans le form RealisationFullCreate.php :


// create input for thumbnail
$thumbnail = new Zend_Form_Element_File('thumbnail');
$thumbnail->setLabel('Vignette : ')
          ->setDestination(PUBLIC_PATH . '/img/portfolio/')
          ->addValidator('Count', false, 1)
          ->addValidator('Size', false, array(
            2000000,
            'message' => 'la taille du fichier est ne peut être supérieure à 2 Mo.'
          ))
          ->addValidator('Extension', true, array(
            'jpg',
            'messages' => 'Erreur : le type de fichier n\'est pas valide : Doit être .jpg'
          ));

La méthode setDestination de Zend_Form_Element_File définie où la photo sera uploadée :

->setDestination(PUBLIC_PATH . '/img/portfolio/')

Code du controller "APPLICATION_PATH"/application/modules/admin/controller/RealisationFullController.php :


<?php

class Admin_RealisationFullController extends Next_Controller_AdminController
{

    public function init()
    {
        // get parent init()
        parent::init();

        // define place holder navigation
        $this->view->placeholder('rubrique')->set('realisation-full');
        $this->_helper->layout->setLayout('admin_realisation_full');
    }

    // action to display list of realisations full items
    public function indexAction()
    {
        $this->view->records = Next_Model_Realisations::getFullRealisations();
    }

    // action to create a realisation full item
    public function createAction()
    {
        // generate input form
        $form = new Next_Form_RealisationFullCreate();

        // display group organization
        $form->addDisplayGroup(array(
            'id_sector',
            'name_sector'
        ), 'sector')
             ->addDisplayGroup(array(
            'id_customer',
            'name',
        ), 'customer')
             ->addDisplayGroup(array(
             'name_project',
             'url_project'
        ), 'project')
             ->addDisplayGroup(array(
             'id_project',
             'position',
             'title',
             'description',
             'text',
             'subtitle',
             'year',
             'type',
             'status',
             'thumbnail',
             'url',
             'id_propre',
             'video',
             'video_width',
             'video_height'
        ), 'realisation')
            ->addDisplayGroup(array(
            'picture'
        ), 'document');

        // send form to the view
        $this->view->form = $form;

        // test for valid input
        // if valid, populate model
        // save to database
        if($this->getRequest()->isPost())
        {
            // method to toggle new item input field
            // store post data and test if value option select sector is not 0
            $postData = $this->getRequest()->getPost();

            // test if selects values are null for set input field as required
            if($postData['id_sector'] != '0')
            {
                $form->name_sector->setRequired(false);
            }

            if($postData['id_customer'] != '0')
            {
                $form->name_customer->setRequired(false);
            }

            if($postData['id_project'] != '0')
            {
                $form->name->setRequired(false);
            }

            // test if form is valid and insert in database
            if($form->isValid($postData))
            {

                // get id's from post
                $id_project = $form->getValue('id_project');

                $id_customer = $form->getValue('id_customer');

                $id_sector = $form->getValue('id_sector');

                // test if id_sector is new
                if($postData['id_sector'] == 0)
                {
                    $sector = new Next_Model_Sectors();
                    $sector_tab = array(
                        'name' => $postData['name_sector']
                    );

                    $sector->fromArray($sector_tab);
                    $sector->save();

                    $id_sector_tab = $sector->identifier();
                    $id_sector = $id_sector_tab['id'];
                }
                else
                {
                    $id_sector = $postData['id_sector'];
                }

                // test if id_customer is new
                if($postData['id_customer'] == 0)
                {
                    $customer = new Next_Model_Customers();
                    $customer_tab = array(
                        'name' => $postData['name_customer'],
                        'id_sector' => $id_sector
                    );
                    $customer->fromArray($customer_tab);
                    $customer->save();
                    $id_customer_tab = $customer->identifier();
                    $id_customer = $id_customer_tab['id'];
                }
                else
                {
                    $id_customer = $postData['id_customer'];
                }

                // test if project is new
                if($postData['id_project'] == 0)
                {
                    $project = new Next_Model_Projects();
                    $project_tab = array(
                        'id_customer' => $id_customer,
                        'name' => $postData['name'],
                        'url' => $postData['url_project']
                    );
                    $project->fromArray($project_tab);
                    $project->save();
                    $id_project_tab = $project->identifier();
                    $id_project = $id_project_tab['id'];
                }
                else
                {
                    $id_project = $postData['id_project'];
                }

                // insert realisations table
                $realisation_full = new Next_Model_Realisations();
                $realisation_full_tab = array(
                    'id_project' => $id_project,
                    'position' => $form->getValue('position'),
                    'title' => $form->getValue('title'),
                    'description' => $form->getValue('description'),
                    'text' => $form->getValue('text'),
                    'subtitle' => $form->getValue('subtitle'),
                    'year' => $form->getValue('year'),
                    'type' => $form->getValue('type'),
                    'status' => $form->getValue('status'),
                    'thumbnail' => $form->getValue('thumbnail'),
                    'url' => $form->getValue('url'),
                    'id_propre' => $form->getValue('id_propre'),
                    'video' => $form->getValue('video'),
                    'video_width' => $form->getValue('video_width'),
                    'video_height' => $form->getValue('video_height')
                );

                $realisation_full->fromArray($realisation_full_tab);
                $realisation_full->save();

                /* insert picture document in db */

                // test if picture is empty
                if($_FILES['picture']['size'] == 0)
                {
                    // replace old picture value in input
                    $input['picture'] = $picture;
                }

                // retrieve id last realisation insert
                $id_realisation_tab = $realisation_full->identifier();
                $id_realisation = $id_realisation_tab['id'];

                // insert document table
                $document = new Next_Model_Documents();
                $document_tab = array(
                    'id_realisation' => $id_realisation,
                    'picture' => $_FILES['picture']['name']
                );

                $document->fromArray($document_tab);
                $document->save();



                // test if picture file is received
                if (!$form->picture->receive())
                {
                    $this->_helper->getHelper('FlashMessenger')->addMessage('Erreur de réception de fichier picture.');
                }

                // message and redirection
                $this->_helper->getHelper('FlashMessenger')->addMessage('Entrée ajoutée à la base.');
                $this->_redirect('/admin/realisation-full/');
            }
        }
    }

    // action to delete realisation item
    public function deleteAction()
    {
        // set filters and validators for POST input
        $filters = array(
            'id' => array('HtmlEntities', 'StripTags', 'StringTrim')
        );
        $validators = array(
            'id' => array('NotEmpty', 'Int')
        );
        $input = new Zend_Filter_Input($filters, $validators);
        $input->setData($this->getRequest()->getParams());

        // retrieve record from children realisation records
        $documentRealisation = Next_Model_Realisations::getRealisationChildren($input->id);

        // test if input have children
        if(!$documentRealisation)
        {
            // test if input is valid
            // read array of record identifiers
            // delete records from database
            if ($input->isValid())
            {
                // delete selected realisation
                $result = Next_Model_Realisations::deleteRealisation($input->id);

                // message and redirection
                $this->_helper->getHelper('FlashMessenger')->addMessage('L\'enregistrement a été effacé avec succès');
                $this->_redirect('/admin/realisation-full/');
            }
            else
            {
                throw new Zend_Controller_Action_Exception('Invalid input');
            }
        }
        else
        {
            $this->_helper->getHelper('FlashMessenger')->addMessage('L\'enregistrement ne peut être effacé : il contient des documents');
            $this->_redirect('/admin/realisation-full/');
        }
    }

    // action to modify an individual realisation item
    public function updateAction()
    {
        // generate input form
        $form = new Next_Form_RealisationFullUpdate();
        $this->view->form = $form;

        if($this->getRequest()->isPost())
        {
            // if POST request
            // test if input is valid
            // retrieve current record
            // update values and save in database
            $postData = $this->getRequest()->getPost();

            // test if selects values are null for set input field as required
            if($postData['id_sector'] != '0')
            {
                $form->name_sector->setRequired(false);
            }

            if($postData['id_customer'] != '0')
            {
                $form->name_customer->setRequired(false);
            }

            if($postData['id_project'] != '0')
            {
                $form->name->setRequired(false);
            }

            // test if form is valid and insert in database
            if($form->isValid($postData))
            {
                // get id's from post
                $id_project = $form->getValue('id_project');
                $id_customer = $form->getValue('id_customer');
                $id_sector = $form->getValue('id_sector');

                // test if id_sector is new
                if($postData['id_sector'] == 0)
                {
                    $sector = new Next_Model_Sectors();
                    $sector_tab = array(
                        'name' => $postData['name_sector']
                    );

                    $sector->fromArray($sector_tab);
                    $sector->save();

                    $id_sector_tab = $sector->identifier();
                    $id_sector = $id_sector_tab['id'];
                }
                else
                {
                    $id_sector = $postData['id_sector'];
                }

                // test if id_customer is new
                if($postData['id_customer'] == 0)
                {
                    $customer = new Next_Model_Customers();
                    $customer_tab = array(
                        'name' => $postData['name_customer'],
                        'id_sector' => $id_sector
                    );

                    $customer->fromArray($customer_tab);
                    $customer->save();

                    $id_customer_tab = $customer->identifier();
                    $id_customer = $id_customer_tab['id'];
                }
                else
                {
                    $id_customer = $postData['id_customer'];
                }

                // test if project is new
                if($postData['id_project'] == 0)
                {
                    $project = new Next_Model_Projects();
                    $project_tab = array(
                        'id_customer' => $id_customer,
                        'name' => $postData['name'],
                        'url' => $postData['url_project']
                    );

                    $project->fromArray($project_tab);
                    $project->save();
                    $id_project_tab = $project->identifier();
                    $id_project = $id_project_tab['id'];
                }
                else
                {
                    $id_project = $postData['id_project'];
                }

                // get the id from the current record
                $input = $form->getValues();

                // get selected realisation item thumbnail from database
                $id = $this->getRequest()->getParam('id');

                $result = Next_Model_Realisations::getRealisation($id);

                $thumbnail = $result[0]['thumbnail'];

                // test if thumbnail is empty
                if($_FILES['thumbnail']['size'] == 0)
                {
                    // replace old thumbnail value in input
                    $input['thumbnail'] = $thumbnail;

                }

                // update realisations table
                $realisation_full = Doctrine::getTable('Next_Model_Realisations')->find($input['id']);
                $realisation_full_tab = array(
                    'id' => $input['id'],
                    'id_project' => $id_project,
                    'position' => $form->getValue('position'),
                    'title' => $form->getValue('title'),
                    'description' => $form->getValue('description'),
                    'text' => $form->getValue('text'),
                    'subtitle' => $form->getValue('subtitle'),
                    'year' => $form->getValue('year'),
                    'type' => $form->getValue('type'),
                    'status' => $form->getValue('status'),
                    'thumbnail' => $input['thumbnail'],
                    'url' => $form->getValue('url'),
                    'id_propre' => $form->getValue('id_propre'),
                    'video' => $form->getValue('video'),
                    'video_width' => $form->getValue('video_width'),
                    'video_height' => $form->getValue('video_height')
                );

                $realisation_full->fromArray($realisation_full_tab);
                $realisation_full->save();

                // message and redirection
                $this->_helper->getHelper('FlashMessenger')->addMessage('Entrée mise à jour.');
                $this->_redirect('/admin/realisation-full/');
            }
        }
        else
        {
            // if GET request
            // set filters and validators for GET input
            // retrieve requested record
            // pre-populate form
            $filters = array(
                'id' => array('HtmlEntities', 'StripTags', 'StringTrim')
            );
            $validators = array(
                'id' => array('NotEmpty', 'Int')
            );
            $input = new Zend_Filter_Input($filters, $validators);
            $input->setData($this->getRequest()->getParams());
            if($input->isValid())
            {
                // get selected realisation item
                $result = Next_Model_Realisations::getRealisation($input->id);

                if(count($result) == 1)
                {
                    $this->view->form->populate($result[0]);
                }
                else
                {
                    throw new Zend_Controller_Action_Exception('Page not found', 404);
                }
            }
            else
            {
                throw new Zend_Controller_Action_Exception('Invalid input');
            }
        }
    }
}