Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et...

47
Symfony en action I M V Controleur

Transcript of Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et...

Page 1: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Symfony en action I

M V Controleur

Page 2: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

controleur• couche contenant le code liant la partie logique et la

présentation• Décomposé en

– contrôleur principal (front controller) : • unique point d'entrée de l'application• chargement configuration • Détermine les actions à effectuer

– actions : • code applicatif• Vérifient l'intégrité des requêtes • préparent les données pour les templates (vues)

– Les requêtes, les réponses et les objets de sessions permettent l'accès à des informations particulières comme les headers des réponses et les données persistantes.

• souvent utilisées par le contrôleur principal. – filtres : portions de codes exécutées à chaque requête, avant ou

après l'action

Page 3: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Contrôleur principal

• Prend toutes les requêtes web en charge• Utilise le système de routage pour

déterminer le module et l’action à patir de l’URL– http://localhost/index.php/mymodule/myaction – appelle le script index.php (contrôleur principal)

qui traduira l’url par un appel à l'action myaction du module mymodule

Page 4: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Séquences d’exécution du controleur principal

1. Définir les constantes. 2. Déterminer les chemins des bibliothèques Symfony. 3. Charger et initialiser les classes du coeur du framework. 4. Charger la configuration. 5. Décoder la requête URL afin d'identifier les actions à effectuer

et les paramètres de la requête. 6. Si l'action n'existe pas, faire une redirection sur l'action 404

error. 7. Activer les filtres (par exemple, si les requêtes nécessitent une

authentification). 8. Exécuter les filtres une première fois. 9. Exécuter l'action et générer la présentation. 10.Exécuter les filtres une seconde fois. 11.Renvoyer la réponse

Page 5: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

<?php define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/..')); define('SF_APP', 'myapp'); define('SF_ENVIRONMENT', 'prod'); define('SF_DEBUG', false);

require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php‘);

sfContext::getInstance()->getController()->dispatch();

Code du controleur par défaut

Etape 1

Etape 2 à 4

Etape 5 à 7

Chaîne des filtres Etape 8 à 10

Page 6: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Un nouveau contrôleur pour un nouvel environnement

• Création d’un environnement staging– Créer web/myapp_staging.php– changer la valeur de la constante

SF_ENVIRONMENT à staging

• Configuration spécifique à l’environnement staging dans app.yml

staging: mail: webmaster: [email protected] contact: [email protected] all: mail: webmaster: [email protected] contact: [email protected]

Page 7: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Les batchs

• scripts en ligne de commande (ou lancer via cron) accédant à l'ensemble des classes symfony, y compris celles spécifiques au projet.

• Similaire à un controleur principal de l’étape 1 à 4

• Initialisation d’un batch symfony init-batch staging myapp script.php

Page 8: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Code typique d’un batch

<?php define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/..')); define('SF_APP', 'myapp'); define('SF_ENVIRONMENT', 'prod'); define('SF_DEBUG', false);

require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php‘);

Page 9: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Les actions

• Groupées par module dans /apps/myapp/modules/mymodule/actions/actions.class.php

• Contiennent la logique de l’application• Utilisent le modèle• Définissent les variables pour les templates• Une URL définit une action d’un module

ainsi que les paramètres avec lesquels elle sera exécutée

http://localhost/index.php/myModule/myAction?var1=val1&...&varn=valn

Page 10: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Convention de nommage

• La classe contenant les actions de myModule se nomme myModuleActions et hérite de sfActions

• L’action myAction de myModule est une méthode de la classe myModuleActions nommée executeMyAction

• Si la taille d'une classe action grandit trop, il faudra probablement faire le refactoring de celle-ci et déplacer une partie de son code dans la couche modèle

Page 11: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Code générique

• Ajouter une action c’est ajouter une nouvelle méthode execute à l’objet sfActions

/apps/myapp/modules/mymodule/actions/actions.class.php

class myModuleActions extends sfActions {

public function executeMyAction() {

…}

}

Page 12: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Syntaxe alternative

• possibilité d’avoir un fichier par actionmyapp/modules/mymodule/actions/myAction.class.php

<?php class myAction extends sfAction{ public function execute() { ... }}

Page 13: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Récupération d’informationsvia la classe action

