SlideShare a Scribd company logo
1 of 48
Download to read offline
Save repository
from save
Norbert Orzechowicz

@norzechowicz
Repository
Here I should add some complicated
description of repository pattern. 

But instead of that…
Keep calm
and
think about…
bookshelf
Bookshelf specification
• it contains books
• it contains books from mixed categories
• it allows you to add new books when it’s not full
• it allows you to find and pick a book or books
• it allows you to remove specific book or books from it
Bookshelf specification
• it contains books
• it contains books from mixed categories
• it allows you to add new books when it’s not full
• it allows you to find and pick specific books/book
• it allows you to remove specific books/book from it
<?php
interface Bookshelf
{
/**
* @param Book $book
* @return bool
*/
public function contains(Book $book);
/**
* @param Book $book
*/
public function add(Book $book);
/**
* @param Title $title
* @return Book
*/
public function findBy(Title $title);
/**
* @param Book $book
*/
public function remove(Book $book);
}
Conclusions
• bookshelf acts as a collection
• bookshelf does not handle book changes
• bookshelf implements repository pattern
Repository
Mediates between the domain and data
mapping layers using a collection-like
interface for accessing domain objects.
Martin Fowler
From pure data
to entity
Database
+----+-------------------+------------+----------------------------------+
| id | title | author | description |
+----+-------------------+------------+----------------------------------+
| 1 | 50 shades of grey | E.L. James | Fifty Shades of Grey is a... |
+----+-------------------+------------+----------------------------------+
But first let me introduce
you few building blocks
Data Access Object
<?php
class BookDataAccessObject
{
public function getByTitle($title);



public function saveNew(array $data);
}
Hydrator
<?php
class BookHydrator
{
/**
* @param array $data
* @return Book
*/
public function hydrateBook($data = []);
}
Converter
<?php
class BookConverter
{
/**
* @param Book $book
* @return array
*/
public function toArray(Book $book);
}
Do you already know
where to assemble them?
Book Repository
<?php
class Bookshelf
{
/**
* @param Title $title
* @return Book
*/
public function findBy(Title $title)
{
$bookData = $this->dao->getByTitle((string) $title);
$book = $this->hydrator->hydrateBook($bookData);
return $book;
}
}
Book Repository
<?php
class Bookshelf
{
/**
* @param Book $book
*/
public function add(Book $book)
{
$data = $this->converter->toArray($book);
$this->dao->saveNew($data);
}
}
What about changes?
Well if you don’t ask your bookshelf
to handle changes why would you
like to ask repository for that?
Example of repository with
too many responsibilities
<?php
interface Bookshelf
{
public function contains(Book $book);
public function add(Book $book);
public function findBy(Title $title);
public function remove(Book $book);
/**
* Sometimes also Update/Handle/Persist
* @param Book $book
*/
public function save(Book $book);
}
Persistence
repositories?
Excuses…
So how to handle
changes?
Unit of Work
Maintains a list of objects affected by
a business transaction and coordinates
the writing out of changes and the resolution
of concurrency problems.
Martin Fowler
Unit of Work
<?php
class UnitOfWork
{
public function watch($entity);
public function remove($entity);
public function commit();
public function rollback();
}
UoW expected extension
points
• Entity Created
• Entity Updated
• Entity Removed
Repository & UoW
<?php
class BookRepository
{
public function add(Book $book)
{
$this->uow->watch($book);
}
public function findBy(Title $title)
{
$bookData = $this->dao->getByTitle((string) $title);
$book = $this->hydrator->hydrateBook($bookData);
$this->uow->watch($book);
return $book;
}
}
Commit?
(save changes, create new entities, delete entities)
Dummy Update Example
<?php
class BookController
{
public function updateBookDescriptionAction(Request $request, $title)
{
$book = $this->get('book.repository')->findBy(new Title($title));
$form = $this->createForm(new FormType());
$form->handle($request);
if ($form->isValid()) {
$book->updateDescription($form->get('description')->getData());
$this->get('unit_of_work')->commit();
return $this->redirect($this->generateUrl('homepage');
}
return $this->render('book/updateDescription.html.twig', [
'book' => $book, 'form' => $form->createView()
]);
}
}
Dummy Remove Example
<?php
class BookController
{
public function removeBookAction($title)
{
$book = $this->get('book.repository')->remove(new Title($title));
$this->get('unit_of_work')->commit();
return $this->render('book/updateDescription.html.twig', [
'book' => $book, 'form' => $form->createView()
]);
}
}
Rollback?
In most web applications there
is no need for rollback because
objects become useless when
response is created.
Still wanna see more?
(more of abstraction of course)
https://github.com/isolate-org
Isolate is a PHP framework that will help you in isolating
business logic from persistence layer.
current version: 1.0.0-alpha2
https://twitter.com/isolate_php
Isolate
Think about it as a registry of persistence contexts
Persistence Context
It’s responsible for opening and closing transactions
Transaction
It’s an abstraction over the unit of work (more or less)
Repository with Isolate
<?php
class BookRepository
{
public function add(Book $book)
{
$persistenceContext = $this->get('isolate')->getContext();
$transaction = $persistenceContext->openTransaction();
$transaction->persist($book);
}
public function findBy(Title $title)
{
$bookData = $this->dao->getByTitle((string) $title);
$book = $this->hydrator->hydrateBook($bookData);
$persistenceContext = $this->get('isolate')->getContext();
if ($persistenceContext->hasOpenTransaction()) {
$transaction = $persistenceContext->openTransaction();
$transaction->persist($book);
}
return $book;
}
}
Update action example
<?php
class BookController
{
public function updateBookDescriptionAction(Request $request, $title)
{
$this->get('isolate')->getContext()->openTransaction();
$book = $this->get('book.repository')->findBy(new Title($title));
$form = $this->createForm(new FormType());
$form->handle($request);
if ($form->isValid()) {
$book->updateDescription($form->get('description')->getData());
$this->get('isolate')->getContext()->closeTransaction();
return $this->redirect($this->generateUrl('homepage');
}
return $this->render('book/updateDescription.html.twig', [
'book' => $book, 'form' => $form->createView()
]);
}
}
But there is more code
in this example….
Refactoring
• implement commands and command handlers
(tactician)
• implement middlewares (tactician)
• move isolate transaction management to
middlewares
• move business logic into command handlers
Transaction middleware
<?php
/**
* This code is available in Isolate Tactician Bridge
*/
class TransactionMiddleware implements Middleware
{
public function execute($command, callable $next)
{
$context = $this->isolate->getContext();
$transaction = $context->openTransaction();
try {
$returnValue = $next($command);
$context->closeTransaction();
return $returnValue;
} catch (Exception $e) {
$transaction->rollback();
throw $e;
}
}
}
Update book command
handler
<?php
class UpdateBookHandler
{
public function handle(UpdateBookCommand $command)
{
$book = $this->bookshelf->findBy(new Title($command->getTitle()));
if (empty($book)) {
throw new BookNotFoundException();
}
$book->updateDescription($command->getDescription());
}
}
Update book controller
<?php
class BookController
{
public function updateBookAction(Request $request, $title)
{
$form = $this->createForm(new FormType());
$form->handle($request);
if ($form->isValid()) {
$command = new UpdateBookCommand($title, $form->get('description')->getData());
$this->get('command_bus')->handle($command);
return $this->redirect($this->generateUrl('homepage');
}
return $this->render('book/updateDescription.html.twig', [
'book' => $book, 'form' => $form->createView()
]);
}
}
Isolate extensions
• Tactician Bridge

https://github.com/isolate-org/tactician-bridge
• Doctrine Bridge

https://github.com/isolate-org/doctrine-bridge
• Symfony Bundle

https://github.com/isolate-org/symfony-bundle



Advantages
• application totally decoupled from storage
• possibility to switch storage for tests
• possibility to replace ORM with ODM, webservice,
filesystem or anything else
• possibility to delay a decision about storage type
• possibility to increase performance by replacing auto-
generated sql queries with custom, optimized queries
• clean architecture not impacted by persistence layer
Disadvantages
• higher entry point for junior developers
• require better understanding of how your storage
works
Questions?

More Related Content

What's hot

Code obfuscation
Code obfuscationCode obfuscation
Code obfuscation
bijondesai
 
Mindset reengineering
Mindset reengineeringMindset reengineering
Mindset reengineering
dutconsult
 

What's hot (20)

Salesforce Tutorial for Beginners: Basic Salesforce Introduction
Salesforce Tutorial for Beginners: Basic Salesforce IntroductionSalesforce Tutorial for Beginners: Basic Salesforce Introduction
Salesforce Tutorial for Beginners: Basic Salesforce Introduction
 
Episode 10 - External Services in Salesforce
Episode 10 - External Services in SalesforceEpisode 10 - External Services in Salesforce
Episode 10 - External Services in Salesforce
 
VSA Webinar: Open Probe Confirm
VSA Webinar: Open Probe ConfirmVSA Webinar: Open Probe Confirm
VSA Webinar: Open Probe Confirm
 
Code obfuscation
Code obfuscationCode obfuscation
Code obfuscation
 
Mindset reengineering
Mindset reengineeringMindset reengineering
Mindset reengineering
 
Partner Lead Generation Proposal Template
Partner Lead Generation Proposal TemplatePartner Lead Generation Proposal Template
Partner Lead Generation Proposal Template
 
Value Based Selling™ business model - Intro
Value Based Selling™  business model - IntroValue Based Selling™  business model - Intro
Value Based Selling™ business model - Intro
 
Define Your WoW! Factor – Create an Unforgettable Brand
Define Your WoW! Factor – Create an Unforgettable BrandDefine Your WoW! Factor – Create an Unforgettable Brand
Define Your WoW! Factor – Create an Unforgettable Brand
 
Marketing Cloud - Partner Office Hour (February 2, 2016)
Marketing Cloud - Partner Office Hour (February 2, 2016)Marketing Cloud - Partner Office Hour (February 2, 2016)
Marketing Cloud - Partner Office Hour (February 2, 2016)
 
Best Practices for Salesforce Campaigns
Best Practices for Salesforce CampaignsBest Practices for Salesforce Campaigns
Best Practices for Salesforce Campaigns
 
E Commerce Application Web Design Proposal PowerPoint Presentation Slides
E Commerce Application Web Design Proposal PowerPoint Presentation SlidesE Commerce Application Web Design Proposal PowerPoint Presentation Slides
E Commerce Application Web Design Proposal PowerPoint Presentation Slides
 
CQRS and Event Sourcing, An Alternative Architecture for DDD
CQRS and Event Sourcing, An Alternative Architecture for DDDCQRS and Event Sourcing, An Alternative Architecture for DDD
CQRS and Event Sourcing, An Alternative Architecture for DDD
 
Episode 14 - Basics of HTML for Salesforce
Episode 14 - Basics of HTML for SalesforceEpisode 14 - Basics of HTML for Salesforce
Episode 14 - Basics of HTML for Salesforce
 
Organic Growth
Organic GrowthOrganic Growth
Organic Growth
 
Dynamics 365 Portals
Dynamics 365 PortalsDynamics 365 Portals
Dynamics 365 Portals
 
Exploring the Salesforce REST API
Exploring the Salesforce REST APIExploring the Salesforce REST API
Exploring the Salesforce REST API
 
Channel Incentives And Loyalty Programs
Channel Incentives And Loyalty ProgramsChannel Incentives And Loyalty Programs
Channel Incentives And Loyalty Programs
 
You've Changed: Field Audit Trails and the Salesforce Time Machine
You've Changed: Field Audit Trails and the Salesforce Time MachineYou've Changed: Field Audit Trails and the Salesforce Time Machine
You've Changed: Field Audit Trails and the Salesforce Time Machine
 
Best Practices with Apex in 2022.pdf
Best Practices with Apex in 2022.pdfBest Practices with Apex in 2022.pdf
Best Practices with Apex in 2022.pdf
 
Magento Product Recommendations powered by Adobe Sensei (AI)
Magento Product Recommendations powered by Adobe Sensei (AI)Magento Product Recommendations powered by Adobe Sensei (AI)
Magento Product Recommendations powered by Adobe Sensei (AI)
 

Viewers also liked

Viewers also liked (16)

A walk through system layers
A walk through system layersA walk through system layers
A walk through system layers
 
Introduction the Repository Pattern
Introduction the Repository PatternIntroduction the Repository Pattern
Introduction the Repository Pattern
 
Grammar
GrammarGrammar
Grammar
 
Wzorce Repository, Unity of Work, Devexpress MVC w architekturze Asp.net MVC
Wzorce Repository, Unity of Work, Devexpress MVC  w architekturze Asp.net MVCWzorce Repository, Unity of Work, Devexpress MVC  w architekturze Asp.net MVC
Wzorce Repository, Unity of Work, Devexpress MVC w architekturze Asp.net MVC
 
Mysqlnd, an unknown powerful PHP extension
Mysqlnd, an unknown powerful PHP extensionMysqlnd, an unknown powerful PHP extension
Mysqlnd, an unknown powerful PHP extension
 
Domain Driven Design in Rails
Domain Driven Design in RailsDomain Driven Design in Rails
Domain Driven Design in Rails
 
MVVM в WinForms – DevExpress Way (теория и практика)
MVVM в WinForms – DevExpress Way (теория и практика)MVVM в WinForms – DevExpress Way (теория и практика)
MVVM в WinForms – DevExpress Way (теория и практика)
 
Generic repository pattern with ASP.NET MVC and Entity Framework
Generic repository pattern with ASP.NET MVC and Entity FrameworkGeneric repository pattern with ASP.NET MVC and Entity Framework
Generic repository pattern with ASP.NET MVC and Entity Framework
 
Solid vs php
Solid vs phpSolid vs php
Solid vs php
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
 
Repository design pattern in laravel - Samir Poudel
Repository design pattern in laravel - Samir PoudelRepository design pattern in laravel - Samir Poudel
Repository design pattern in laravel - Samir Poudel
 
DDD Repository
DDD RepositoryDDD Repository
DDD Repository
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
Repository and Unit Of Work Design Patterns
Repository and Unit Of Work Design PatternsRepository and Unit Of Work Design Patterns
Repository and Unit Of Work Design Patterns
 
PhpSpec extension points
PhpSpec extension pointsPhpSpec extension points
PhpSpec extension points
 
Laravel 5 In Depth
Laravel 5 In DepthLaravel 5 In Depth
Laravel 5 In Depth
 

Similar to Save Repository From Save

SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
jsmith92
 
X Query for beginner
X Query for beginnerX Query for beginner
X Query for beginner
Nguyen Quang
 
First java-server-faces-tutorial-en
First java-server-faces-tutorial-enFirst java-server-faces-tutorial-en
First java-server-faces-tutorial-en
techbed
 
Understanding PHP objects
Understanding PHP objectsUnderstanding PHP objects
Understanding PHP objects
julien pauli
 
Zf Zend Db by aida
Zf Zend Db by aidaZf Zend Db by aida
Zf Zend Db by aida
waraiotoko
 

Similar to Save Repository From Save (20)

SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
X Query for beginner
X Query for beginnerX Query for beginner
X Query for beginner
 
DBIx::Class introduction - 2010
DBIx::Class introduction - 2010DBIx::Class introduction - 2010
DBIx::Class introduction - 2010
 
First java-server-faces-tutorial-en
First java-server-faces-tutorial-enFirst java-server-faces-tutorial-en
First java-server-faces-tutorial-en
 
A single language for backend and frontend from AngularJS to cloud with Clau...
A single language for backend and frontend  from AngularJS to cloud with Clau...A single language for backend and frontend  from AngularJS to cloud with Clau...
A single language for backend and frontend from AngularJS to cloud with Clau...
 
A single language for backend and frontend from AngularJS to cloud with Clau...
A single language for backend and frontend  from AngularJS to cloud with Clau...A single language for backend and frontend  from AngularJS to cloud with Clau...
A single language for backend and frontend from AngularJS to cloud with Clau...
 
Xpath & xquery
Xpath & xqueryXpath & xquery
Xpath & xquery
 
Practical PHP 5.3
Practical PHP 5.3Practical PHP 5.3
Practical PHP 5.3
 
Development Approach
Development ApproachDevelopment Approach
Development Approach
 
Firebase for Apple Developers - SwiftHeroes
Firebase for Apple Developers - SwiftHeroesFirebase for Apple Developers - SwiftHeroes
Firebase for Apple Developers - SwiftHeroes
 
Object Oriented Programming in PHP
Object Oriented Programming in PHPObject Oriented Programming in PHP
Object Oriented Programming in PHP
 
OOPs Concept
OOPs ConceptOOPs Concept
OOPs Concept
 
Php course-in-navimumbai
Php course-in-navimumbaiPhp course-in-navimumbai
Php course-in-navimumbai
 
Understanding PHP objects
Understanding PHP objectsUnderstanding PHP objects
Understanding PHP objects
 
Zf Zend Db by aida
Zf Zend Db by aidaZf Zend Db by aida
Zf Zend Db by aida
 
SPL Primer
SPL PrimerSPL Primer
SPL Primer
 
Driving Design with PhpSpec
Driving Design with PhpSpecDriving Design with PhpSpec
Driving Design with PhpSpec
 
laravel-53
laravel-53laravel-53
laravel-53
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
 
Modern php
Modern phpModern php
Modern php
 

Recently uploaded

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 

Recently uploaded (20)

ManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide Deck
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 

Save Repository From Save

