Presented by Maxime Colin / @colin_maxime
Refonte d'une application. 250 JH. Qualité et testabilité demandé par le client.
Data Model
View Model
Repository interfaces
Adapters interfaces
Domain services
namespace VendorName\Domain;
Business actions
Business logic
Business services
Adapters interfaces
namespace VendorName\Application;
Repository implementations
Persistence layer
Adapters implementations
Services definitions (DIC)
namespace VendorName\Bundle\InfrastuctureBundle;
doctrine: orm: naming_strategy: doctrine.orm.naming_strategy.underscore auto_generate_proxy_classes: "%kernel.debug%" auto_mapping: false mappings: entity: type: yml prefix: Acme\Domain\Model dir: %kernel.root_dir%/../src/Acme/Bundle/InfrastructureBundle/Resources/config/doctrine/entity alias: Entity is_bundle: false
Symfony stuff
Controllers
Forms
Views
namespace VendorName\Bundle\AppBundle;
namespace VendorName\Bundle\ApiBundle;
Models for read only purpose
Models for write purpose
Hydrate your query results in read only data
SELECT new ArticleListView(a.title, a.author) FROM Entity:Article
Use entities for write purpose only
Do not use Doctrine repositories, inject EntityManager
Repository can be based on Doctrine, an API, memory, redis, ...
The persistance should not impact the domain
Use command bus...
or request/response service...
or even manager
No Symfony dependencies
No business code in controllers
Easier to test
Events
Exceptions
Don't limit your form architecture to your entities model
Validation is easier
/** * "Gabarit" */ class Pattern { }
Create reusable form type
Create form extension
Don't repeat yourself
Handle redundant development tasks by...
Creating your own code skeletons
Creating your own generate commands
Create exception for every errors you must handle
Throw general exception for others
Reusable and chainable query builder
Put criteria/filter in method
Create many query builder as you want
class ArticleQueryBuilder { public function __construct(EntityManager $em) { parent::__construct($em); $this ->select('article') ->from('Entity:Article', 'article'); } }
class ArticleQueryBuilder { public function isPublished(\DateTime $at) { $this ->andWhere('article.published = TRUE') ->andWhere('article.publishedAt < :at') ->setParameter('at', $at); return $this; } }
Put your business rules in reusable classes
Less getter/setter
More domain method
$article->setPublished(true); $article->setPublished(false);by
$article->publish(); $article->unpublish();
$product = new Product() $product->setTitle('Lorem ipsum'); $product->setDecription('Foobar'); $product->setPrice(15.99);by
$product = new Product('Lorem ipsum', 'Foobar', 15.99);
Doctrine 2.5
/** @Entity */ class User { /** @Embedded(class = "Address", columnPrefix = "myPrefix_") */ private $address; }
SELECT u FROM User u WHERE u.address.city = :myCity
216f-ff40-98d9-11e3-a5e2-0800-200c-9a66
Controller as service
YAML routing
No @Template, @Route, ...