class myModuleActions extends sfActions {

public function executeMyAction() {

$password = $this->getRequestParameter('password');$moduleName = $this->getModuleName();$actionName = $this->getactionName();$request = $this->getRequest();$userSession = $this->getUser();$response = $this->getResponse();$controller = $this->getController();$context = $this->getContext();$this->setVar('foo', 'bar');$this->foo = 'bar';

} }

Page 14: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Le contexte

$this->getContext() sfContext::getInstance()Accés à tous les objets du noyau symfony• sfController: objet contrôleur (->getController())• sfRequest: objet requêtes (->getRequest())• sfResponse: objet réponse (->getResponse())• sfUser: objet session utilisateur (->getUser())• sfDatabaseConnection: connexion à la bdd (->getDatabaseConnection())• sfLogger: objet de log (->getLogger())

• sfI18N: l'objet d'internationalisation (->getI18N())

• sfContext::getInstance() est utilisable n’importe où dans le code(modèle, vue, controleur, helper, fichier de conf, etc …)

Page 15: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Terminaison d’une action

• La valeur retournée par une action (ici myAction) détermine le template à utiliser

• Constantes de classe sfView– return sfView::SUCCESS;

• templates/myActionSuccess.php (implicite)

– return sfView::ERROR;• templates/myActionError.php

– return sfView::NONE;• Pas de template appelé (batch, AJAX, etc …)

• Template personnalisé– Return ‘myResult’;

• templates/myActionMyResult.php

Page 16: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Terminaisons d’actions particulières

• Envoyer une réponse HTML sans passer par une vue

public function executeIndex() {

$this->getResponse()->setContent("<html><body>hi!</body></html>");  

return sfView::NONE;

}

• Équivalent àexecuteIndex()

{

return $this->renderText("<html><body>Hello, World!</body></html>");

}

Page 17: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Terminaisons d’actions particulières II

• Ne renvoyer que les en-têtes httppublic function executeRefresh()

{

$output = '<"title","My basic letter"],["name","Mr Brown">';

$this->getResponse()->setHttpHeader("X-JSON", '('.$output.')');  

return sfView::HEADER_ONLY;

}

• Renvoyer un template spécifique$this->setTemplate('myCustomTemplate');

• Pas d’instruction return

Page 18: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Passer à une autre action• Si l'action précède l'appel à la nouvelle action

(conserve la même URL)– $this->forward('otherModule', 'index');

• Si le résultat de l'action est une redirection web: – $this->redirect('otherModule/index'); – $this->redirect('http://www.google.com/');

• Methode post : redirect péréfrable pour éviter la ressoumission au refresh

• Redirection vers une erreur 404– $this->forward404(); – $this->forward404If(); – $this->forward404Unless();

Page 19: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Code partagé par les actionsclass mymoduleactions extends sfactions {

public function preExecute() {

// Le code à insérer ici est executé au début de chaque appel d'action } public function executeList() {

$this->myCustomMethod(); } public function postExecute() {

// Le code inséré ici est exécuté à la fin de chaque appel de l'action } protected function myCustomMethod() {

//partagée à condition qu'elles ne débutent pas par le mot "execute",// déclarée protected ou private

} }

Page 20: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

valeurs de la requête

getMethod() méthode requête `sfRequest::GET` ou `sfRequest::POST`

getMethodName() POST ou GET

getHttpHeader('Server') Valeur d'une entête http donnée

getCookie('foo') Valeur d'un cookie donné

isXmlHttpRequest() Est-ce une requête AJAX?

isSecure() Est-ce une requête SSL?

Information sur la requête

Page 21: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

valeurs de la requête

hasParameter('foo') Y a-t-il un paramètre foo dans la requête?

getParameter('foo' ) Quelle est la valeur du paramètre foo?

getParameterHolder()->getAll() Tableau de tous les paramètres de la requête

Paramètres de la requête

getLanguages() Tableau des langages acceptés

getCharsets() Tableau des charsets appelés

getAcceptableContentTypes() Tableau des content-types acceptés

informations sur le navigateur

Page 22: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

valeurs de la requête

getUri() URI entière

getPathInfo() information sur le path getReferer() L’url qui a mené à l’uri courante

getHost() Nom de l’hôté

getScriptName() Path du front controller et son nom

Information sur l’URI

Page 23: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Petit rappel

