0
Application Layer
ein Vortrag von Per Bernhardt
Agenda
• Disclaimer / Credits
• Ein kleines bisschen Theorie
• Ein echtes Beispiel: Chefkoch API
Credit goes to…
• http://martinfowler.com/
• http://domainlanguage.com/
• http://alistair.cockburn.us/
• http://www.whitew...
Ein bisschen
Theorie…
Application Layer
Presentation Layer
Infrastructure Layer
Domain Layer
Application Layer
Presentation Layer
Infrastructure Layer
Domain Layer
- Controller
- Template / HTML
- Session / HTTP
Application Layer
Presentation Layer
Infrastructure Layer
Domain Layer
- Controller
- Template / HTML
- Session / HTTP
- F...
Application Layer
Presentation Layer
Infrastructure Layer
Domain Layer
- Controller
- Template / HTML
- Session / HTTP
- F...
Application Layer
Presentation Layer
Infrastructure Layer
Domain Layer
- Controller
- Template / HTML
- Session / HTTP
- F...
Application Layer
Presentation Layer
Infrastructure Layer
Domain Layer
- Controller
- Template / HTML
- Session / HTTP
- F...
Application Layer
Presentation Layer
Infrastructure Layer
Domain Layer
- Controller
- Template / HTML
- Session / HTTP
- F...
Chefkoch API
POST /cookbooks/{id}/categories
<?php
!
namespace ChefkochBundleApiBundleController;
!
use SymfonyBundleFrameworkBundleControllerController;
use ChefkochD...
<?php
!
namespace ChefkochApplicationCookbookCommand;
!
use ChefkochApplicationCookbookRequestCategoryRequest;
use Chefkoc...
<?php
!
namespace PixelhouseApplicationEvent;
!
use PixelhouseApplicationCommand;
use PixelhouseApplicationUseCase;
use Pi...
<?php
!
namespace PixelhouseApplicationEvent;
!
class Events
{
const PRE_COMMAND = 'application.pre_command';
const POST_C...
<?php
!
namespace PixelhouseApplicationEvent;
!
use PixelhouseApplicationCommand;
!
class DispatchingService
{
!
...
!
pub...
<?php
!
namespace ChefkochInfrastructureApplication;
!
use PixelhouseApplicationEvent;
use PixelhouseEventDispatcherSubscr...
<?php
!
namespace PixelhouseApplicationSecurity;
!
use PixelhouseApplicationEvent;
use PixelhouseEventDispatcherSubscriber...
<?php
!
namespace ChefkochApplicationCookbookSecurity;
!
use ChefkochDomainModelCookbookCookbookRepository;
use ChefkochUs...
<?xml version="1.0" ?>
<container
xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSche...
<?php
!
namespace ChefkochApplicationCookbookUseCase;
!
use ChefkochApplicationCookbookCommandSaveCategoryCommand;
use Pix...
<?php
!
namespace ChefkochApplicationCookbookUseCase;
!
use PixelhouseApplicationUseCase;
use ChefkochApplicationCookbookC...
HTTP/1.1 201 Created
Per Bernhardt
info@perprogramming.de
perprogramming.de
slideshare.net/perprogramming
Bilder
• Warning: https://www.flickr.com/photos/gerardstolk/
6538330609
• Show Time: https://www.flickr.com/photos/
florida_p...
Application Layer in PHP
Application Layer in PHP
Application Layer in PHP
Application Layer in PHP
Application Layer in PHP
Nächste SlideShare
Wird geladen in ...5
×

Application Layer in PHP

949

Published on

Vortrag über eine beispielhafte Implementierung eines Application Layers in PHP

Published in: Technologie
0 Kommentare
0 Gefällt mir
Statistiken
Notizen
  • Hinterlassen Sie den ersten Kommentar

  • Be the first to like this

Keine Downloads
Views
Gesamtviews
949
Bei Slideshare
0
Aus Einbettungen
0
Anzahl an Einbettungen
0
Aktionen
Geteilt
0
Downloads
9
Kommentare
0
Gefällt mir
0
Einbettungen 0
No embeds

No notes for slide

Transcript of "Application Layer in PHP"

