1. Présentation par Vlad RIABCHENKO
Les patrons de conception du composant Form
9
Mai 2017
2. Vlad RIABCHENKO
Web développeur chez
depuis 2016
http://vria.eu
P r e s e n t a t i o n
L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
2
3. 1 / Patrons de conception
P l a n
L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
2 / Composite, Abstract factory, Observer
3 / Il y en a encore plus
3
5. P a t r o n s d e c o n c e p t i o n – q u e s o n t - i l s ?
L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
est un arrangement de modules/classes
un concept d'architecture
un exemple générique de solution
récurrent
reconnu comme une bonne pratique
issu de l'expérience de concepteurs de logiciels
Un patron de conception :
qui est
5
6. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
Le formalisme est important. Chaque patron possède :
un nom
une description de la problématique à résoudre
une description de la solution : les éléments de la solution, leurs relations
une liste des conséquences possibles
P a t r o n s d e c o n c e p t i o n – q u e s o n t - i l s ?
6
7. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
Les patrons de conception :
Réduisent la complexité des algorithmes
Réduisent le couplage
Promeuvent la réutilisation – flexibilité
Favorisent (et parfois rendent possible) la testabilité – TDD
Evitent les doublons – DRY
P a t r o n s d e c o n c e p t i o n – q u e s o n t - i l s ?
7
9. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
aPicture
aPicture aSquare aLine
aText aLine aLine
...
draw
C o m p o s i t e – T r a i t e r u n i f o r m é m e n t d e s
o b j e t s i n d i v i d u e l s e t l e u r s c o m p o s i t i o n s
Représenter des hiérarchies partie-entier
Permettre aux clients de traiter uniformément tous les objets dans une structure hiérarchique
Permettre aux clients d’ignorer la différence entre des objets individuels et les compositions
d'objets
9
10. C o m p o s i t e – T r a i t e r u n i f o r m é m e n t d e s
o b j e t s i n d i v i d u e l s e t l e u r s c o m p o s i t i o n s
L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
10
11. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
C o m p o s i t e – T r a i t e r u n i f o r m é m e n t d e s
o b j e t s i n d i v i d u e l s e t l e u r s c o m p o s i t i o n s
11
12. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
C o m p o s i t e – T r a i t e r u n i f o r m é m e n t d e s
o b j e t s i n d i v i d u e l s e t l e u r s c o m p o s i t i o n s
12
13. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
setData()
submit()
isValid()
...
all()
add()
remove()
has()
get()
...
C o m p o s i t e – T r a i t e r u n i f o r m é m e n t d e s
o b j e t s i n d i v i d u e l s e t l e u r s c o m p o s i t i o n s
12
14. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
$form->getConfig()->getCompound()
$formBuilder->setCompound(true)
$resolver->setDefaults([
'compound' => true
]);
C o m p o s i t e – T r a i t e r u n i f o r m é m e n t d e s
o b j e t s i n d i v i d u e l s e t l e u r s c o m p o s i t i o n s
13
15. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
Type Compound ?
TextType (EmailType,
PasswordType, ...)
non
IntegerType non
FileType non
CollectionType oui
RepeatedType oui
ChoiceType (EntityType, ...) pareil que l’option “expanded”
DateType (DateTimeType,
DateIntervalType, ...)
false si ‘widget’ est ‘single_text‘,
true sinon
FormType oui
YourCustomType oui
Par défaut :
C o m p o s i t e – T r a i t e r u n i f o r m é m e n t d e s
o b j e t s i n d i v i d u e l s e t l e u r s c o m p o s i t i o n s
14
16. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
Error bubbling
Compound forms need a data mapper
Compound forms expect an array or NULL on submission
You cannot add children to a simple form. Maybe you should set the option "compound" to true?
C o m p o s i t e – T r a i t e r u n i f o r m é m e n t d e s
o b j e t s i n d i v i d u e l s e t l e u r s c o m p o s i t i o n s
15
18. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
Un système devrait être indépendant de la façon dont ses produits sont créés, composés et représentés.
Un système doit être configuré avec une de plusieurs familles de produits.
Vous souhaitez fournir une bibliothèque de classes de produits, et vous souhaitez révéler uniquement
leurs interfaces.
Une famille d'objets produits doit être utilisée conjointement, et vous devez garantir cette contrainte.
Fournit une interface pour créer des familles d'objets liés ou inter-dépendants sans avoir à
préciser la classe concrète à utiliser au moment de leur création.
$factory->createObject($arguments); //suffit
$factory->createLogger(); // MonologLogger ou log4phpLogger ou ...
$factory->createHandler(); // MonologHandlerInterface ou log4phpLoggerAppender ou …
$factory->create...();
A b s t r a c t F a c t o r y – C r é e r d e s f a m i l l e s d ' o b j e t s
s a n s c o n n a î t r e l e u r s c l a s s e s c o n c r è t e s
16
19. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
A b s t r a c t F a c t o r y – C r é e r d e s f a m i l l e s d ' o b j e t s
s a n s c o n n a î t r e l e u r s c l a s s e s c o n c r è t e s
$factory->createLogger(); //MonologLogger ou log4phpLogger ou ...
$factory->createHandler(); //MonologHandlerInterface ou log4phpLoggerAppender ou …
$factory->create...();
MonologFactory
Création déléguée
Plusieurs familles de produits
Seulement les objets d'une certaine famille
Organiser les familles en bibliothèques
log4phpFactory
$factory->createLogger(); //MonologLogger ou log4phpLogger ou ...
$factory->createHandler(); //MonologHandlerInterface ou log4phpLoggerAppender ou …
$factory->create...();
17
20. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
A b s t r a c t F a c t o r y – C r é e r d e s f a m i l l e s d ' o b j e t s
s a n s c o n n a î t r e l e u r s c l a s s e s c o n c r è t e s
AbstractFactory
$factory->createLogger(); //AbstractLogger ...
$factory->createHandler(); //AbstractHandler ...
$factory->create...();
AbstractLogger AbstractHandler
log4phpFactory
log4phpLogger
log4phpHandler
MonologFactory
MonologLogger
MonologHandler
18
21. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
A b s t r a c t F a c t o r y – C r é e r d e s f a m i l l e s d ' o b j e t s
s a n s c o n n a î t r e l e u r s c l a s s e s c o n c r è t e s
19
22. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
A b s t r a c t F a c t o r y – C r é e r d e s f a m i l l e s d ' o b j e t s
s a n s c o n n a î t r e l e u r s c l a s s e s c o n c r è t e s
$container->get('form.factory')->createForm(...);
$this->createForm(...); //dans Controller
$form->getConfig()->getFormFactory()->createForm();
my_service:
class: FQCNClassName
arguments: ['@form.factory']
20
24. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
Lorsqu’un objet doit notifier aux autres un événement à la suite d’une action quelconque (modèle
“publish-subscribe”).
Crée une communication abstraite entre un observable (subject) et des observateurs :
Permet l’exécution de code dans le package A (B, C, ...) à un certain moment d’éxécution de code
dans le package réutilisable Z.
// Des observers peuvent s'attacher a un observable
$observable->addObserver($observer1);
$observable->addObserver($observer2);
// un observable peut notifier des observers
$observable1->notify($data);
$observable2->notify($data);
21
25. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
22
26. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
interface SplObserver {
abstract public void update(SplSubject $subject)
}
Interface SplSubject {
abstract public void attach(SplObserver $observer)
abstract public void detach(SplObserver $observer)
abstract public void notify(void)
}
Prêt-à-implémenter :
23
27. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
Distinguer les évenements
app.my_exception_listener:
class: ExceptionListener
tags:
- {name: kernel.event_listener, event: kernel.exception}
/**
* @ORMPrePersist
*/
public function setCreatedAtValue()
{ ... }
$formBuilder->addEventListener(FormEvents::PRE_SUBMIT, $listener);
24
28. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
Passer de l'information utile aux observers lors de l'appel
class ExceptionListener {
public function onKernelException(GetResponseForExceptionEvent $event)
{ ... }
}
$listener = function (FormEvent $event) {
...
};
/**
* @ORMPrePersist
*/
public function setCreatedAtValue(LifecycleEventArgs $args)
{ ... }
25
29. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
26
Formulaire
initialisé
navigateur
Formulaire
vide
PRE_SET_DATA
POST_SET_DATA
Transformers
Formulaire
vide ou initialisé
PRE_SUBMIT
SUBMIT
view-to-norm transformer
SUBMIT
norm-to-view transformer,
norm-to-model transformer
Données envoyées
Données de modèle
30. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
PRE_SET_DATA
Modifier les données fournies pendant la pré-
population
Modifier le formulaire en fonction des données
pré-peuplées
Début
Form::setData()
ResizeFormListener
27
navigateur
31. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
PRE_SET_DATA
Modifier les données fournies pendant la pré-
population
Modifier le formulaire en fonction des données
pré-peuplées
POST_SET_DATA
Accéder aux données transformées (normalisées,
view)
Début
Form::setData()
Fin
Form::setData()
ResizeFormListener
DataCollectorListener
navigateur
27
32. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
PRE_SET_DATA
Modifier les données fournies pendant la pré-
population
Modifier le formulaire en fonction des données
pré-peuplées
POST_SET_DATA
Accéder aux données transformées (normalisées,
view)
PRE_SUBMIT
Changer les données de Request avant de
soumettre les données au formulaire
Ajouter ou supprimer des champs de formulaire,
avant de soumettre les données au formulaire
Début
Form::setData()
Fin
Form::setData()
Début de
Form::submit()
ResizeFormListener
DataCollectorListener
TrimListener
CsrfValidationListener
ResizeFormListener
navigateur
27
33. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
PRE_SET_DATA
Modifier les données fournies pendant la pré-
population
Modifier le formulaire en fonction des données
pré-peuplées
POST_SET_DATA
Accéder aux données transformées (normalisées,
view)
PRE_SUBMIT
Changer les données de Request avant de
soumettre les données au formulaire
Ajouter ou supprimer des champs de formulaire,
avant de soumettre les données au formulaire
SUBMIT
Mêmes que pour PRE_SUBMIT
Modifier les données normalisées
Début
Form::setData()
Fin
Form::setData()
Début de
Form::submit()
Données de
Request sont
normalisé
ResizeFormListener
DataCollectorListener
TrimListener
CsrfValidationListener
ResizeFormListener
FixUrlProtocolListener
navigateur
27
34. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
O b s e r v e r – N o t i f i e r d e s é v è n e m e n t s d i v e r s
PRE_SET_DATA
Modifier les données fournies pendant la pré-
population
Modifier le formulaire en fonction des données
pré-peuplées
POST_SET_DATA
Accéder aux données transformées (normalisées,
view)
PRE_SUBMIT
Changer les données de Request avant de
soumettre les données au formulaire
Ajouter ou supprimer des champs de formulaire,
avant de soumettre les données au formulaire
SUBMIT
Mêmes que pour PRE_SUBMIT
Modifier les données normalisées
POST_SUBMIT
Mêmes que pour PRE_SUBMIT
Modifier les données normalisées
Début
Form::setData()
Fin
Form::setData()
Début de
Form::submit()
Données de
Request sont
normalisé
Fin de
Form::submit()
ResizeFormListener
DataCollectorListener
TrimListener
CsrfValidationListener
ResizeFormListener
FixUrlProtocolListener
ValidationListener
DataCollectorListener
navigateur
27
36. L e s p a t r o n s d e c o n c e p t i o n d u
c o m p o s a n t F o r m
I l y e n a e n c o r e p l u s
Adapter : ResolvedFormType, FormType
Bridge: FormRenderer
Builder: FormBuilderInterface (FormBuilder, SubmitButtonBuilder, ButtonBuilder) et
FormConfigBuilderInterface (FormConfigBuilder)
Facade: Forms
Factory method: ResolvedFormType::createBuilder
Chain of responsibility: Form::setError
28
37. R ETR OU VEZ W EBN ET
Merci
pour votre attention