class mymoduleActions extends sfActions {

public function executeIndex() {

$hasFoo = $this->getRequest()->hasParameter('foo'); $hasFoo = $this->hasRequestParameter('foo'); // Shorter $foo = $this->getRequest()->getParameter('foo'); $foo = $this->getRequestParameter('foo'); // Shorter}

}

Page 24: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Upload de fichierclass mymoduleactions extends sfActions{ public function executeUpload() { if ($this->getRequest()->hasFiles()) { foreach ($this->getRequest()->getFileNames() as $fileName) { $fileSize = $this->getRequest()->getFileSize($fileName); $fileType = $this->getRequest()->getFileType($fileName); $fileError = $this->getRequest()->hasFileError($fileName); $uploadDir = sfConfig::get('sf_upload_dir'); $this->getRequest()->moveFile('file', $uploadDir.'/'.$fileName); } } }}

Page 25: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Session utilisateur

• Les variable de sessions sont accessibles via l’objet sfUser– lecture

• $this->getUser()->getAttribute('nickname'); – écriture

• $this->getUser()->setAttribute('nickname‘,’mazenovi’); – supression

• $this->getUser()->getAttributeHolder() ->remove('nickname'); – suppression de toutes les variables

• $this->getUser()->getAttributeHolder()->clear();

• Accessible dans les templates via la variable $sf_user– $sf_user->getAttribute(‘nickname’)– $sf_user->setAttribute(‘nickname’,’mazenovi’)

Page 26: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Attributs Flash

• attribut éphémère qui peut être défini puis oublié – lecture

• $this->getFlash('attrib');

– écriture• $this->setFlash('attrib', $value);

• Accessible dans les templates via la variable $sf_flash – $sf_flash->get (‘attrib’) – $sf_flash->set (‘attrib’,$value))

Page 27: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Gestion des sessions

• Le cookie de session de symfony est appelé symfony (modifiable)

apps/myapp/config/factories.yml

all: storage: class: sfSessionStorage param: session_name: my_cookie_name

Page 28: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Configuration des sessions

• Pour passer la session via l’url (déconseillé), modifier le php.ini– session.use_trans_sid = 1

• Paramétrer la durée de vie d’une session– apps/myapp/config/settings.yml

default: .settings: timeout: 1800 # Session lifetime in seconds

Page 29: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Gérer les sessions avec MySQL

• Gérer dans des fichiers par défaut

apps/myapp/config/factories.yml

all: storage: class: sfMySQLSessionStorage param: db_table: SESSION_TABLE_NAME database: DATABASE_CONNECTION

Page 30: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Sécurisé une action

apps/myapp/modules/mymodule/config/security.yml

read: is_secure: offupdate: is_secure: ondelete: is_secure: on credentials: adminall: is_secure: off

Page 31: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Autorisations complexes

apps/myapp/modules/mymodule/config/security.yml

editArticle: credentials: [ admin, editor ] # admin and editor publishArticle: credentials: [[ admin, superuser ]] # admin or superuser userManagement: credentials: [[root, [supplier, [owner, quasiowner]], accounts]] # root OR (supplier AND (owner OR quasiowner)) OR accounts

Page 32: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Authentification

• authentifier– $this->getUser()->setAuthenticated(true);

• déconnecter– $this->getUser()->setAuthenticated(false);

• vérifier l’authetification– $this->getUser()->getAuthenticated();

Page 33: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Autorisation

• ajouter une autorisation– $this->getUser()->addCredential(‘foo’);

• ajouter des autorisations– $this->getUser()->addCredentials(‘foo’,’bar’);

• tester une autorisation– $this->getUser()->hasCredential(‘foo’);

• tester des autorisations– $this->getUser()->hasCredential(array(‘foo’,’bar’));

• supprimer une autorsiation– $this->getUser()->removeCredential(‘foo’);

• supprimer toutes les autorsiations– $this->getUser()->clearCredentials();

Page 34: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Validation d’une actionau niveau controleur

1. validateActionName: méthode de validation retournant true ou false. Si elle n'existe pas la méthode de l'action est directement exécutée.

2. handleErrorActionName : méthode appelée quand la méthode de validation retourne false. Si elle n'existe pas, le template Error est affiché.

3. executeActionName : méthode d'action. Elle doit exister pour toutes les actions.

Page 35: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Validation d’une action - code typique -

class mymoduleactions extends sfActions {

public function validateMyaction() {

return ($this->getRequestParameter('id') > 0); }public function handleErrorMyaction() {

$this->message = "Invalid parameters"; return sfView::SUCCESS;

} public function executeMyaction() {

$this->message = "The parameters are correct"; }

}

Page 36: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Processus de validation

Page 37: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Les filtres

• Classes de filtres permettant d’exécuter du code avant l’exécution de l’action ou avant l’envoie de la requête– Similaire à preExecute et postExecute mais pour toute l’application

• Tout filtre hérite de la classe sfFilter et contient au moins une méthode execute qui prend un objet $filterChain en paramètre

• Le filtre devra appeler dans son code $filterChain->execute() afin de passer au filtre suivant de la chaîne

• Le code situé avant $filterChain->execute() est exécuté avant l’action

• Le code situé après $filterChain->execute() est exécuté après l’action

Page 38: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.
Page 39: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

La chaîne de filtres par défaut

• myapp/config/filters.yml rendering: ~ web_debug: ~ security: ~

# Generally, you will want to insert your own filters here

cache: ~ common: ~ flash: ~ execution: ~

Page 40: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Les filtres core

• Le ~ dans myapp/config/filters.yml signifie « héritage » des classes symfony

• $sf_symfony_data_dir/config/filters.yml

rendering: class: sfRenderingFilter # Filter class param: # Filter parameters type: rendering

Page 41: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

(dés)activation des filtres

• Désactiver un filtreweb_debug: enabled: off • Ne pas supprimer un filtre dans filters.yml (une exception

sera levée)• Les filtres personnalisés doivent obligatoirement être insérés

entre les filtres rendering et execution• Il est possible de redéfinir les filtres par défaut (notamment

pour modifier le système de sécurité)• Il est également possible de désactiver les filtres par défaut

dans settings.yml (chaque filtre par défaut possède une condition calculée à partir de ces valeurs)

Page 42: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Filtres personnalisés

• apps/myapp/lib/rememberFilter.class.php class rememberFilter extends sfFilter{

public function execute($filterChain) { // le filtre ne s’exécute qu’une fois même si redirect ou forwardif ($this->isFirstCall()) {

$request = $this->getContext()->getRequest(); $user = $this->getContext()->getUser();   if ($request->getCookie('MyWebSite')) {

$user->setAuthenticated(true); }

}   filter $filterChain->execute();

} }