  • 3. Repository Here I should add some complicated description of repository pattern. 
 But instead of that…
  • 5. Bookshelf specification • it contains books • it contains books from mixed categories • it allows you to add new books when it’s not full • it allows you to find and pick a book or books • it allows you to remove specific book or books from it
  • 6. Bookshelf specification • it contains books • it contains books from mixed categories • it allows you to add new books when it’s not full • it allows you to find and pick specific books/book • it allows you to remove specific books/book from it
  • 7. <?php interface Bookshelf { /** * @param Book $book * @return bool */ public function contains(Book $book); /** * @param Book $book */ public function add(Book $book); /** * @param Title $title * @return Book */ public function findBy(Title $title); /** * @param Book $book */ public function remove(Book $book); }
  • 8. Conclusions • bookshelf acts as a collection • bookshelf does not handle book changes • bookshelf implements repository pattern
  • 9. Repository Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects. Martin Fowler
  • 11. Database +----+-------------------+------------+----------------------------------+ | id | title | author | description | +----+-------------------+------------+----------------------------------+ | 1 | 50 shades of grey | E.L. James | Fifty Shades of Grey is a... | +----+-------------------+------------+----------------------------------+
  • 12. But first let me introduce you few building blocks
  • 13. Data Access Object <?php class BookDataAccessObject { public function getByTitle($title);
 
 public function saveNew(array $data); }
  • 14. Hydrator <?php class BookHydrator { /** * @param array $data * @return Book */ public function hydrateBook($data = []); }
  • 15. Converter <?php class BookConverter { /** * @param Book $book * @return array */ public function toArray(Book $book); }
  • 16. Do you already know where to assemble them?
  • 17. Book Repository <?php class Bookshelf { /** * @param Title $title * @return Book */ public function findBy(Title $title) { $bookData = $this->dao->getByTitle((string) $title); $book = $this->hydrator->hydrateBook($bookData); return $book; } }
  • 18. Book Repository <?php class Bookshelf { /** * @param Book $book */ public function add(Book $book) { $data = $this->converter->toArray($book); $this->dao->saveNew($data); } }
  • 20. Well if you don’t ask your bookshelf to handle changes why would you like to ask repository for that?
  • 21. Example of repository with too many responsibilities <?php interface Bookshelf { public function contains(Book $book); public function add(Book $book); public function findBy(Title $title); public function remove(Book $book); /** * Sometimes also Update/Handle/Persist * @param Book $book */ public function save(Book $book); }
  • 23. So how to handle changes?
  • 24. Unit of Work Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems. Martin Fowler
  • 25. Unit of Work <?php class UnitOfWork { public function watch($entity); public function remove($entity); public function commit(); public function rollback(); }
  • 26. UoW expected extension points • Entity Created • Entity Updated • Entity Removed
  • 27. Repository & UoW <?php class BookRepository { public function add(Book $book) { $this->uow->watch($book); } public function findBy(Title $title) { $bookData = $this->dao->getByTitle((string) $title); $book = $this->hydrator->hydrateBook($bookData); $this->uow->watch($book); return $book; } }
  • 28. Commit? (save changes, create new entities, delete entities)
  • 29. Dummy Update Example <?php class BookController { public function updateBookDescriptionAction(Request $request, $title) { $book = $this->get('book.repository')->findBy(new Title($title)); $form = $this->createForm(new FormType()); $form->handle($request); if ($form->isValid()) { $book->updateDescription($form->get('description')->getData()); $this->get('unit_of_work')->commit(); return $this->redirect($this->generateUrl('homepage'); } return $this->render('book/updateDescription.html.twig', [ 'book' => $book, 'form' => $form->createView() ]); } }
  • 30. Dummy Remove Example <?php class BookController { public function removeBookAction($title) { $book = $this->get('book.repository')->remove(new Title($title)); $this->get('unit_of_work')->commit(); return $this->render('book/updateDescription.html.twig', [ 'book' => $book, 'form' => $form->createView() ]); } }
  • 32. In most web applications there is no need for rollback because objects become useless when response is created.
  • 33. Still wanna see more? (more of abstraction of course)
  • 34. https://github.com/isolate-org Isolate is a PHP framework that will help you in isolating business logic from persistence layer. current version: 1.0.0-alpha2 https://twitter.com/isolate_php
  • 35. Isolate Think about it as a registry of persistence contexts
  • 36. Persistence Context It’s responsible for opening and closing transactions
  • 37. Transaction It’s an abstraction over the unit of work (more or less)
  • 38. Repository with Isolate <?php class BookRepository { public function add(Book $book) { $persistenceContext = $this->get('isolate')->getContext(); $transaction = $persistenceContext->openTransaction(); $transaction->persist($book); } public function findBy(Title $title) { $bookData = $this->dao->getByTitle((string) $title); $book = $this->hydrator->hydrateBook($bookData); $persistenceContext = $this->get('isolate')->getContext(); if ($persistenceContext->hasOpenTransaction()) { $transaction = $persistenceContext->openTransaction(); $transaction->persist($book); } return $book; } }
  • 39. Update action example <?php class BookController { public function updateBookDescriptionAction(Request $request, $title) { $this->get('isolate')->getContext()->openTransaction(); $book = $this->get('book.repository')->findBy(new Title($title)); $form = $this->createForm(new FormType()); $form->handle($request); if ($form->isValid()) { $book->updateDescription($form->get('description')->getData()); $this->get('isolate')->getContext()->closeTransaction(); return $this->redirect($this->generateUrl('homepage'); } return $this->render('book/updateDescription.html.twig', [ 'book' => $book, 'form' => $form->createView() ]); } }
  • 40. But there is more code in this example….
  • 41. Refactoring • implement commands and command handlers (tactician) • implement middlewares (tactician) • move isolate transaction management to middlewares • move business logic into command handlers
  • 42. Transaction middleware <?php /** * This code is available in Isolate Tactician Bridge */ class TransactionMiddleware implements Middleware { public function execute($command, callable $next) { $context = $this->isolate->getContext(); $transaction = $context->openTransaction(); try { $returnValue = $next($command); $context->closeTransaction(); return $returnValue; } catch (Exception $e) { $transaction->rollback(); throw $e; } } }
  • 43. Update book command handler <?php class UpdateBookHandler { public function handle(UpdateBookCommand $command) { $book = $this->bookshelf->findBy(new Title($command->getTitle())); if (empty($book)) { throw new BookNotFoundException(); } $book->updateDescription($command->getDescription()); } }
  • 44. Update book controller <?php class BookController { public function updateBookAction(Request $request, $title) { $form = $this->createForm(new FormType()); $form->handle($request); if ($form->isValid()) { $command = new UpdateBookCommand($title, $form->get('description')->getData()); $this->get('command_bus')->handle($command); return $this->redirect($this->generateUrl('homepage'); } return $this->render('book/updateDescription.html.twig', [ 'book' => $book, 'form' => $form->createView() ]); } }
  • 45. Isolate extensions • Tactician Bridge
 https://github.com/isolate-org/tactician-bridge • Doctrine Bridge
 https://github.com/isolate-org/doctrine-bridge • Symfony Bundle
 https://github.com/isolate-org/symfony-bundle
 

  • 46. Advantages • application totally decoupled from storage • possibility to switch storage for tests • possibility to replace ORM with ODM, webservice, filesystem or anything else • possibility to delay a decision about storage type • possibility to increase performance by replacing auto- generated sql queries with custom, optimized queries • clean architecture not impacted by persistence layer
  • 47. Disadvantages • higher entry point for junior developers • require better understanding of how your storage works