Rich Model And Layered Architecture in SF2 Application

4,248 views

Published on

Presentation for Symfony Camp UA 2012.
* What are Rich Model, Service Layer & Layered Architecture
* Layered architecture in Sf2 Application
* Integration with 3rd party bundles

Published in: Technology

Rich Model And Layered Architecture in SF2 Application

  1. 1. RichModelAnd Layered Architecture Kirill chEbba Chebunin (Creara.ru) iam@chebba.org
  2. 2. Rich Model. ??? http://www.vexinthecity.com/2010/10/estee-lauder-christmas-collection-pure.html © Kirill chEbba Chebunin. Creara 2012
  3. 3. Rich Model. Who? Martin Fowler – Anemic Domain Model – Domain Model – Transaction Script Eric Evans – Domain-Driven Design Benjamin Eberlei – Building an Object Model: No setters allowed © Kirill chEbba Chebunin. Creara 2012
  4. 4. Rich Model. What? About business objects – Entities Data + Logic instead of pure Data (Anemic Model) Real encapsulation Consistent state Business methods instead of Setters Low level validation © Kirill chEbba Chebunin. Creara 2012
  5. 5. Rich Model. How?class Project{ const STATUS_NEW = new; const STATUS_ACTIVE = active; const STATUS_BLOCKED = blocked; private $name; private $status; public function setName($name) { $this->name = $name; } public function getName() { return $this->name; } public function setStatus($status) { $this->status = $status; } public function getStatus() { return $this->status; }} © Kirill chEbba Chebunin. Creara 2012
  6. 6. Rich Model. How?class Project http://rober-raik.deviantart.com/art/Fuck-You-263589802{ const STATUS_NEW = new; const STATUS_ACTIVE = active; const STATUS_BLOCKED = blocked; private $name; private $status; public function setName($name) { $this->name = $name; } public function getName() { return $this->name; } public function setStatus($status) { $this->status = $status; } public function getStatus() { return $this->status; }} FUCK YOU, SETTERS! © Kirill chEbba Chebunin. Creara 2012
  7. 7. Rich Model. How?class Project class Project{ { const STATUS_NEW = new; const STATUS_NEW = new; const STATUS_ACTIVE = active; const STATUS_ACTIVE = active; const STATUS_BLOCKED = blocked; const STATUS_BLOCKED = blocked; private $name; private $name; private $status; private $status; public function setName($name) public function __construct($name) { { $this->name = $name; $this->name = trim($name); } $this->status = self::STATUS_NEW; } public function getName() { public function getName() return $this->name; { } return $this->name; } public function setStatus($status) { public function getStatus() $this->status = $status; { } return $this->status; } public function getStatus() { public function activate() return $this->status; { } if ($this->status === self::STATUS_BLOCKED) {} throw new LogicException( Can not activate blocked project); } $this->status = self::STATUS_ACTIVE; } } © Kirill chEbba Chebunin. Creara 2012
  8. 8. rdRich Model. 3 Party? © Kirill chEbba Chebunin. Creara 2012
  9. 9. rdRich Model. 3 Party? Doctrine2 – Persistence Layer – Same as Serialization Symfony2 Form – Data Binder – Born to use Accessors – Data Transformers? Symfony2 Validation – External Validation – Heavyweight for Internal Validation © Kirill chEbba Chebunin. Creara 2012
  10. 10. Rich Model. Doctrine Side Effects $entity = $this->em->find($className, $id); try { $this->update($entity, $data); // Failed, no update was executed } catch (ValidationException $e) { // Do stuff on fail } // ................................. $entity->link($anotherEntity); $this->em->flush(); // Old invalid updates will be executed © Kirill chEbba Chebunin. Creara 2012
  11. 11. rdRich Model. 3 Party? © Kirill chEbba Chebunin. Creara 2012
  12. 12. Rich Model. Solution. Isolated Persistence Layer Transactional Operations Rich + Anemic Objects (DTO) Service Layer (Facade) © Kirill chEbba Chebunin. Creara 2012
  13. 13. Rich Model. DTO.class ProjectData{ /** * @AssertNotBlank * @AssertRegex(pattern="/[a-z0-9_]+/i") */ private $name; public function setName($name) { $this->name = $name; return $this; } public function getName() { return $this->name; }} © Kirill chEbba Chebunin. Creara 2012
  14. 14. Rich Model. Domain Interface.interface Project{ const STATUS_NEW = new; const STATUS_ACTIVE = active; const STATUS_BLOCKED = blocked; /** * Get project name * * @return string */ public function getName(); /** * Get project status * * @return string STATUS_* constant */ public function getStatus();} © Kirill chEbba Chebunin. Creara 2012
  15. 15. Rich Model. Service Layer.interface ProjectService{ /** * Create new project * * @param ProjectData $data * * @return Project * @throws ValidationException */ public function createProject(ProjectData $data);} © Kirill chEbba Chebunin. Creara 2012
  16. 16. Rich Model. Example.class ProjectManager implements ProjectService{ /* ... */ public function createProject(ProjectData $data) { $this->validate($data); $project = new EntityProject($data->getName()); $this->em->persist($project); $this->em->flush(); return $project; }} © Kirill chEbba Chebunin. Creara 2012
  17. 17. Rich Model. Example.class ProjectController extends Controller{ public function createAction(Request $request) { $data = new ProjectData(); $form = $this->createForm(new ProjectType(), $data); $form->bind($request); if ($form->isValid()) { return $this->projectService->createProject($data); } return $form; }} © Kirill chEbba Chebunin. Creara 2012
  18. 18. Rich Model. Solution. Client Code Controller, Command, etc. DTO Domain Interface Service Interface Persistence Layer © Kirill chEbba Chebunin. Creara 2012
  19. 19. Rich Model. Profit? © Kirill chEbba Chebunin. Creara 2012
  20. 20. Rich Model. Profit? © Kirill chEbba Chebunin. Creara 2012
  21. 21. rdRich Model. 3 Party Bundles. Anemic Model Managers Direct ObjectManager Manipulation © Kirill chEbba Chebunin. Creara 2012
  22. 22. Rich Model. FOSUser. © Kirill chEbba Chebunin. Creara 2012
  23. 23. Rich Model. FOSUser. Problems. User – Property Setters – Unnecessary Functions Manager – Low Level Methods © Kirill chEbba Chebunin. Creara 2012
  24. 24. Rich Model. FOSUser. Solution.Delegation instead of Inheritancehttp://thevanwinkleproject.blogspot.com/2011_02_01_archive.html http://www.halloweencostumes.com/sweet-daddy-pimp-costume.html © Kirill chEbba Chebunin. Creara 2012
  25. 25. Rich Model. FOSUser. Delegation.class UserWrapper implements FOSUserInterface{ private $user; private $email; private $enabled = false; public function __construct(DomainUser $user = null) { if ($user) { $this->setUser($user); } } public function setUser(DomainUser $user) { $this->user = $user; $this ->setEmail($user->getEmail()) ->setEnabled($user->getStatus() == DomainUser::STATUS_ACTIVE) ; } // Other UserInterface methods} © Kirill chEbba Chebunin. Creara 2012
  26. 26. Rich Model. FOSUser. Delegation.class FOSUserManager implements FOSUserManagerInterface{ public function updateUser(UserInterface $wrapper) { $user = $wrapper->getUser(); $userService = $this->userService; // User registration if (!$user) { $user = $userService->registerUser($wrapper->getRegistrationData()); // Update simple fields } else { $user = $userService->updateUser($id, $wrapper->getUserData()); } $wrapper->setUser($user); } // Other UserManagerInterface methods} © Kirill chEbba Chebunin. Creara 2012
  27. 27. Rich Model. SonataAdmin.http://southpark.wikia.com/wiki/File:ScauseForApplause00031.png © Kirill chEbba Chebunin. Creara 2012
  28. 28. Rich Model. Admin Architecture. SonataAdminBundle – Base CRUD View Functions – Dashboard, Menu, etc. – Interfaces for Storage Implementations ORM/ODM/... Bundles – Storage Implementations registered in Admin – Direct Object Manager Manipulation © Kirill chEbba Chebunin. Creara 2012
  29. 29. Rich Model. Admin Interfaces.We have interfaces! Implement them!class CustomModelManager implements ModelManagerInterface{ /* ... */ /** * {@inheritDoc} */ public function modelTransform($class, $instance) { // Method is not used in Admin } /** * {@inheritDoc} */ public function getParentFieldDescription($parentAssociationMapping, $class) { // Method is not used in Admin }} © Kirill chEbba Chebunin. Creara 2012
  30. 30. Rich Model. Admin Interfaces. © Kirill chEbba Chebunin. Creara 2012
  31. 31. Rich Model. Admin.Custom Model.interface Model{ /** * Create mew object instance * * @return mixed */ public function createInstance(); /** * Save new object * * @param object $object * * @throws RuntimeException */ public function create($object); /** * Update existing object * * @param $object * @throws RuntimeException */ public function update($object); // Some other methods} © Kirill chEbba Chebunin. Creara 2012
  32. 32. Rich Model. Admin.Custom Model.class UserModel implements Model{ public function createInstance() { return new UserWrapper(); } public function create($wrapper) { $user = $this->userService->registerUser( $wrapper->getRegistrationData() ); $wrapper->setUser($user); } public function update($wrapper) { $user = $this->userService->updateUser( $wrapper->getUserData() ); $wrapper->setUser($user); } // Some other methods} © Kirill chEbba Chebunin. Creara 2012
  33. 33. Rich Model. PROFIT! © Kirill chEbba Chebunin. Creara 2012
  34. 34. Rich Model. Summary. Object Logic in Object Class Separate Domain Objects from View Object Isolated Business Layer (Service Layer) Delegation instead of Inheritance Read 3rd Party Code © Kirill chEbba Chebunin. Creara 2012
  35. 35. Rich Model. Pros & Cons. OOPed (KISS, DRY, Patterns, blah, blah, blah) Pros: – Less side effects – Less code duplication – Less chances to shoot your leg – Easy serialization – Easy API creation – Etc, etc, etc. Cons: – More code – Codebase required – Hi shit sort out level © Kirill chEbba Chebunin. Creara 2012
  36. 36. Rich Model. Questions? © Kirill chEbba Chebunin. Creara 2012

×