Allumeddd


@vibby0
Allumeddd
Fabrique
d’Allumettes
Industrielle
Ligériennes

Rencontrer
un métier
Représenter le réel :
User Story

En tant que receptionnaire,
Je receptionne un tronc
Afin d’en préparer le débitageSpécifier

namespace spec;
use PhpSpec\ObjectBehavior;
class ReceptionisteSpec extends ObjectBehavior
{
function it_receptionne_tronc()
{
$tronc = new Tronc('542kg');
$this->receptionnerTronc($tronc)->shouldReturn($etiquette);
}
}Encore trop old-school
Le cas d’usage

namespace App\Scierie\Application\UseCase\ReceptionerUnTronc;
use App\Scierie\Domain\Depository\TroncDepository;
class ReceptionerUnTroncHandler
{
function __construct(
private readonly TroncDepository $troncDepository;
) {}
function __invoke(ReceptionerUnTroncInput $input)
{
$tronc = new Tronc(
masse: $input->masse,
essence: $input->essence
);
$this->troncDepository->store($tronc);
return new Etiquette($tronc);
}
}Qu’est ce qu’on fait ?
Entrée
Qu’est ce qu’on donne ?

namespace App\Scierie\Application\
UseCase\ReceptionerUnTronc;
use Symfony\Component\Validator\Constraints;
use App\Scierie\Application\Asserts;
class ReceptionerUnTroncInput
{
function __construct(
#[Constraints\NotBlank]
#[Asserts\IsMasse]
public string $masse,
#[Constraints\NotBlank]
#[Asserts\IsEssence]
public string $essence,
) {}
}Objet métier
C’est quoi ce truc ?

namespace App\Scierie\Domain\Entity;
use App\Scierie\Application\Asserts;
use Ramsey\Uuid\Uuid;
#[Asserts\MasseMinimumParEssence]
class Tronc
{
public readonly Uuid $id;
function __construct(
private Masse $masse,
private Essence $essence,
) {
$this->id = Uuid::uuid4();
}
function refendre(
EpaisseurDeCoupe $epaisseur
): Planche {
[…]
}
}Value object
Une propriété à forte valeur

namespace App\Scierie\Domain\ValueObject;
use Symfony\Component\Validator\Constraints;
class Masse
{
function __construct(
#[Constraints\Positive]
public readonly int $value,
public readonly UniteMasse $unite,
) {
}
}
Enum UniteMasse
{
case Kilogramme;
case Tonne;
case Livre;
}Interfaces
Se connecter au monde

namespace App\Scierie\Domain\Depository;
interface TroncDepository
{
function store(Tronc $tronc): void;
function update(Tronc $tronc): void;
function marquerCommeSecs(\DateTime $date);
}
interface TroncRepository
{
function findById(Uuid $id): Tronc;
function findByMasseMinimum(
Tronc $tronc,
Masse $masse,
): \ArrayObject;
}
Point Archi

- src
- Scierie
- Application
- UseCase
- ReceptionnerTronc
- RefendreTronc
- Asserts
- Domain
- Entity
- ValueObject
- Depository
- Repository
- Franglais d’ubiquitous langage
- La doc ? Quelle doc ?
- Je fais pas du MVC ! (ou si ?)
- Tests fonctionnels
Modélisation
- Holistique et Étendue
- Sous-domaines
- Objectiver le métier

C’est fini ?

On entre par où ?

- Site web backend
- API pour frontend
- Appli mobile
- Ligne de commande
- Objet connecté
Avec Symfony

Côté gauche
namespace App\Scierie\Infrastructure\Controller;
class NewTroncController extends AbstractController
{
public function __invoke(
Request $request,
ReceptionerUnTroncHandler $handler,
) {
$input = new ReceptionerUnTroncInput(
masse: $request->get('masse'),
essence: $request->get('essence'),
);
$etiquette = $handler($input);
return $this->render(
'view.html.twig',
['etiquette' => $etiquette]
);
}
}
Avec Symfony

Côté droit
namespace App\Scierie\Domain\Depository;
interface TroncDepo implements TroncDepository
{
function __construct(
private EntityManager $em,
private ElasticSearchIndexer $es,
){}
function store(Tronc $tronc)
{
$this->em->persist($tronc);
$this->em->flush();
$this->es->index($tronc);
}
}
Doctrine

namespace App\Scierie\Infrastructure\Doctrine\Type;
use Doctrine\DBAL\Types\ArrayType;
use App\Scierie\Domain\ValueObject\Masse;
class voMasseType extends ArrayType
{
function convertToPHPValue($value): mixed
{
return new Masse($value['value'], $value['unite']);
}
function convertToDatabaseValue($value): array
{
return [
'value' => $value->value,
'unite' => $value->unite,
];
}
}
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="…">
<entity name="App\Scierie\Domain\Entity\Tronc">
<field name="id" type="string" length="32" />
<field name="masse" type="vo_masse" length="16" />
<field name="essence" type="enum_essence" length="16" />
</entity>
</doctrine-mapping>
Because I’m API
Api-Platform
App\Scierie\Domain\Entity\Tronc:
attributes:
order:
dateArrivee: ASC
collectionOperations:
get:
method: GET
security: is_granted('ROLE_USER')
output: App\Forfait\Application\Output\Etiquette
post:
method: POST
path: /reception-tronc
security: is_granted('ROLE_RECEPTIONISTE')
input: App\Scierie\Application\UseCase\ReceptionerUnTroncInput
output: App\Forfait\Application\Output\Etiquette
messenger: input
itemOperations:
get:
method: GET
security: is_granted('ROLE_USER')
output: App\Forfait\Application\Output\Etiquette
Jusqu’où ?

- ERP, CRM, GED, CMS ?
- Identifier le spécifique
- Pour quels projets ?
- Dette technique
Au service

- Approche globale
- Se méfier du besoin exprimé
- Se concentrer sur la valeur
Allumeddd


@vibby0
Merci
deck
By vibby
deck
- 134