  1. 1. Application Layer ein Vortrag von Per Bernhardt
  2. 2. Agenda • Disclaimer / Credits • Ein kleines bisschen Theorie • Ein echtes Beispiel: Chefkoch API
  3. 3. Credit goes to… • http://martinfowler.com/ • http://domainlanguage.com/ • http://alistair.cockburn.us/ • http://www.whitewashing.de/ • und viele andere..
  4. 4. Ein bisschen Theorie…
  5. 5. Application Layer Presentation Layer Infrastructure Layer Domain Layer
  6. 6. Application Layer Presentation Layer Infrastructure Layer Domain Layer - Controller - Template / HTML - Session / HTTP
  7. 7. Application Layer Presentation Layer Infrastructure Layer Domain Layer - Controller - Template / HTML - Session / HTTP - Fasade - Transaktionen - Sicherheit / Zugriffsschutz - Integration / Orchestrierung
  8. 8. Application Layer Presentation Layer Infrastructure Layer Domain Layer - Controller - Template / HTML - Session / HTTP - Fasade - Transaktionen - Sicherheit / Zugriffsschutz - Integration / Orchestrierung - Daten - Geschäftslogik
  9. 9. Application Layer Presentation Layer Infrastructure Layer Domain Layer - Controller - Template / HTML - Session / HTTP - Fasade - Transaktionen - Sicherheit / Zugriffsschutz - Integration / Orchestrierung - Daten - Geschäftslogik - Datenbank - Mailserver - Logger - …
  10. 10. Application Layer Presentation Layer Infrastructure Layer Domain Layer - Controller - Template / HTML - Session / HTTP - Fasade - Transaktionen - Sicherheit / Zugriffsschutz - Integration / Orchestrierung - Daten - Geschäftslogik - Datenbank - Mailserver - Logger - …
  11. 11. Application Layer Presentation Layer Infrastructure Layer Domain Layer - Controller - Template / HTML - Session / HTTP - Fasade - Transaktionen - Sicherheit / Zugriffsschutz - Integration / Orchestrierung - Daten - Geschäftslogik - Datenbank - Mailserver - Logger - …
  12. 12. Chefkoch API
  13. 13. POST /cookbooks/{id}/categories
  14. 14. <?php ! namespace ChefkochBundleApiBundleController; ! use SymfonyBundleFrameworkBundleControllerController; use ChefkochDomainModelCookbookCookbookId use SensioBundleFrameworkExtraBundleConfigurationParamConverter; use ChefkochBundleApiBundleAnnotationApiSerialize; use ChefkochApplicationCookbookRequest; use ChefkochApplicationCookbookCommand; use PixelhouseApplicationEventDispatchingService; use PixelhouseApplicationResponse; ! class CookbookController extends Controller { ! ... ! /** * @ParamConverter("category", options={"deserialize"=true}) * @ApiSerialize * @return Response */ public function saveCategoryAction(CookbookId $cookbookId, RequestCategoryRequest $category) { return $this->getCookbookService()->execute( new CommandSaveCategoryCommand($cookbookId, $category) ); } ! ... ! /** * @return DispatchingService */ private function getCookbookService() { return $this->get('chefkoch_api.application.cookbook_service'); } }
  15. 15. <?php ! namespace ChefkochApplicationCookbookCommand; ! use ChefkochApplicationCookbookRequestCategoryRequest; use ChefkochApplicationCookbookSecurityCookbookWriteAccessRequired; use ChefkochDomainModelCookbookCookbookId; use PixelhouseApplicationCommand; ! class SaveCategoryCommand implements Command, CookbookWriteAccessRequired { ! /** @var CookbookId */ private $cookbookId; ! /** @var CategoryRequest */ private $categoryRequest; ! public function __construct(CookbookId $cookbookId, CategoryRequest $categoryRequest) { $this->cookbookId = $cookbookId; $this->categoryRequest = $categoryRequest; } ! public function getCookbookId() { return $this->cookbookId; } ! public function getCategoryRequest() { return $this->categoryRequest; } }
  16. 16. <?php ! namespace PixelhouseApplicationEvent; ! use PixelhouseApplicationCommand; use PixelhouseApplicationUseCase; use PixelhouseEventDispatcherEventDispatcher; ! class DispatchingService { ! /** @var EventDispatcher */ private $eventDispatcher; ! /** @var UseCase[] */ private $useCases = array(); ! public function __construct(EventDispatcher $eventDispatcher) { $this->eventDispatcher = $eventDispatcher; } ! public function registerCommand($commandClass, UseCase $useCase) { $this->useCases[$commandClass] = $useCase; } ! public function execute(Command $command) { ... } }
  17. 17. <?php ! namespace PixelhouseApplicationEvent; ! class Events { const PRE_COMMAND = 'application.pre_command'; const POST_COMMAND = 'application.post_command'; const EXCEPTION = 'application.exception'; }
  18. 18. <?php ! namespace PixelhouseApplicationEvent; ! use PixelhouseApplicationCommand; ! class DispatchingService { ! ... ! public function execute(Command $command) { try { $this->eventDispatcher->dispatch( Events::PRE_COMMAND, new CommandEvent($command) ); $response = $this->useCases[get_class($command)]->run($command); $this->eventDispatcher->dispatch( Events::POST_COMMAND, new PostCommandEvent($command, $response) ); ! return $response; } catch (Exception $exception) { $event = new CommandExceptionEvent($command, $exception); $this->eventDispatcher->dispatch( Events::EXCEPTION, $event ); if ($response = $event->getResponse()) { return $response; } else { throw $exception; } } } }
  19. 19. <?php ! namespace ChefkochInfrastructureApplication; ! use PixelhouseApplicationEvent; use PixelhouseEventDispatcherSubscriber; use DoctrineORMEntityManager; ! class DoctrineTransactionListener implements Subscriber { ! /** @var EntityManager */ private $entityManager; ! public function __construct(EntityManager $entityManager) { $this->entityManager = $entityManager; } ! public function preCommand(EventCommandEvent $event) { $this->entityManager->getConnection()->beginTransaction(); } ! public function postCommand(EventPostCommandEvent $event) { $this->entityManager->flush(); $this->entityManager->getConnection()->commit(); } ! public function onException(EventCommandExceptionEvent $event) { $this->entityManager->close(); if ($this->entityManager->getConnection()->isTransactionActive()) { $this->entityManager->getConnection()->rollBack(); } } }
  20. 20. <?php ! namespace PixelhouseApplicationSecurity; ! use PixelhouseApplicationEvent; use PixelhouseEventDispatcherSubscriber; ! class SecurityListener implements Subscriber { ! /** @var Context */ private $context; ! /** @var Policy[] */ private $policies = array(); ! public function __construct(Context $context) { $this->context = $context; } ! public function addPolicy(Policy $policy) { $this->policies[] = $policy; } ! /** * throws Exception */ public function preCommand(EventCommandEvent $event) { foreach ($this->policies as $policy) { $policy->check($this->securityContext, $event->getCommand()); } } }
  21. 21. <?php ! namespace ChefkochApplicationCookbookSecurity; ! use ChefkochDomainModelCookbookCookbookRepository; use ChefkochUserDomainModelUserRepository; use PixelhouseApplicationCommand; use PixelhouseApplicationSecurityAccessDeniedException; use PixelhouseApplicationSecurityContext; use PixelhouseApplicationSecurityPolicy; ! class CookbookAccessPolicy implements Policy { ! /** @var CookbookRepository */ private $cookbookRepository; ! /** @var UserRepository */ private $userRepository; ! public function __construct(CookbookRepository $cbRepo, UserRepository $uRepo) { $this->cookbookRepository = $cbRepo; $this->userRepository = $uRepo; } ! public function check(Context $context, Command $command) { if ($command instanceof CookbookWriteAccessRequired) { $cookbook = $this->cookbookRepository->findOneById($command->getCookbookId()); $user = $this->userRepository->findOneById($context->getUserId()); ! // Zugriff prüfen ... ! throw new AccessDeniedException(); } } }
  22. 22. <?xml version="1.0" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services ..."> <services> ... ! <service id="chefkoch_api.application.use_case.cookbook_save_category" class="ChefkochApplicationCookbookUseCaseSaveCategory"> <argument type="service" id="chefkoch_api.infrastructure.cookbook_category_repository" /> <argument type="service" id="chefkoch_api.infrastructure.user_repository" /> <argument type="service" id="chefkoch_api.application.security_context" /> <tag name="chefkoch_api.application.use_case" commandClass="ChefkochApplicationCookbookCommandSaveCategoryCommand" applicationService="chefkoch_api.application.cookbook_service" /> </service> ! ... </services> </container>
  23. 23. <?php ! namespace ChefkochApplicationCookbookUseCase; ! use ChefkochApplicationCookbookCommandSaveCategoryCommand; use PixelhouseApplicationSecurityContext; use PixelhouseApplicationUseCase; use ChefkochDomainModelCookbookCategoryRepository; use ChefkochUserDomainModelUserRepository; ! class SaveCategory implements UseCase { ! /** @var CategoryRepository */ private $categoryRepository; ! /** @var UserRepository */ private $userRepository; ! /** @var Context */ private $context; ! public function __construct(CategoryRepository $cRepo, UserRepository $uRepo, Context $context) { $this->categoryRepository = $cRepo; $this->userRepository = $uRepo; $this->context = $context; } ! public function run(SaveCategoryCommand $command) { ... } }
  24. 24. <?php ! namespace ChefkochApplicationCookbookUseCase; ! use PixelhouseApplicationUseCase; use ChefkochApplicationCookbookCommandSaveCategoryCommand; use ChefkochDomainModelCookbookCategory; use ChefkochApplicationCookbookNotificationCategorySavedSuccess; use ChefkochApplicationCookbookResponseCategoryResponse; use PixelhouseApplicationResponse; ! class SaveCategory implements UseCase { ... ! public function run(SaveCategoryCommand $command) { $user = $this->userRepository->findOneById($this->context->getUserId()); ! $category = new Category( $command->getCookbookId(), $user->getId(), $command->getCategoryRequest()->getName(), $command->getCategoryRequest()->getDescriptionText() ); ! $this->categoryRepository->add($category); ! $categoryResponse = new CategoryResponse($category, $user); ! $response = new Response(); $response->getNotification()->addMessage(new CategorySavedSuccess($categoryResponse)); ! return $response; } }
  25. 25. HTTP/1.1 201 Created
  26. 26. Per Bernhardt info@perprogramming.de perprogramming.de slideshare.net/perprogramming
  27. 27. Bilder • Warning: https://www.flickr.com/photos/gerardstolk/ 6538330609 • Show Time: https://www.flickr.com/photos/ florida_photo_guy/5212663826 • Question Marks: https://www.flickr.com/photos/ loneblackrider/315302588 • Thank You: https://www.flickr.com/photos/wwworks/ 4759535950
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×