Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 21-02-2008 12:54:49

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

Contrôleur CRUD abstrait [+ sources]

voici les premières docs concernant le controleur CRUD abstrait que j'ai développé, en m'inspirant du travail de sekaijin et 2mx. et en l'assaisonnant selon mes besoins

les documents sont un ensemble d'images PNG (+ sources en SVG) avec quelques fichiers textes bruts de réflexions préalables.

les commentaires détaillés de ces images et bien entendu le code source arriveront un peu plus tard

www.eozine.fr/temp/CRUD/index.php

bonne lecture,

Héfeust


je viens d'ajouter le source provisoire à la même adresse : archive "applicado.zip"
commentaires et compléments de doc la semaine prochaine !

Dernière modification par hefeust (22-02-2008 19:03:05)

Hors ligne

 

#2 21-02-2008 13:06:39

Mr.MoOx
Administrateur
Lieu: Toulouse
Date d'inscription: 27-03-2007
Messages: 1444
Site web

Re: Contrôleur CRUD abstrait [+ sources]

Manque pas un lien...??

Hors ligne

 

#3 21-02-2008 14:33:26

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

Re: Contrôleur CRUD abstrait [+ sources]

Hors ligne

 

#4 21-02-2008 16:15:58

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: Contrôleur CRUD abstrait [+ sources]

j'ai moi aussi avancé sur mon approche de CRUD générique.
Je me suis basé sur le patron d'architecture MVC de Zend que j'ai dérivé pour mettre en place le patron de comportement CRUD que j'ai basé sur le design pattern PRG

C'est clair là non ? big_smile

