Symfony en action 1 M V Controleur

mellowfetaΑσφάλεια

19 Ιουν 2012 (πριν από 5 χρόνια και 4 μήνες)

474 εμφανίσεις

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 (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

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

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

<?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

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: dummy@mysite.com


contact: dummy@mysite.com

all:


mail:


webmaster: webmaster@mysite.com


contact: contact@mysite.com

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

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‘);


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?var
1
=val
1
&...&var
n
=val
n



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

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()


{






}

}

Syntaxe alternative


possibilité d’avoir un fichier par action

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

<?php

class myAction extends sfAction

{


public function execute()


{


...


}

}


Récupération d’informations

via 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';



}

}

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 …)



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


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>");

}

Terminaisons d’actions
particulières II


Ne renvoyer que les en
-
têtes http

public 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

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();

Code partagé par les actions

class 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


}

}

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

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

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

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


}

}

Upload de fichier

class 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);


}


}


}

}

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’)


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))

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

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

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

Sécurisé une action

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

read:


is_secure: off

update:


is_secure: on

delete:


is_secure: on


credentials: admin

all:


is_secure: off

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

Authentification


authentifier


$this
-
>getUser()
-
>setAuthenticated(true);


déconnecter


$this
-
>getUser()
-
>setAuthenticated(false);


vérifier l’authetification


$this
-
>getUser()
-
>getAuthenticated();






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();


Validation d’une action

au 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.

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";


}


}

Processus de validation

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



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: ~

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

(dés)activation des filtres


Désactiver un filtre

web_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)

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 forward



if ($this
-
>isFirstCall())



{




$request = $this
-
>getContext()
-
>getRequest();




$user = $this
-
>getContext()
-
>getUser();






if ($request
-
>getCookie('MyWebSite'))




{





$user
-
>setAuthenticated(true);




}



}





filter $filterChain
-
>execute();


}

}

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: ~



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

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()));


}

}

Exemple de filtre personnalisé II

class 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();


}


}

}

Configuration des modules


apps/myapp/modules/mymodule/config/module.ym
l

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)