"Après-midi balançoire" - 1978
"Après-midi balançoire" - 1980
Une histoire de
compréhension
AFUP Day Lyon 2023
@matarld
@afup
@florianm__
client
@matarld
@afup
@florianm__
customer
acquéreur
utilisateur
patient
majeur
client
@matarld
@afup
@florianm__
user
élève
utilisateur
client
@matarld
@afup
@florianm__
Florian Merle
@florianm__
Florian-Merle
AKAWAKA
ancien élève
@matarld
@afup
@florianm__
ancien élève aussi
@matarld
mtarld
les-tilleuls.coop
Mathias Arlaud
@matarld
@afup
@florianm__
user
élève
utilisateur
client
@matarld
@afup
@florianm__
élève
$user
@matarld
@afup
@florianm__
$student
élève
@matarld
@afup
@florianm__
$eleve
élève
@matarld
@afup
@florianm__
L'élève est éligible pour une bourse
@matarld
@afup
@florianm__
L'éleve a eu une bourse en 2020 et est inscrit à Parcours Sup et a été accepté à un de ses voeux se trouvant loin de son domicile
@matarld
@afup
@florianm__
$eleve->bourses ->filter(/* lycée 2020 */) ->count() > 0 && $parcoursSup->inscrits ->contains($eleve) && $eleve->voeux ->filter(/* accepté */) ->filter(/* loin */) ->count() > 0;
L'éleve a eu une bourse en 2020 et est inscrit à Parcours Sup et a été accepté à un de ses voeux se trouvant loin de son domicile
@matarld
@afup
@florianm__
$parcoursSup->inscrits
->contains($eleve)
&& $eleve->voeux
->filter(/* accepté */)
->filter(/* loin */)
->count() > 0
|| $potDeVin > UnBonMontant->value;
L'éleve est inscrit à Parcours Sup et a été accepté à un de ses voeux se trouvant loin de son domicile ou a versé un bon pot de vin
@matarld
@afup
@florianm__
Expression language
@matarld
@afup
@florianm__
Expression language
@matarld
@afup
@florianm__
$services->set('indexBuilder')
->arg(
'$indexName',
expr("env('index_prefix') ~ '_' ~ parameter('main_index_name')"),
);
@matarld
@afup
@florianm__
use Symfony\Component\Security\Http\Attribute\IsGranted;
final class ViewPostController
{
#[IsGranted('"ROLE_ADMIN" in roles or is_granted("VIEW", subject)', subject: 'post')]
public function __invoke(Post $post): Response
{
return new Response('ok');
}
}
@matarld
@afup
@florianm__
Expression language
@matarld
@afup
@florianm__
$el = new ExpressionLanguage();
$somme = $el->evaluate('a + b', [
'a' => 1,
'b' => 2,
]);
@matarld
@afup
@florianm__
$el = new ExpressionLanguage();
$redouble = $el->evaluate(
'((notes.semestre * 2 + notes.soutenance) / 3) < 10',
['notes' => $eleve->getNotes()]),
);
@matarld
@afup
@florianm__
$eleve->bourses ->filter(/* lycée 2020 */) ->count() > 0 && $parcoursSup->inscrits ->contains($eleve) && $eleve->voeux ->filter(/* accepté */) ->filter(/* loin */) ->count() > 0;
L'éleve a eu une bourse en 2020 et est inscrit à Parcours Sup et a été accepté à un de ses voeux se trouvant loin de son domicile
@matarld
@afup
@florianm__
$el = new ExpressionLanguage();
$reglePourEtreEligible = <<<EOT
a_eu_une_bourse(eleve, 2020)
&& est_inscrit_a_parcours_sup(eleve)
&& a_voeux_accepté_et_loin(eleve)'
EOT;
$eligible = $el->evaluate(
$reglePourEtreEligible,
['eleve' => $eleve],
);
L'éleve a eu une bourse en 2020 et est inscrit à Parcours Sup et a été accepté à un de ses voeux se trouvant loin de son domicile
@matarld
@afup
@florianm__
$el = new ExpressionLanguage();
$eligible = $el->evaluate(
$regles->findEligiblePourBourse(),
['eleve' => $eleve],
);
L'éleve a eu une bourse en 2020 et est inscrit à Parcours Sup et a été accepté à un de ses voeux se trouvant loin de son domicile
@matarld
@afup
@florianm__
@matarld
@afup
@florianm__
L'arbre syntaxique
@matarld
@afup
@florianm__
L'AFUP organise des trucs cools
@matarld
@afup
@florianm__
L'AFUP organise des trucs cools
VERBE
NOM
DET
DET
NOM
ADJ
@matarld
@afup
@florianm__
L'AFUP organise des trucs cools
VERBE
NOM
DET
DET
NOM
ADJ
GRP NOMINAL
VERBE
GRP NOMINAL
@matarld
@afup
@florianm__
L'AFUP organise des trucs cools
VERBE
NOM
DET
DET
NOM
ADJ
GRP NOMINAL
VERBE
GRP NOMINAL
GRP NOMINAL
GRP VERBAL
@matarld
@afup
@florianm__
L'AFUP organise des trucs cools
VERBE
NOM
DET
DET
NOM
ADJ
GRP NOMINAL
VERBE
GRP NOMINAL
GRP NOMINAL
GRP VERBAL
PHRASE
@matarld
@afup
@florianm__
L'AFUP organise des trucs cools
VERBE
NOM
DET
DET
NOM
ADJ
GRP NOMINAL
VERBE
GRP NOMINAL
GRP NOMINAL
GRP VERBAL
PHRASE
P
GN
GV
D
N
V
GN
D
N
A
@matarld
@afup
@florianm__
(soutenance + notes.semestre) / 2
@matarld
@afup
@florianm__
(soutenance + notes.semestre) / 2
VAR.
OP.
(
VAR.
)
OP.
CST.
.
CST.
@matarld
@afup
@florianm__
(soutenance + notes.semestre) / 2
VAR.
OP.
(
VAR.
)
OP.
CST.
.
CST.
VAR.
OP.
(
PROPERTY ACCESSOR
)
OP.
CST.
@matarld
@afup
@florianm__
(soutenance + notes.semestre) / 2
VAR.
OP.
(
VAR.
)
OP.
CST.
.
CST.
VAR.
OP.
(
PROPERTY ACCESSOR
)
OP.
CST.
ADDITION OPERATOR
OP.
CST.
@matarld
@afup
@florianm__
(soutenance + notes.semestre) / 2
VAR.
OP.
(
VAR.
)
OP.
CST.
.
CST.
VAR.
OP.
(
PROPERTY ACCESSOR
)
OP.
CST.
ADDITION OPERATOR
OP.
CST.
DIVISION OPERATOR
@matarld
@afup
@florianm__
(soutenance + notes.semestre) / 2
VAR.
OP.
(
VAR.
)
OP.
CST.
.
CST.
VAR.
OP.
(
PROPERTY ACCESSOR
)
OP.
CST.
ADDITION OPERATOR
OP.
CST.
DIVISION OPERATOR
/
+
C
V
P
V
C
@matarld
@afup
@florianm__
Lexer
foo === bar.baz
// Chaine de caractères
@matarld
@afup
@florianm__
Lexer
foo === bar.baz
f
o
o
=
=
=
b
a
r
.
b
a
z
// Chaine de caractères
// Flux de caractères
_
_
@matarld
@afup
@florianm__
Lexer
foo === bar.baz
f
o
o
=
=
=
b
a
r
.
b
a
z
foo
===
bar
.
baz
// Chaine de caractères
// Flux de caractères
// Tokens
VAR.
OP.
VAR.
.
CST.
@matarld
@afup
@florianm__
Parser
foo
===
bar
.
baz
PROPERTY ACCESSOR
VAR.
OP.
VAR.
CST.
.
VAR.
OP.
IDENTICAL OPERATOR
===
V
P
V
C
// Tokens
@matarld
@afup
@florianm__
Expression Language
===
V
P
V
C
// Arbre syntaxique
// Magie
@matarld
@afup
@florianm__
eleve in parcoursSup.inscrits
@matarld
@afup
@florianm__
syntaxe spécifique
structure interne
in
.inscrits
eleve in parcoursSup.inscrits
@matarld
@afup
@florianm__
est_inscrit_a_parcours_sup(eleve)
$parcoursSup->inscrits->contains($eleve)
@matarld
@afup
@florianm__
new ExpressionFunction(
name: 'est_inscrit_a_parcours_sup',
compiler: static function (string $s): string {
// ...
},
evaluator: static function (array $args, Eleve $e): bool {
return $args['parcoursSup']->inscrits->contains($e);
},
)
@matarld
@afup
@florianm__
final class ParcoursSupFunctionProvider implements ExpressionFunctionProviderInterface
{
public function getFunctions(): array
{
return [
new ExpressionFunction('est_inscrit_a_parcours_sup', ...),
new ExpressionFunction(...),
// ...
];
}
}
@matarld
@afup
@florianm__
use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseEL;
final class EcoleExpressionLanguage extends BaseEL
{
public function __construct(
CacheItemPoolInterface $cache = null,
array $providers = [],
) {
array_unshift($providers, new ParcoursSupFunctionProvider());
array_unshift($providers, new BourseFunctionProvider());
parent::__construct($cache, $providers);
}
}
@matarld
@afup
@florianm__
$el = new EcoleExpressionLanguage();
$reglePourEtreEligible = <<<EOT
a_eu_une_bourse(eleve, 2020)
&& est_inscrit_a_parcours_sup(eleve)
&& a_voeux_accepté_et_loin(eleve)'
EOT;
$eligible = $el->evaluate($reglePourEtreEligible, [
'eleve' => $eleve,
'parcoursSup' => $parcoursSup,
]);
@matarld
@afup
@florianm__
Démo'
@matarld
@afup
@florianm__
final class DefinirRegleEligiblePourBourseAction extends AbstractController
{
public function __invoke(EcoleExpressionLanguage $el, RegleRepository $regles)
{
if ($form->isSubmitted() && $form->isValid()) {
$regles->saveEligiblePourBourse($form->get('expression')->getData());
return $this->redirectToRoute('regles');
}
return $this->render('definir_regle_eligible_pour_bourse.html.twig', [
'completion' => [
...array_map(
fn ($f) => ['type' => 'function', 'label' => $f->getName()],
$el->getFunctions(),
),
...array_map(
fn ($v) => ['type' => 'variable', 'label' => $v],
['eleve', 'parcoursSup'],
),
],
]);
}
}
@matarld
@afup
@florianm__
readonly final class AppliqueBourseCommandHandler
{
public function __construct(
private EcoleExpressionLanguage $el,
private RegleRepository $regles,
private ParcoursSup $parcoursSup,
) {
}
public function __invoke(AppliqueBourseCommand $command): void
{
$eligible = $el->evaluate($regles->findEligiblePourBourse(), [
'eleve' => $command->eleve,
'parcoursSup' => $this->parcoursSup,
]);
if (!$eligible) {
return;
}
// ...
}
}
@matarld
@afup
@florianm__
@matarld
@afup
@florianm__
Merci !
vos retours
Copy of [AFUP] Expression Language
By Florian David Merle
Copy of [AFUP] Expression Language
- 50