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
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);
}
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();
}
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
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()
]);
}
}
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