bon trêve de plaisanterie. j'ai donc dérivé les classes Zend_Controller_Action Zend_Db_Table
pour implémenter la base de mon système.
pour faire un CRUD j'ai besoin des fichier suivants
showList.phtm showForm.phtml confirm.phtml pour les vue qui affiche la liste des élément, le formulaire de saisie  et une demande de confirmation pour la suppression.
un fichier Element.php qui contient le modèle (métier) où une façade sur ce dernier.
et enfin un crudController.php qui est mon contrôleur et son fichier de parametres moduleControleur.ini
(j'utilise un moteur de template  mes vues sont donc en html) mais voici un exemple client

Code:

-- Création table client

CREATE TABLE `client` (
  `cli_id` int(10) unsigned NOT NULL auto_increment,
  `cli_code` varchar(10) collate latin1_bin default NULL,
  `cli_name` varchar(30) collate latin1_bin default NULL,
  `cli_firstname` varchar(30) collate latin1_bin default NULL,
  `cli_valid` int(11) NOT NULL default '1',
  PRIMARY KEY  (`cli_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;

le modèle

Code:

<?php
/*
    Ici est définit le molèle métier client.
    
    on y trouve toutes les fonction qui traite de client.
    Ce n'est qu'une façade, un interface qui donne accès aux objets qui compose ce métier
    
*/
Zend_Loader::loadClass('Fast_Model_Component');
require_once dirname(__FILE__).'/Client/Table.php';

class Model_Client extends Fast_Model_Component
{
   /**
    *  @var Zend_Db_Adapter_Abstract
    */
   private $_db;

   public function __construct()
   {      
      // On va avoir besoin de la base.
      $this->_db = Fast_Registry::get('dbAdapter');
   }

    /*
    retourne un tableau alphabétique avec le nombre
    d'enregistrements pour chaque lettre
    */
   public function getClientAlphabetic() {
      $table = new Model_Client_Table();
      return $table->getAlphabeticCount('cli_name');
   }

    /*
    retourne la liste des client (tableau d'objet)
    */
   public function getClientList() {
      $table = new Model_Client_Table();
      return $table->getList();
   } 


    /*
    retourne la liste des client dont le nom commence par $nameStart
    (tableau d'objet)
    */
   public function getAlphabeticClientList($nameStart = null) {
      $table = new Model_Client_Table();
      return $table->getList($nameStart);
   } 

    /*
     Créé un nouvel objet client
     soit un objet vierge soit si $obj est null
     soit un objet réparer avec les valeur de $obj
    */
   public function newClient($obj = null) {
      $table = new Model_Client_Table();
      $client = $table->newRow($obj);
      return $client;
   }

    /*
    recherche un client par son id
    */
   public function getClientById($id) {
      $table = new Model_Client_Table();
      return $table->getById($id);
   }

    /*
    supprime un client par son id
    */
   public function deleteClientById($id) {
      $table = new Model_Client_Table();
      return $table->deleteById($id);
   }

}

le contrôleur

Code:

<?php
/*
 Ceci est le contôleur de gestion des client.
 C'est un CRUD (Create, Retrive, Update and Delete pattern)
 C'est une implémentation dans le design pattern MVC (http://en.wikipedia.org/wiki/Model-view-controller)
 du design PRG (http://en.wikipedia.org/wiki/Post/Redirect/Get)
*/
Zend_Loader::loadClass("Client_Controllers_Action");

/**
 * Contrôleur gestion des client (CRUD)
 *
 * @author Jean-Yves Terrien
 *
 */
class Client_ManagerController extends Client_Controllers_Action
{
   protected $_isCrud = true;

   public function init()
   {
      parent::init();
      //Chargement du modèle (métier client)
      $this->model->addComponent('Model_Client' , dirname(dirname(dirname(__FILE__))));
   }

   /*
        Méthode de vérification des champs du formulaire
    */
    protected function _verifForm() {
        Zend_Loader::loadClass('Fast_Validate');

        $verifForm = array(
        'cli_code'      => array('required'    => "Le code client est obligatoire"),
        'cli_name'      => array('required'    => "Le nom est obligatoire"),
        'cli_firstname' => array('required'    => "Le prénom est obligatoire")
        );
        $validate = new Fast_Validate($this->context->formData, $verifForm);
        return parent::_performVerif($validate);
    }

    /*
        Filtrage des données issues du formulaire
    */
    protected function _filter($form) {
        Zend_Loader::loadClass('Zend_Filter');
        Zend_Loader::loadClass('Zend_Filter_StripTags');
        Zend_Loader::loadClass('Zend_Filter_StringTrim');
        $filter = new Zend_Filter();
        $filter->addFilter(new Zend_Filter_StripTags());
        $filter->addFilter(new Zend_Filter_StringTrim());
        foreach ($form as $key=>$value) {
            $this->context->formData->$key = $filter->filter($value);
        }
    }
}

le fichier de paramètres

Code:

;méthodes d'accès au données.
[methods]
_getList            = getAlphabeticClientList
_getAlphabeticCount = getClientAlphabetic
_newItem            = newClient
_getItemById        = getClientById
_deleteItemById     = deleteClientById

;Liste des massages
[messages]
noItemFor       = Aucun Client pour l'initiale :
unknowItem      = Enregistrement introuvable :
invalidFormData = Les données du formulaire sont invalides
saved           = Enregistrement effectué
unsaved         = Impossible d'enregistrer
deleted         = Client définitivement supprimé
undeleted       = Impossible de supprimer le client

;Titre des différents écrans
[titles]
showList      = Gestion des clients
deleteConfirm = Suppression du client
add           = Création d'un client
update        = Mise à jour d'un client

;Libelé des boutons
[buttons]
cancel = Retour
save   = Enregistrer
add    = Ajouter un client
delete = Supprimer
return = Retour

[datas]
// nom du champs pour la recherche alphabétique
_alphabeticField = cli_name;

et les vues

Code:

{* Modèle d'affichage de la liste des clients *}
{mask:content}
<h1>{page/title}</h1>
<p class="collapse">Ajouter ou modifier des clients.</p>
<div fast:tabLabel="Liste">
        <table id='datagrid' fast:class="Grid"
       fast:options="tableHeight: 350, tableWidth: 500,
                     rowClass: 'hoverrow', clickClass: 'click',
                     headRows: false, footRows: true, headCols: true, footCols: true"
       class="listing" border="0" cellspacing="0" cellpadding="0">
   {set:alphabet}
   <caption class="alphabet">
   {mask:alphabet}
      {if:{nb}>0}<strong>{/if}<a class="LienTitre" href="{//crud/listAction}nameStart/{letter}">{letter}</a>{if:{nb}>0}</strong>{/if}&nbsp;
   {/mask}
   </caption>
   {/set}
<thead>
   <tr>     
      <th>Nom</th>
      <th>Prénom</th>
      <th>Valide</th>
      <th>Code Client</th>
      <th>action</th>
   </tr>
</thead>
<tbody>
   {mask:list}
   <tr class="{set:_even}even{/set}">
      <td nowrap>{name}</td>
      <td nowrap>{firstname}</td>
      <td nowrap>{valide}</td>
      <td nowrap title="Mettre à jour">{const:flecheDroite}<a href="{//crud/editAction}id/{id}/" >{ident}</a></td>
      <td >{const:flecheDroite}<a href="{//crud/deleteAction}id/{id}/" >{//crud/deleteButton}</a></td>
   </tr>
   {/mask}
</tbody>
</table>
</div>
<p>
{set:crud/returnPath}<a href="{//baseUrl}{returnPath}">{returnButton}</a>{const:flecheGauche}&nbsp;{/set}
{const:flecheDroite}<a href="{crud/addAction}">{crud/addButton}</a>
</p>

<br />
<!--p class="nota">nota bene</p-->
{/mask}

Code:

{* Formulaire de saisie de client *}
{mask:content}
<h1>{page/title}</h1>
{mask:form}
<form action="{//crud/saveAction}" method="post">
<input type="hidden" name="form[cli_id]" value="{cli_id}" />
<table class="form">
   <tr>
      <th class="request{set://formErrors/cli_code}, error{/set}">Code Client{set:cli_code}{code}{/set}{const:requestMark}</th>
      <td>
         <input type="text" name="form[cli_code]" value="{cli_code}" size="8" maxlength="8" />
      </td>
   </tr>
   <tr>
      <th class="request{set://formErrors/cli_name}, error{/set}">Nom{const:requestMark}</th>
      <td>
         <input type="text" name="form[cli_name]" value="{cli_name}" size="30" />
      </td>
   </tr>
   <tr>
      <th class="request{set://formErrors/cli_firstname}, error{/set}">Pénom{const:requestMark}</th>
      <td>
         <input type="text" name="form[cli_firstname]" value="{cli_firstname}" size="30" />
      </td>
   </tr>
   <tr>
      <th class="request{set://formErrors/cli_valid}, error{/set}">Valide{const:requestMark}</th>
      <td>
         <input type="radio" {if: 0 == {cli_valid}}checked="true"{/if} name="form[cli_valid]" value="0">&nbsp;non&nbsp;
         <input type="radio" {if: 1 == {cli_valid}}checked="true"{/if} name="form[cli_valid]" value="1">&nbsp;oui
      </td>
   </tr>

   <tr>
         <td>&nbsp;</td>
      <td>
         <input type="submit" class="submit" value="{//crud/saveButton}" />
      </td>
   </tr>

</table>
<ul class="nota">
   <li>Les champs marqués d'un <span class="request">*</span> sont obligatoires, d'un <span class="error">!</span> sont erronés.</li>
</ul>
</form>
{/mask}
<a href="{crud/cancelAction}">{crud/cancelButton}</a>{const:flecheGauche}
{/mask}

Code:

{* Demande de confirmation de suppression d'un client *}
{mask:content}
<h1>{page/title}</h1>
<pre>
{mask:form}
<table class="form">
   <tr>
      <th>Code Client</th>
      <td>&nbsp;</td>
      <td>{cli_code}</td>
   </tr>
   <tr>
      <th align="right">Nom</th>
      <td>&nbsp;</td>
      <td>{cli_name}</td>
   </tr>
   <tr>
      <th align="right">Prénom</th>
      <td>&nbsp;</td>
      <td>{cli_firstname}</td>
   </tr>
</table>
{/mask}
</pre>
{const:flecheGauche}<a href="{crud/cancelAction}">{crud/cancelButton}</a>
{const:flecheDroite}<a href="{crud/deleteAction}id/{form/cli_id}/">{crud/deleteButton}</a>
{/mask}

Voilà le gros du travail pour faire le crud ce concentre donc sur les méthode d'accès au données
et les vues

J'utilise beaucoup la navigation alphabétique, c'est pour cette raison que mon CRUD générique le gère lui même.
Je vais essayer de trouver le temps de poster un tuto complet sur mon blog pour vous mettre tout ça à disposition.

il n'est pas nécessaire de définir les actions mais il est possible de les surcharger
elles s'appellent

Code:

showList    //affiche la liste des element
add         //prepare un enregistrement pour le formulaire
edit        //lit un enregistrement
showForm    //affiche le formulaire
checkForm   //vérifie le formulaire
save        //enregistre les données
delete      //recherche l'élément à suprimer
confirm     //affiche une demande de confirmation
remove      //supprime l'enregistrement

http://sekaijin.ovh.org/wp-content/uploads/2008/02/crud.jpg
A+JYT

Dernière modification par sekaijin (21-02-2008 16:31:51)

Hors ligne

 

#5 21-02-2008 18:50:28

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

Re: Contrôleur CRUD abstrait [+ sources]

merci pour ce commentaire très rapide !

(et heuresement que je viens de lire un article sur le design pattern PRG sur Linux magazine il y a 10 minutes : c'est comme pour la CRUD, j'en faisais sans le savoir ;-)

je n'ai pas encore fini TOUT mon controleur, je vais placer un code provisoire sur le site (lundi ?)

j'ai égalment dérivé Zend_Controller_Action (pratique quand même) et Zend_Db_Table (forcément) notamment pour pouvoir intercaler mes traitements, validateteurs, extraction de vues dans la base et 'champ étendus' (auto-jointures dans ton blog il me semble) avec la possibilité de calculer certains champs à partir de fonctions personnalisées dans la classe de modèle.

pour ce qui est de la config ca ne passe par par des fichiers textes et le templating reste un classique .phtml

pour ce qui est des filtres/validateurs, je passe le tableau POST à un setFromArray() personnalisé; es règles de validation proprement dites sont dans la classe table concrète proprement dite, mais ton idée de les placer dans le contrôleur concret me parait plus simple à la longue.

je n'ai pas encore traité complètement les histoires de tri des données à afficher et mon Pager pour les données volumnieuses reste encore à faire...

je me suis beaucoup focalisé sur les hiistoires d'enchainement de contrôleurs en identifiant trois modes de fonctionnement :
a- le contrôleur gère une table seule et va swapper perpétuellement entre les vues LISTER et DETAILLER
OU le controleur permet l'acces à une table enchâssée dans une série de relations 1-N alors la vue LISTER appartient au DETAILLER de l'appelant, donc il y a deux cas :
b- la table dépendant est en bout de chaine, donc on peut revenir directement à l'appelant quand on a fini l'édition
c- la table est au coeur du réseau de relations, donc il faut pouvoir, pour chaque nouvel élément créé, rester sur l'item quand on a fni de la créer, pour pouvoir ajouter des éléments dans la (les) collections qui dépendent de lui (retour INdirect)

par exemle, si on édite une simple liste de courses, c'est le cas a), si on a les relations

Auteurs --(1--N)-> Articles --(1-N)--> ImagesJointes

le contrôleur ImagesJointes sera dans le cas b) (retour direct) tandis que le contrôleur Articles sera dans le cas c) (retour INdirect)

la session gère tout ca au travers d'un fil d'Ariane, le modèle relationnel peut être arborescent, ca marche aussi !
Il faudrait l'améliorer pour les relations de type plusieurs-à-plusieurs (N-N) et les tables jointes sur elles-mêmes :

Articles --(1-N)--> JONCTION <-(1-N)-- MotsClés
et
MotsClés --(1-N)--> EST_RELIE_SEMANTIQUEMENT_A <-(1-N)-- MotsClés


voilà, une petite image pour terminer, la structures des actions de mon contrôleur qui ressemble ^surement au tien ;-)

Image 01_CRUD_sequence.png sur mon site http://www.eozine.fr/temp/CRUD/

http://www.eozine.fr/temp/CRUD/01_CRUD_sequence.png

Hors ligne

 

#6 22-02-2008 07:45:32

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: Contrôleur CRUD abstrait [+ sources]

J'utilise un enchainement par redirection, un historique côté serveur et une gestion de la session nommé contexte lié à une entrée dans l'historique.
du coup lorsque j'ai des relations n,m je fais plusieurs Crud. par exemple j'ai des user qui on plusieurs profils (role étant la relation n,m entre user et profil) je fais un crud user et un crud profil
dans le showForm de user je liste les profils de l'utilisateur (comme dans le profil->showList) avec les lien vers les actions de profil. (editer supprimer, ajouter)
vu que je gère un historique côté serveur mes actions dans le crud profil vont s'enchainer comme si on était parti de showList mais une fois le traitement fini elle vont revenir à leur point de départ c'est à dire le showForm de user
et vu que le contexte est lié à l'entrée de l'historique les données seront toujours là.

ça demande juste un peu de sur charge de quelques actions.
dans User les méthodes surchargées

Code:

//contrairement au crud std lorsqu'on a fini d'éditer ou ajouter un user on reste sur l'écran showForm on le quitte par le lien retour pour pouvoir ajouter des profils
    public function addAction() {
        $redirect = parent::_addAction(false);
        $this->context->cancelPath = $this->context->returnPath;
        $this->context->returnPath = $this->_to('showForm');
        $this->_redirect($redirect);
    }

    public function editAction() {
        $redirect = parent::_editAction(false);
        $this->context->cancelPath = $this->context->returnPath;
        $this->context->returnPath = $this->_to('showForm');
        $this->_redirect($redirect);
    }

//on ajoute la liste des profils au formulaire avec les actions
    public function showFormAction(){
        parent::_showFormAction();
        $this->context->profiles = $this->model->getProfileList($this->context->formData->usr_id);
        #Fast_Debug::show('showFormAction',$this->context->getIterator());
        $this->view->defaut_email = '@orange-ftgroup.com';
        $this->view->profiles = $this->context->profiles;

        $this->view->crud->addAction    = $this->view->baseUrl.'/'.$this->view->module.'/profile/add/';
        $this->view->crud->editAction   = $this->view->baseUrl.'/'.$this->view->module.'/profile/edit/';
        $this->view->crud->deleteAction = $this->view->baseUrl.'/'.$this->view->module.'/profile/delete/';
        $this->view->crud->cancelAction = $this->view->baseUrl.$this->context->cancelPath;

        $this->view->crud->addButton    = $this->_buttons['addProfile'];
        $this->view->crud->deleteButton = $this->_buttons['delete'];
    }

Il va de soit qu'il faut adapter la vue.
le crud profil lui est adapté ainsi

Code:

// sur un ajout on a besoin de savoir à qui on ajoute un profil
   public function addAction() {
      $redirect = parent::_addAction(false);
      $this->context->formData->usr_id = $this->_request->get('usrId');
      $this->_redirect($redirect);
   }

le reste se fait tout seul.
A+JYT

Dernière modification par sekaijin (22-02-2008 07:50:42)

Hors ligne

 

#7 01-04-2008 09:59:53

lesauf
Membre
Lieu: Yaoundé - Cameroun
Date d'inscription: 29-11-2007
Messages: 52
Site web

Re: Contrôleur CRUD abstrait [+ sources]

Je suis aussi parti de l'approche de Sekaijin pour développer un controlleur CRUD.
J'ai intégré Zend_Form (du coup j'ai supprimé checkForm).

Fast_Controller_Crud ShowFormAction():

Code:

/**
     * Affiche le formulaire d'édition d'un élément.
     *
     * @return null
     */
    public function showFormAction()
    {
        $this->_linkContext();
        if (isset($this->context->formData)) {
            $baseAction = $this->view->baseUrl
                            .'/'.$this->view->module
                            .'/'.$this->view->controller;
            $this->view->page->title = 
                        $this->_titles[$this->context->saveMethod];
            $this->view->crud->cancelAction = $this->context->returnPath;
            $this->view->crud->cancelButton = $this->_buttons['cancel'];
            $this->view->crud->saveButton   = $this->_buttons['save'];         
            $this->view->formErrors = (object)$this->context->formErrors;
            $this->history->previous->path = $baseAction . '/show-form';

            // Messages
            $this->view->messages =  $this->_messenger->toArray();

            // chargement du formulaire
            $form = $this->_createForm();

            // validation et enregistrement du formulaire
            if ($this->getRequest()->isPost()) {
                // source des donnees du formulaire
                $dataSource = $this->getRequest()->getPost();

                if ($form->isValid($dataSource)) {
                    // Récuperation des données filtrées
                    $this->context->formData = $form->getValues();

                    // enregistrement
                    $redirect = $this->_to('save');
                    $this->_redirect($redirect);
                } else { // formulaire invalide
                    // message d'erreur
                    $this->_messenger->addError(
                                    $this->_messages['invalidFormData']);
                }
            } 

            // rendu
            $this->view->form = $form;
            $this->view->messages = $this->_messenger->toArray();
        } else {
            trigger_error('Invalid context to call show-formAction', 
                                E_USER_WARNING);
            $redirect = $this->history->previous->path;
            $this->_deleteContext($this->_popHistory());
            $this->_redirect($redirect);
        }
    }

Fast_Controller_Crud _createForm() :

Code:

/**
     * Crée et rempli un formulaire a partir du fichier de config
     * @RETURN Zend_Form object with data
     */
    protected function _createForm()
    {
        // Creation du formulaire using Zend_Form
        Zend_Loader::loadClass('Zend_Form');
        Zend_Loader::loadClass('Zend_Config_Ini');

        // Chemins
        $basePath = $this->view->baseUrl
                            .'/'.$this->view->module;
        $formAction = $basePath
                            .'/'.$this->view->controller
                            .'/show-form/';
        $formConfig = './application'
                        .'/'.$this->view->module
                        .'/controllers/config'
                        .'/'.$this->view->controller
                        .'.ini';

        $config = new Zend_Config_Ini($formConfig, 'formulaire');
        $form = new Zend_Form($config);

        // methode et action du formulaire
        $form->setMethod('POST');
        $form->setAction($formAction);

        // Remplissage
        $form->populate((array)$this->context->formData);

        return $form;
    }

Je rajoute ceci dans le fichier de configuration du controlleur, /controller/config/user.ini

Code:

[formulaire]
; general form metainformation
;action = /user/show-form
;method = post
id = formenreg

; login element
elements.us_login.type = text
elements.us_login.options.label = Login
elements.us_login.options.validators.notempty.validator = notEmpty
elements.us_login.options.validators.notempty.options.messages = obligatoire
elements.us_login.options.validators.strlen.validator = StringLength
elements.us_login.options.validators.strlen.options.min = 6
elements.us_login.options.validators.strlen.options.max = 20
elements.us_login.options.validators.strlen.options.messages = longueur : de 6 à 20 caractères
elements.us_login.options.required = true
elements.us_login.options.filters.lower.filter = StringToLower

;decorators.elements.decorator = FormElements
;decorators.form.errors.decorator = Errors
;decorators.form.htmltag.decorator = HtmlTag
;decorators.form.htmltag.options.tag = div
;decorators.form.errors = Errors
;decorators.form = form

; nom element
elements.us_nom.type = text
elements.us_nom.readonly = readonly
elements.us_nom.options.label = Nom
elements.us_nom.options.validators.notempty.validator = notEmpty
elements.us_nom.options.validators.notempty.options.messages = obligatoire
elements.us_nom.options.required = true
elements.us_nom.options.filters.lower.filter = StringToLower

; prenom element
elements.us_prenom.type = text
elements.us_prenom.options.label = Prénom
elements.us_prenom.options.required = false

; password element
elements.us_pass.type = password
elements.us_pass.options.label = Mot de passe
elements.us_pass.options.validators.notempty.validator = notEmpty
elements.us_pass.options.validators.notempty.options.messages = obligatoire
elements.us_pass.options.validators.strlen.validator = StringLength
elements.us_pass.options.validators.strlen.options.min = 6
elements.us_pass.options.validators.strlen.options.max = 20
elements.us_pass.options.validators.strlen.options.messages = longueur : de 6 à 20 caractères
elements.us_pass.options.required = true
elements.us_pass.options.filters.lower.filter = StringToLower

; type element
elements.us_type.type = text
elements.us_type.options.label = Type
elements.us_type.options.required = false

; submit element
elements.submit.type = submit
elements.submit.name = Enregistrer

; reset element
elements.reset.type = reset
elements.reset.name = Effaçer

show-form.phtml

Code:

<?php 
    //Formulaire de saisie de client
?>
<?= $this->form ?>

Structure de la table ...

Code:

-- 
-- Structure de la table `users`
-- 

CREATE TABLE `users` (
  `us_id` int(11) NOT NULL auto_increment,
  `us_login` varchar(15) collate latin1_general_ci NOT NULL,
  `us_nom` varchar(30) collate latin1_general_ci NOT NULL,
  `us_prenom` varchar(30) collate latin1_general_ci NOT NULL,
  `us_pass` varchar(50) collate latin1_general_ci NOT NULL,
  `us_type` varchar(10) collate latin1_general_ci NOT NULL,
  PRIMARY KEY  (`us_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=2 ;

Je suis en train de nettoyer mon code. Il faut qu'il soit un peu plus propre.Je suis ouvert aux suggestions. Dès que c'est fini je donne le lien du zip.

Dernière modification par lesauf (01-04-2008 10:05:08)

Hors ligne

 

#8 02-04-2008 09:25:14

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: Contrôleur CRUD abstrait [+ sources]

je vais tenter de trouver du temps pour publier la structure complète de ce que j'ai fais sur ZF avec le crud la gestion de l'historique et les tables hiérarchiques
plus tous les petits truc que j'ai ajouté

je pensais justement intégrer Zend_Form dans le futur
mais mon hébergement principal n'est peut être pas suffisant pour ZF 1.5
à voir
A+JYT

Hors ligne

 

#9 02-04-2008 10:23:20

lesauf
Membre
Lieu: Yaoundé - Cameroun
Date d'inscription: 29-11-2007
Messages: 52
Site web

Re: Contrôleur CRUD abstrait [+ sources]

Sekaijin, j'aimerais savoir comment tu gère l'historique et le messager.
Moi, le messager je ne l'utilise que pour l'affichage des messages à l'utilisateur. j'envisage aussi de logger les messages.
L'historique n'est utilisé que pour la derniere page.
Le zip des fichiers

Dernière modification par lesauf (02-04-2008 10:40:32)

Hors ligne

 

#10 02-08-2008 12:13:53

JuTs
Membre
Date d'inscription: 07-03-2008
Messages: 63

Re: Contrôleur CRUD abstrait [+ sources]

Bonjour

Je remonte ce topic pour poser une question pour lesauf.

Pour quoi y a-t-il deux méthodes qui initialisent le context ? Je constate que _linkContext utilise le paramètre $singleInstance mais je ne comprends pas vraiment sont effet sur le CRUD.


Julien

Hors ligne

 

#11 02-08-2008 12:42:34

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: Contrôleur CRUD abstrait [+ sources]

_createContext définit un nouveau contexte associé à l'action si ce contexte existe déjà (i.e. on ré-exécute l'action) le contexte est juste relié à la l'action sinon il est créé

_linkContexte sert à relier un contexte à l'action courante. Si aucun paramètre n'est passé c'est le contexte de l'action précédente qui est relié. sinon on recherche le contexte dont la clef est passé en paramètre pour le relier.

cette mécanique est utilisé par le CRUD mais on peut l'utiliser en dehors. il faut voir ça comme un processus complet.
on est sur une page. et l'utilisateur lance un processus 'création d'un livre' on vas donc enchaîner plusieurs actions.
Livre->add (qui prépare un enregistrement avec les valeurs par défaut)
Livre->showForm (qui affiche l'enregistrement)
Livre->chekForm (qui vérifie les donnée du formulaire)
Livre->save (qui enregistre les donnée.)

et là on revient sur l'action qui précédait le processus.
dans add on crée un contexte dans le quel on place le chemin de l'action précédente et l'enregistrement que l'on vient de créer
dans showForm on affiche l'enregistrement contenu dans le contexte.
chekForm vérifie les donnée et place les erreur et les données dans le contexte
save enregistre les données du contexte.

showForm chekForm et save ont besoin du contexte du processus ils font donc un link pour l'obtenir.

en imaginant que je gère une bibliothèque et que je suis sur la liste des livres, cette liste est affiché par page alphabétique j'ai donc dans ma page tous les livre dont le titre comment par une lettre donnée.
je lance le processus d'ajout et je reviens sur cette liste. ce serait bien que je me retrouve dans la liste des livre dont le titre commence par la même lettre que celui que je viens d'ajouter.

dans save après avoir enregistré mes données je redirige vers la liste.
juste avant la redirection je refais un linkContexte mais cette fois en lui passant en paramètre la clef du contexte liste
j'ai donc le contexte de cette action à disposition et je peux changer la lettre par celle de mon livre. une fois le redirections faite je suis sur la bonne liste.

A+JYT

Hors ligne

 

#12 03-08-2008 15:28:52

JuTs
Membre
Date d'inscription: 07-03-2008
Messages: 63

Re: Contrôleur CRUD abstrait [+ sources]

Merci, je ne demandais pas tant d'explication :-)

mais je ne suis pas totalement sûr d'avoir saisi la différence entre _createContext et _linkContext. Les deux tente de récupérer le context en session et s'il n'existe pas le crée. La différence, $singleInstance = true pour _linkContext qui, si j'ai bien compris permet d'éviter que le contexte ne soit "linké" plus d'une fois. Mais pourquoi ? Un namespace de session n'est pas obligatoirement unique ?


Julien

Hors ligne

 

#13 22-08-2008 10:07:49

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: Contrôleur CRUD abstrait [+ sources]

le create crée un contexte associé à l'action courante s'il n'existe pas.
le link relie l'action courante à in contexte existant

le namespace est différent pour chaque create pour pour pouvoir garder plusieurs processus en cours (un par create)

ainsi on peut commencer un processus de CRUD pour un type d'objet le suspendre pour en faire un autre d'un autre type etc. avant de les reprendre.

A+JYT

Hors ligne

 

#14 06-09-2008 14:36:33

JuTs
Membre
Date d'inscription: 07-03-2008
Messages: 63

Re: Contrôleur CRUD abstrait [+ sources]

Ok, j'ai compris le but.

le namespace est différent pour chaque create pour pour pouvoir garder plusieurs processus en cours (un par create)

Alors tu ne dois pas avoir le même _createContext() que lesauf. Ou alors il l'a modifié et ne l'a pas mis dans le zip qu'il propose en téléchargement.

la méthode que j'ai de son zip :

Code:

 protected function _createContext()
{
     $this->context = new Zend_Session_Namespace('context');
}

ce code correspond bien à quelque chose du genre $this->context = $_SESSION['context'], non ?
Et donc chaque contexte correspondra (quel que soit le contrôleur, action, ...) à $_SESSION['context'] et donc identique dans tous les cas. (à moins d'une modification du contenu, évidemment)


Julien

Hors ligne

 

#15 03-10-2008 21:10:51

lesauf
Membre
Lieu: Yaoundé - Cameroun
Date d'inscription: 29-11-2007
Messages: 52
Site web

Re: Contrôleur CRUD abstrait [+ sources]

sekaijin a écrit:

le namespace est différent pour chaque create pour pour pouvoir garder plusieurs processus en cours (un par create)

ainsi on peut commencer un processus de CRUD pour un type d'objet le suspendre pour en faire un autre d'un autre type etc. avant de les reprendre.

A+JYT

J'avoue que j'ai vraiment bidouillé sur la gestion du contexte. Mais je ne vois pas très bien dans quels cas on pourrait avoir besoin de gérer simultanément plusieures opérations de CRUD, parce que là j'ai fait une gestion plutot élémentaire.

Je veux dire, moi par exemple, lorsque l'enregistrement d'un formulaire fait appel à plusieurs modèles, je dérive saveAction (le contexte ici contient toutes les données du formulaire) en y ajoutant des appels directs aux différents modeles necessaires. Je n'ai donc pas besoin, dans ce cas, d'interrompre le processus de crud des données principales.

Hors ligne

 

#16 04-10-2008 11:04:24

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: Contrôleur CRUD abstrait [+ sources]

un exemple simple
Dans mes application les utilisateur exercent des rôle dans des groupe de travail.

imagine qu'on te demande d'ajouter au pied levé un utilisateur. tu est donc en train de le créer et au moment de lui affecter un rôle (dans un groupe) le gars au tel qui t'a fait la demande te dit que le groupe il faut aussi le créer

tu ouvre le menu gestion de groupe et tu créé ton groupe (nouveau crud) lorsque tu as fini tu reviens sur le crud gestion des user qui est resté en l'état tu n'a plus qu'a choisir le groupe que tu viens de créer.

autre exemple tu travaille sur une partie du métier de l'application. et en urgence il y a autre chose à faire dans une toute autre partie.
(dans word tu as un doc ouvert et tu doit le lâcher pour envoyer un mail, word étant ton éditeur de mail) tu lance donc un nouveau process sans pour autant perdre le travail en cours.

effectivement dans les application web on est plutôt en mode tunnel c'est à dire que l'on commence une tache et tant qu'on ne l'a pas fini on ne peut pas passer à autre chose. ou alors on perd tout le travail en cours.

l'idée de gérer un contexte consiste à faire en sorte qu'il n'y ait plus de navigation figé mais au contraire une invocation à la demande de l'utilisateur. pour y parvenir il faut suivre ses agissements et surtout ne pas perdre la mémoire. mais ce n'est pas suffisent il faut aussi savoir mettre en relation une action et une zone mémoire.

A+JYT

Hors ligne

 

#17 05-10-2008 09:20:36

3uclide
Membre
Date d'inscription: 09-08-2008
Messages: 194

Re: Contrôleur CRUD abstrait [+ sources]

sekaijin a écrit:

imagine qu'on te demande d'ajouter au pied levé un utilisateur. tu est donc en train de le créer et au moment de lui affecter un rôle (dans un groupe) le gars au tel qui t'a fait la demande te dit que le groupe il faut aussi le créer

tu ouvre le menu gestion de groupe et tu créé ton groupe (nouveau crud) lorsque tu as fini tu reviens sur le crud gestion des user qui est [b]resté en l'état[b] tu n'a plus qu'a choisir le groupe que tu viens de créer.

Je demande comment les données sont sauvegardé si le formulaire n'a pas été soumis... Je ne sais pas si tu comprends se que je veux dire.
Le gars commence à remplir le formulaire pour "ajouter", puis lorsqu'on lui dit qu'il faut ajouter le groupe, il clique sur le lien pour aller créer le groupe...  Je ne vois pas où les données précédemment entrées sont sauvegardé.

Hors ligne

 

#18 08-10-2008 11:19:29

lesauf
Membre
Lieu: Yaoundé - Cameroun
Date d'inscription: 29-11-2007
Messages: 52
Site web

Re: Contrôleur CRUD abstrait [+ sources]

3uclide a écrit:

Je demande comment les données sont sauvegardé si le formulaire n'a pas été soumis... Je ne sais pas si tu comprends ce que je veux dire.

clic droit -> "ouvrir dans un nouvel onglet"


sekaijin a écrit:

l'idée de gérer un contexte consiste à faire en sorte qu'il n'y ait plus de navigation figé mais au contraire une invocation à la demande de l'utilisateur. pour y parvenir il faut suivre ses agissements et surtout ne pas perdre la mémoire. mais ce n'est pas suffisant il faut aussi savoir mettre en relation une action et une zone mémoire.

Je comprend, merci. L'idee c'est de donner un max de souplesse à l'application. Je vais l'intégrer dans mon crud, et peut-etre bien que je mettrai les fichiers récents en ligne.

Hors ligne

 

#19 08-10-2008 21:06:11

3uclide
Membre
Date d'inscription: 09-08-2008
Messages: 194

Re: Contrôleur CRUD abstrait [+ sources]

lesauf a écrit:

clic droit -> "ouvrir dans un nouvel onglet"

Il n'est pas nécessaire d'avoir un context pour faire cela.

Hors ligne

 

#20 10-10-2008 12:02:13

Jean-Marc Rigade
Membre
Lieu: Rennes
Date d'inscription: 25-09-2007
Messages: 314

Re: Contrôleur CRUD abstrait [+ sources]

sekaijin a écrit:

un exemple simple
Dans mes application les utilisateur exercent des rôle dans des groupe de travail.

imagine qu'on te demande d'ajouter au pied levé un utilisateur. tu est donc en train de le créer et au moment de lui affecter un rôle (dans un groupe) le gars au tel qui t'a fait la demande te dit que le groupe il faut aussi le créer

tu ouvre le menu gestion de groupe et tu créé ton groupe (nouveau crud) lorsque tu as fini tu reviens sur le crud gestion des user qui est resté en l'état tu n'a plus qu'a choisir le groupe que tu viens de créer.

C'est vraiment instructif tout ça.

Mais dans le cas où la création de groupe, ou pire, suppression d'un groupe, est faite par un autre client, donc autre session et autre contexte, avant que le premier utilisateur ai fini la création de son utilisateur, mais déjà lu la liste des groupes...

Il me semble de dans ce cas le traitement standard CRUD du premier client (qui crée un utilisateur) s'il se fie à son contexte va essayer d'écrire en base avec comme référence un groupe qui n'existe plus ou qui n'a rien à voir... non ?

Dernière modification par Jean-Marc Rigade (10-10-2008 12:02:55)

Hors ligne

 

#21 07-05-2009 09:03:01

lesauf
Membre
Lieu: Yaoundé - Cameroun
Date d'inscription: 29-11-2007
Messages: 52
Site web

Re: Contrôleur CRUD abstrait [+ sources]

Bonjour,

J'ai mis fichiers récents en ligne :
Crud Lesauf

Cordialement,
Lesauf

Dernière modification par lesauf (11-11-2010 14:06:57)

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages