Mathias Arlaud
Co-Founder & COO @Bakslash - Co-Founder & CTO @Synegram
"Après-midi balançoire" - 1978
"Après-midi balançoire" - 1980
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__@florianm__
Florian-Merle
AKAWAKA
ancien élève
@matarld@afup@florianm__ancien élève aussi
@matarld
mtarld
les-tilleuls.coop
@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__@matarld@afup@florianm__@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__@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__@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__foo === bar.baz
// Chaine de caractères
@matarld@afup@florianm__foo === bar.baz
f
o
o
=
=
=
b
a
r
.
b
a
z
// Chaine de caractères
// Flux de caractères
_
_
@matarld@afup@florianm__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__foo
===
bar
.
baz
PROPERTY ACCESSOR
VAR.
OP.
VAR.
CST.
.
VAR.
OP.
IDENTICAL OPERATOR
===
V
P
V
C
// Tokens
@matarld@afup@florianm__===
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__@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__vos retours
By Mathias Arlaud