Page 43: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Filtres personnalisés II

• Pour passer à une autre action

return $this->getContext()->getController()->forward('mymodule', 'myAction');

• apps/myapp/config/filters.yml …security: ~

remember: # Filters need a unique name class: rememberFilter param: cookie_name: MyWebSite condition: %APP_ENABLE_REMEMBER_ME% cache: ~ …

Page 44: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Filtres personnalisés III

• Il est possible de faire passer des paramètres à un filtre (ici cookie_name)

$request->getCookie($this->getParameter('cookie_name')

• Le paramètre condition détermine si le filtre doit être exécuté

• Pour être exécuté /apps/myapp/config/app.yml doit contenir

all: enable_remember_me: on

Page 45: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Exemple de filtre personnalisé I

class sfGoogleAnalyticsFilter extends sfFilter {

public function execute($filterChain) { $filterChain->execute();$googleCode = ' <script src="http://www.google-

analytics.com/urchin.js" type="text/javascript"></script><script type="text/javascript">

uacct="UA-'.$this->getParameter('google_id').'";urchinTracker();

</script>'; $response = $this->getContext()->getResponse();

$response->setContent(str_ireplace('</body>', $googleCode.'</body>',$response->getContent())); }

}

Page 46: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Exemple de filtre personnalisé IIclass sfSecureFilter extends sfFilter { public function execute($filterChain) { $context = $this->getContext();

$request = $context->getRequest();   if (!$request->isSecure()) { $secure_url = str_replace('http', 'https', $request->getUri());   return $context->getController()->redirect($secure_url);

} else { $filterChain->execute(); } } }

Page 47: Symfony en action I M V Controleur. controleur couche contenant le code liant la partie logique et la présentation Décomposé en –contrôleur principal.

Configuration des modules

• apps/myapp/modules/mymodule/config/module.yml

all: # For all environments enabled: true is_internal: false view_class: sfPHP

• enabled : (dés)active toutes les actions du module• is_internal : les appels aux actions ne se font qu’à

parti de l’appli (mail)• view_class : hérite de sfView par défaut, mais

peuvent hérité d’un autre langage de template (Smarty)