diff --git a/index.md b/index.md index 0857afa3072d5969548a27873bfc823f85b053b6..d88a6fe40376216c809c7341b87dcf67a81a956d 100644 --- a/index.md +++ b/index.md @@ -475,7 +475,6 @@ Note: - Interface Segregation Principle --- -<!-- .slide: class="big_code" --> ## Aliasing d'interfaces ```yaml @@ -484,6 +483,20 @@ services: '@App\Infrastructure\Article\DoctrineGetLatestArticles' ``` +```php +use App\Domain\Article\GetLatestArticlesInterface; + +final class LatestArticlesAction +{ + private $latestArticles; + + public function __construct(GetLatestArticlesInterface $latestArticles) + { + $this->latestArticles = $latestArticles; + } +} +``` + Note: - Inutile si il n'y a qu'une seule implémentation et que la feature de discovery est configurée sur un namespace commun. @@ -560,10 +573,16 @@ Note: <div class="tweet" data-src="https://twitter.com/Ocramius/status/975399920202080256" style="transform: scale(1.5) translate(-33%,0%);"></div> +--- + +- Découplage de Doctrine ✓ +- Découplage de `symfony/form` +- Découplage de `{symfony,jms}/serializer` --- <!-- .slide: data-background="./iwantmore.gif" --> + --- ## Quelle API pour interroger la base de données ? diff --git a/talk.md b/talk.md index 8271ff13b03d3a31aa6c06271d9a59e0654c2c34..3bf2a0def8c6ecb30def842dc5aa043893f08cf2 100644 --- a/talk.md +++ b/talk.md @@ -28,17 +28,19 @@ sont dépourvus de toute logique, et si vous les testez, vous aurez probablement l'impression de perdre votre temps et de faire un travail répétitif, à tel point que certains vont jusqu'à créer des paquets Composer pour automatiser ce genre de tests, et que jusqu'à très récemment, il y avait -une commande qui permettait de les générer. +une commande qui permettait de les générer. Finalement, avec ce genre d'entité, +regarder le mapping YAML est mieux car on a une meilleure vue d'ensemble, et +tout le reste en découle. On peut remarquer que Doctrine ne fait pas d'active record et ne vous oblige pas à étendre quoi que ce soit, ce qui est une très bonne chose, car ce serait une forme de couplage très forte. -Ce modèle porte un nom ou des noms, il est connu sous le nom de modèle -anémique, car il plein de vide. +Cette architecture porte un nom, il est connu sous le nom de modèle anémique, +car il est plein de vide. Mais si vous avez écouté le talk de Romain Kuzniak tout à l'heure, vous savez que ce n'est pas la seule architecture possible. -Maxime et moi, nous aimons et utilsons le Domain Driven Design dans nos application. +Maxime et moi, nous aimons et utilisons le Domain Driven Design dans nos applications. C'est une architecture dont voici certains points clés, le principal point-clé étant dans le nom, DDD. Une des choses importantes en DDD, c'est qu'on commence @@ -78,9 +80,10 @@ crasher aussitôt et de la façon la plus visible possible. Plutôt que de cache la poussière sous le tapis, on jette une exception et on se débarasse de tout une classe de bug venant du fait que vous pensez quelque chose être vrai alors qu'il ne l'est pas. Par exemple ici, après l'instanciation, si on fait appel à -getId(). C'est un des problèmes avec les identifiants. L'autre problème, c'est -le couplage qu'on a avec la base de données qui est censée rester un outil -externe et ne devrait pas dicter les ids. +getId(), on obtiendra une `TypeError`. C'est un des problèmes avec les +identifiants classiques. L'autre problème, c'est le couplage qu'on a avec la +base de données qui est censée rester un outil externe et ne devrait pas dicter +les ids. Comme solution, vous pouvez utiliser les UUIDs, si vous n'avez pas de clé naturelle. Une clé naturelle, c'est par exemple l'ISBN d'un livre. Si vous avez @@ -102,48 +105,51 @@ d'entité. Maintenant qu'on a résolu le problème des ids, revenons à nos moutons. On a un constructeur, avec n propriétés, et chaque propriété a x règles de validation… ça peut vite devenir très lourd pour le constructeur, surtout que certaines -règles de validation devront aussi être vérifier si vous avez des mutateurs +règles de validation devront aussi être vérifiées si vous avez des mutateurs (des méthodes qui changent vos propriétés). Pour résoudre ce problème, on peut utiliser des value objects. Voilà à quoi ça peut ressembler. -On a une classe, sans identités, avec seulement une ou deux propriétés qui vont +On a une classe, sans identité, avec seulement une ou deux propriétés qui vont ensemble, et des règles métier pour les valider. Le nom de value object vient du fait que ce genre d'objet est caractérisé par sa valeur, et que deux value object doivent être considérés comme égaux si et seulement si toutes leurs propriétés sont égales. Ce qui va se passer si vous partez là dessus, c'est que -vous allez passer au constructeur des value objects. +vous allez passer au constructeur des value objects. Vous pouvez le faire car +Doctrine n'appelle pas le constructeur à l'hydratation. Le problème avec cette approche, c'est que l'instanciation peut vite devenir très pénible, car il faut ajouter un use statement par value object, plus celui de la classe principale. Une bonne solution, c'est d'utiliser des constructeurs nommés, qui sont des -factory statiques. Je dis des parce que vous pouvez en avoir plusieurs. Ces +factory statiques. Je dis "des" parce que vous pouvez en avoir plusieurs. Ces constructeurs nommés, vous allez leur passer des types primitifs et vous allez -pouvoir les charger de mettre des valeurs par défaut ou non suivant le -constructeur. Vous pouvez même mettre le constructeur en privé si vous voulez -forcer les gens à créer de nouveaux constructeurs nommés si ceux que vous avez -faits ne sont pas assez complets. +pouvoir les charger de mettre des valeurs par défaut ou non, faire des +conversions ou non suivant le constructeur. Vous pouvez même mettre le +constructeur en privé si vous voulez forcer les gens à créer de nouveaux +constructeurs nommés si ceux que vous avez faits ne sont pas assez complets. +Le constructeur décrit ce qui est requis pour construire votre objet, et les +constructeurs nommés sont une couche pour permettre une utilisation simple. Alors maintenant, on a un obtenu des entités qui ne sont plus des tableaux améliorés. On n'est pas en train de modéliser une base de données, on a fait les chose à l'endroit et on a modélisé le problème du client, code first, ou même model first pour ceux qui commencent par faire de l'UML et génèrent ensuite du code. Comment persister une structure arborescente de value objects -avec Doctrine? +avec Doctrine? C'est la que l'ORM prend toute sa valeur. -Deux solutions: les custom types, et les value objects. Commençons par la plus -simple, les custom types. +Deux solutions: les custom types, et les embeddables. Commençons par les custom +types. Un custom type, c'est un type à vous, qui va devenir utilisable dans vos -mappings Doctrine au même type que string, json_array ou integer. +mappings Doctrine au même titre que string, json_array ou integer. Pour en créer un, vous devez pour le moment étendre une classe de base, et surcharger quelques méthodes. Dans le futur, il y aura probablement un gros refactoring de cette partie pour que vous n'ayez plus qu'à implémenter une interface. Il y a également gros à parier que `getName` disparaitra, de même -qu'il avait disparu dans le composant form de Symfony. Pour le moment, il vous +qu'elle avait disparu dans le composant form de Symfony. Pour le moment, il vous faut utiliser le même nom dans cette méthode et lors de l'enregistrement dans -la registre des types, qui se comme ceci. +la registre des types, qui se présente comme ceci. Les 2 méthodes qui nous intéressent, `convertToPHPValue` et `convertToDatabaseValue` doivent permettre de convertir une valeur provenant d'une colonne de la base de données en value object et vice versa. Avec cette