mercredi 5 août 2009

Framework Turbulences : TUTO 3 - Validation, relations entre modèles et ACL

Turbulences Tutorial - Chapter 3 : More models : validation, model relationships and access control

Pré-requis
Il faut que turbulences soit installé. Il faut créer les modules user et address de cette manière :

$ cd /myapp $ php script/generate_module.php user $ php script/generate_module.php address
Puis il faut completer les fichiers user.schema.sql et address.schema.sql :

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(10) unsigned NOT NULL auto_increment,
`firstname` varchar(30) NOT NULL,
`lastname` varchar(30) NOT NULL,
`email` varchar(30) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `address`;
CREATE TABLE `address` (
`id` int(10) unsigned NOT NULL auto_increment,
`address` varchar(30) NOT NULL,
`city` varchar(30) NOT NULL,
`zip_code` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


Dans ce chapitre, nous allons apprendre à :

* Créer un nouveau module. Créer le module Administrator.
o Un administrator a les mêmes attributs qu'un autre utilisateur du siteweb
o Un administrator a des attributs spécifiques en plus (niveau d'administration et adresse)
* Gérer toutes les erreurs (administrator, user and address) en même temps
* Gérer l'accès aux attributs pour les modèles et pour les actions des controlleurs

Generation du module administrator

* Grace au script de génération de module, on créé le module administrator :

php script/generate_module.php administrator

Créer la table

On va ajouter une table pour les attributs spécifiques des administrators, incluant toutes les clés étrangères pour les utilisateurs(user) et les adresses(address). On va juste créer un script user.schema.sql et address.schema.sql
modules/administrator/DB/administrator.schema.sql.

DROP TABLE IF EXISTS `administrator`;
CREATE TABLE `administrator` (
`id` INT( 10 ) NOT NULL AUTO_INCREMENT ,
`user_id` INT( 10 ) NOT NULL ,
`level` ENUM( 'super-admin', 'moyen-admin', 'petit-admin' ) NOT NULL ,
`address_id` INT( 10 ) NOT NULL ,
PRIMARY KEY ( `id` ) ,
INDEX ( `user_id` , `level` )
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Pour installer la nouvelle table, vous devez executer le nouveau script ou l'installation complete par le script habituel.

mysql <> var $_joins = array(
'user' => array('User', array('user_id' => 'id')),
'address' => array('Address', array('address_id' => 'id'))
);
On va utiliser les jointures dans notre code pour obtenir quel utilisateur correspond à tel administrator en écrivant une formule très simple : $admin->user. En ce qui concerne les adresses, c'est la même chose : $admin->address. Ceci est appelé une jointure directe.

Créer le controlleur

// cette fonction renvoi un objet administrator // si $_GET['id'] ou $_POST['id'] est vérifié, on charge l'objet correspondant // sinon on retourne un objet vide public function getAdministratorFromRequest() { if(isset($this->__get['id']) && is_numeric($this->__get['id'])) $id = $this->__get['id']; elseif(isset($_POST['id']) && is_numeric($_POST['id'])) $id = $_POST['id']; else $id = NULL; if(!is_null($id)) $u = Administrator::getByPKey('Administrator',$id); else $u = new Administrator(); return $u; } // action for general editing public function action_edit() { return $this->_edit('edit'); } // action for access_level editing public function action_set_level() { return $this->_edit('edit'); } // function to save the object for all action private function _edit($view) { $v = new AdministratorView(); // get the object from request $obj = $this->getAdministratorFromRequest(); // if request type is post if($this->isPost()) { $administrator = Administrator::getByPKey('Administrator',$_POST['id']); if(!is_null($administrator)) { //mise à jour de ce champs avec les données send en POST $administrator->setFromArray($_POST['administrator']); $administrator->update(); //maj du user associé au champ administrator modifié $user=User::getByPKey('User',$administrator->user_id); $user->setFromArray($_POST['user']); $user->update(); //maj de l'addresse associée au champ administrator modifié $address = Address::getByPKey('Address',$administrator->address_id); $address->setFromArray($_POST['address']); $address->update(); } // if no arrors , redirect to action_list if(isset($obj->id) && !$obj->hasError()) return $this->action_list(); } // render the asked view and pass the object $view = 'html_'.$view; return $v->$view($obj); } // action for listing public function action_list() { $v = new AdministratorView(); $objs = Administrator::getFor('Administrator'); return $v->html_list($objs); }
On peut maintenant tester la méthode de listage des administrators en tapant http://turbapp/administrator/list

Les actions basiques : CreateReadUpdateDelete

* En ce qui concerne les vues, elles passent simplement l'objet entier ou un tableau d'objets

public function _edit($obj) { $this->assign('administrator',$obj); } public function _list($objs) { $this->assign('administrators',$objs); }
* La template edit.tpl -- (les widgets sont des plugins smarty)


<!-- Widget to print all errors on our object, including dependant objects -->
{wdgt_print_object_error object=$administrator}

<form name="" method="post" action="" enctype="multipart/form-data">
<!-- keep the object id in form -->
<input type="hidden" name="id" value="{$administrator->id}" />
<!-- hardcode the user type -->
<input type="hidden" name="user[user_type]" value="administrator" />

<fieldset>
<legend>
<div class="title">
<div class="title_right"></div>
Administrateur
</div>
</legend>
<!-- following widget print all inputs, regarding the access_level defined in models (cf following points) -->
{wdgt_input object=$administrator->user field='lastname' label='Nom'}
{wdgt_input object=$administrator->user field='firstname' label='Prénom'}
{wdgt_input object=$administrator->user field='email' label='Email'}
{wdgt_select object=$administrator field='level' label='Niveau d\'admistration'}

</fieldset>

<fieldset>
<legend>
<div class="title">
<div class="title_right"></div>
Adresse
</div>
</legend>
<!-- following widget print all inputs, regarding the access_level defined in models (cf following points) -->
{wdgt_input field=address object=$administrator->address prefix_name=address label='Adresse'}
{wdgt_input field=city object=$administrator->address prefix_name=address label='Ville'}
{wdgt_input field=zip_code object=$administrator->address prefix_name=address label='Code postal'}

</fieldset>
<hr />

<ul>
<li class="reset"><input type="reset" value="Annuler" /></li>
<li class="submit"><input type="submit" value="Enregistrer les modifications" /></li>
</ul>
</form>



* Maintenant, on peut tester le module insert/edit en tapant ceci : http://turbapp/administrator/edit/?id=1

Controle d'accès : ACL

* On va gerer les accès aux champs du modele. On va utiliser un simple modèle de sécurité : les Access Control List (ACL)

Premièrement, le controlleur doit propager les _access_level aux objets (_access_level est le type d'utilisateur dans la session)
private function _edit($view) { $v = new AdministratorView(); $obj = $this->getAdministratorFromRequest(); // HERE $obj->setAccessLevel($this->_access_level); // transmission of the access level to the object if($this->isPost()) { $obj->setFromArray($_POST); $obj->saveDependantObjects(); if(isset($obj->id) && !$obj->hasError()) return $this->action_list(); } $view = 'html_'.$view; return $v->$view($obj); }
On doit définir les règles de lecture d'un champ d'édition. Si vous êtes admin, vous allez pouvoir lire et écrire : admin_read et admin_write. On voit que seul un administrateur ne peut parametrer le niveau d'un administrateur, le default_access ne peut le faire.
var $_access_limit = array( 'default_read' => array(), 'default_write' => array('level'), 'admin_read' => array(), 'admin_write' => array(), );
* On peut définir les access_level pour toutes les actions du controlleur. Si l'access_level courant ne peut acceder à l'action, il est redirigé vers ErrorController::access_not_allowed
administrator.php
var $_allowed_access_level = array( 'edit' => array('admin','default'), 'set_level' => array('admin'), );
public function action_set_level() { return $this->_edit('edit'); }
Vous pouvez maintenant tester l'ACL : seulement les administrateurs sont capable d'accéder à http://turbapp/administrator/set_level

Aucun commentaire:

Enregistrer un commentaire

Bonjour,