Robert Lemke_The Real WorldBeyond the Blog Example
project founder of TYPO3 Flow and TYPO3 Neosco-founder of the TYPO3 Associationcoach, coder, consultant36 years old       ...
"the leftovers talks"
TEXT HERE
Application Structure
Request / Response    and MVC
$context = getenv(FLOW_CONTEXT) ?: (getenv(REDIRECT_FLOW_CONTEXT) ?: Development);$bootstrap = new TYPO3FlowCoreBootstrap(...
/** * Bootstraps the minimal infrastructure, resolves a fitting request handler and * then passes control over to that req...
/** * Handles a HTTP request * * @return void */public function handleRequest() {    $this->request = Request::createFromE...
/**  * Dispatches a request to a controller  *  * @param TYPO3FlowMvcRequestInterface $request The request to dispatch  * ...
/** * Book controller for the RobertLemke.Example.Bookshop package */class BookController extends ActionController {    /*...
/**  * Dispatches a request to a controller  *  * @param TYPO3FlowMvcRequestInterface $request The request to dispatch  * ...
/** * Handles a HTTP request * * @return void */public function handleRequest() {    $this->request = Request::createFromE...
/** * GeneratePdf action * * @param AcmeDemoDomainModelInvoice $invoice * @param boolean $forward */public function genera...
namespace AcmeDemo;class InvoiceController extends AcmeDemoControllerAbstractBaseController {   /**    * @var AcmeDemoAppl...
Forms
TEXT HERE
HTTP Caches
$this->response->getHeaders()  ->setCacheControlDirective(s-max-age, 100);
Safe Request / method tunneling
Network Working Group                                           R. FieldingRequest for Comments: 2616                     ...
9.1 Safe and Idempotent Methods9.1.1 Safe MethodsImplementors should be aware that the software represents the user inthei...
no automatic persistence
CSRF
<a href="http://myserver.com/book/amazing-apps-with-flow/delete">Delete Book</a>
<a href="http://myserver.com/book/amazing-apps-with-flow/delete?__csrfToken=abcdef1234567890">Delete Book</a>
<form enctype="multipart/form-data" name="newBook" action="book/create" method="post">    <input type="hidden" name="__tru...
speed!
Lazy Dependency Injection
class BookController extends ActionController {    /**     * @FlowInject     * @var BookRepository     */    protected $bo...
class BookController extends ActionController {    …    public function myAction() {        // $this->bookRepository is in...
$greet = function($name) {   printf("Hello %s", $name);};$greet(World);
class BookController extends BookController_Original implements ProxyInterface {   /**     * Autogenerated Proxy Method   ...
$bookRepository_reference = &$this->bookRepository;$this->bookRepository = Bootstrap::$staticObjectManager   ->getLazyDepe...
class BookController extends ActionController {    …    public function myAction() {       $this->bookRepository->findAll(...
class DependencyProxy {   …   /**     * Proxy magic call method which triggers the injection of the real dependency     * ...
Accounts, Users, AuthenticationFlow distinguishes between accounts and persons: _ account: TYPO3FlowSecurityAccount _ pers...
Creating Accounts _ always use the AccountFactory _ create a party (eg. a Person) separately _ assign the account to the p...
$account = $this->accountFactory->createAccountWithPassword(   $accountIdentifier,   $password,   array($role));$this->acc...
Roles
roles:  User: []  Manager: [User]  Editor: [User, TYPO3.Neos:Editor]
/** * Create a role and return a role instance for it. * * @param string $roleIdentifier * @return TYPO3FlowSecurityPolicy...
Virtual Browser
/** * @FlowInject * @var TYPO3FlowHttpClientBrowser */protected $browser;/** * @return array */public function getBookInfo...
Page Cache
/**  * Shows a list of books  *  * @return void  */public function indexAction() {     $this->view->assign(books, $books);}
RobertLemke_Example_Bookshop_Html:  frontend: TYPO3FlowCacheFrontendStringFrontend  backend: TYPO3FlowCacheBackendFileBack...
/**  * Shows a list of books  *  * @return string  */public function indexAction() {     $output = $this->htmlCache->get(B...
RobertLemkeExampleBookshopControllerBookController:  properties:    htmlCache:      object:        factoryObjectName: TYPO...
Ask me anything *                * technical
https://github.com/robertlemke
TYPO3 Flow Trainings andInhouse Workshops
Robert Lemke Blog
Robert Lemke_robertlemke.com@robertlemke
TYPO3 Flow: Beyond the Blog Example (Inspiring Flow 2013)
TYPO3 Flow: Beyond the Blog Example (Inspiring Flow 2013)
TYPO3 Flow: Beyond the Blog Example (Inspiring Flow 2013)
Upcoming SlideShare
Loading in …5
×

TYPO3 Flow: Beyond the Blog Example (Inspiring Flow 2013)

5,973 views

Published on

This talks was a mixture of hints for your next Flow application and insights into features of TYPO3 Flow 2.0

Published in: Technology, Business
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,973
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
27
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide

TYPO3 Flow: Beyond the Blog Example (Inspiring Flow 2013)

  1. 1. Robert Lemke_The Real WorldBeyond the Blog Example
  2. 2. project founder of TYPO3 Flow and TYPO3 Neosco-founder of the TYPO3 Associationcoach, coder, consultant36 years old TEXT HERElives in Lübeck, Germany1 wife, 2 daughters, 1 espresso machinelikes drumming
  3. 3. "the leftovers talks"
  4. 4. TEXT HERE
  5. 5. Application Structure
  6. 6. Request / Response and MVC
  7. 7. $context = getenv(FLOW_CONTEXT) ?: (getenv(REDIRECT_FLOW_CONTEXT) ?: Development);$bootstrap = new TYPO3FlowCoreBootstrap($context);$bootstrap->run();
  8. 8. /** * Bootstraps the minimal infrastructure, resolves a fitting request handler and * then passes control over to that request handler. * * @return void * @api */public function run() { Scripts::initializeClassLoader($this); Scripts::initializeSignalSlot($this); Scripts::initializePackageManagement($this); $this->activeRequestHandler = $this->resolveRequestHandler(); $this->activeRequestHandler->handleRequest();}
  9. 9. /** * Handles a HTTP request * * @return void */public function handleRequest() { $this->request = Request::createFromEnvironment(); $this->response = new Response(); $this->boot(); $this->resolveDependencies(); $this->request->injectSettings($this->settings); $this->router->setRoutesConfiguration($this->routesConfiguration); $actionRequest = $this->router->route($this->request); $this->securityContext->setRequest($actionRequest); $this->dispatcher->dispatch($actionRequest, $this->response); $this->response->makeStandardsCompliant($this->request); $this->response->send(); $this->bootstrap->shutdown(Runtime); $this->exit->__invoke();}
  10. 10. /** * Dispatches a request to a controller * * @param TYPO3FlowMvcRequestInterface $request The request to dispatch * @param TYPO3FlowMvcResponseInterface $response The response, to be modified by the cont * @return void * @throws TYPO3FlowMvcExceptionInfiniteLoopException * @api */public function dispatch(RequestInterface $request, ResponseInterface $response) { $dispatchLoopCount = 0; while (!$request->isDispatched()) { $controller = $this->resolveController($request); try { $this->emitBeforeControllerInvocation($request, $response, $controller); $controller->processRequest($request, $response); $this->emitAfterControllerInvocation($request, $response, $controller); } catch (StopActionException $exception) { $this->emitAfterControllerInvocation($request, $response, $controller); if ($exception instanceof ForwardException) { $request = $exception->getNextRequest(); } elseif ($request->isMainRequest() === FALSE) { $request = $request->getParentRequest(); } } }}
  11. 11. /** * Book controller for the RobertLemke.Example.Bookshop package */class BookController extends ActionController { /** * @FlowInject * @var RobertLemkeExampleBookshopDomainRepositoryBookRepository */ protected $bookRepository; /** * Shows a single book object * * @param RobertLemkeExampleBookshopDomainModelBook $book The book to show * @return void */ public function showAction(Book $book) { $this->view->assign(book, $book); }}
  12. 12. /** * Dispatches a request to a controller * * @param TYPO3FlowMvcRequestInterface $request The request to dispatch * @param TYPO3FlowMvcResponseInterface $response The response, to be modified by the cont * @return void * @throws TYPO3FlowMvcExceptionInfiniteLoopException * @api */public function dispatch(RequestInterface $request, ResponseInterface $response) { $dispatchLoopCount = 0; while (!$request->isDispatched()) { $controller = $this->resolveController($request); try { $this->emitBeforeControllerInvocation($request, $response, $controller); $controller->processRequest($request, $response); $this->emitAfterControllerInvocation($request, $response, $controller); } catch (StopActionException $exception) { $this->emitAfterControllerInvocation($request, $response, $controller); if ($exception instanceof ForwardException) { $request = $exception->getNextRequest(); } elseif ($request->isMainRequest() === FALSE) { $request = $request->getParentRequest(); } } }}
  13. 13. /** * Handles a HTTP request * * @return void */public function handleRequest() { $this->request = Request::createFromEnvironment(); $this->response = new Response(); $this->boot(); $this->resolveDependencies(); $this->request->injectSettings($this->settings); $this->router->setRoutesConfiguration($this->routesConfiguration); $actionRequest = $this->router->route($this->request); $this->securityContext->setRequest($actionRequest); $this->dispatcher->dispatch($actionRequest, $this->response); $this->response->makeStandardsCompliant($this->request); $this->response->send(); $this->bootstrap->shutdown(Runtime); $this->exit->__invoke();}
  14. 14. /** * GeneratePdf action * * @param AcmeDemoDomainModelInvoice $invoice * @param boolean $forward */public function generatePdfAction(AcmeDemoDomainModelInvoice $invoice, $forward = TRUE) $fopCommand = $this->settings[pdf][fopCommand]; $storageInvoiceFilename = $this->renderInvoiceFilename($invoice); $outputPath = $this->environment->getPathToTemporaryDirectory() . Acme.Demo/; $packageResourcesPath = $this->packageManager->getPackage(Acme.Demo)->getResourcesPath( $xmlPathAndFilename = $outputPath . Xml/. $storageInvoiceFilename . .xml; $configurationPathAndFilename = $outputPath . Configuration.xml; $pdfPathAndFilename = $outputPath.Pdf/. $storageInvoiceFilename; $fontsPath = $packageResourcesPath . Private/Fop/Fonts/; $xslPathAndFilename = $packageResourcesPath . Private/Fop/Xsl/Document.xsl; if (!file_exists($outputPath . Pdf)){ Files::createDirectoryRecursively($outputPath . Pdf); } if (!file_exists($outputPath . Xml)){ Files::createDirectoryRecursively($outputPath . Xml); } $standaloneView = new StandaloneView(); $standaloneView->setTemplatePathAndFilename(resource://Acme.Demo/Private/Fop/Xml/Documen $standaloneView->assign(invoice, $invoice);
  15. 15. namespace AcmeDemo;class InvoiceController extends AcmeDemoControllerAbstractBaseController { /** * @var AcmeDemoApplicationServiceInvoiceGenerator * @FlowInject */ protected $invoiceGenerator; /** * GeneratePdf action * * @param AcmeDemoDomainModelInvoice $invoice * @param boolean $forward */ public function generatePdfAction(AcmeDemoDomainModelInvoice $invoice, $forward = TRUE) $this->invoiceGeneratorService->generate($invoice, $pdf); $this->forward(download, NULL, NULL, array(invoice => $invoice)); }
  16. 16. Forms
  17. 17. TEXT HERE
  18. 18. HTTP Caches
  19. 19. $this->response->getHeaders() ->setCacheControlDirective(s-max-age, 100);
  20. 20. Safe Request / method tunneling
  21. 21. Network Working Group R. FieldingRequest for Comments: 2616 UC IrvineObsoletes: 2068 J. GettysCategory: Standards Track Compaq/W3C J. Mogul Compaq H. Frystyk W3C/MIT L. Masinter Xerox P. Leach Microsoft T. Berners-Lee W3C/MIT June 1999 Hypertext Transfer Protocol -- HTTP/1.1Status of this Memo This document specifies an Internet standards track protocol for the Internet community, and requests discussion and suggestions for improvements. Please refer to the current edition of the "Internet
  22. 22. 9.1 Safe and Idempotent Methods9.1.1 Safe MethodsImplementors should be aware that the software represents the user intheir interactions over the Internet, and should be careful to allow theuser to be aware of any actions they might take which may have anunexpected significance to themselves or others.In particular, the convention has been established that the GET and HEADmethods SHOULD NOT have the significance of taking an action other thanretrieval. These methods ought to be considered "safe". This allows useragents to represent other methods, such as POST, PUT and DELETE, in aspecial way, so that the user is made aware of the fact that a possiblyunsafe action is being requested.Naturally, it is not possible to ensure that the server does not generateside-effects as a result of performing a GET request; in fact, somedynamic resources consider that a feature. The important distinction hereis that the user did not request the side-effects, so therefore cannot beheld accountable for them.9.1.2 Idempotent Methods
  23. 23. no automatic persistence
  24. 24. CSRF
  25. 25. <a href="http://myserver.com/book/amazing-apps-with-flow/delete">Delete Book</a>
  26. 26. <a href="http://myserver.com/book/amazing-apps-with-flow/delete?__csrfToken=abcdef1234567890">Delete Book</a>
  27. 27. <form enctype="multipart/form-data" name="newBook" action="book/create" method="post"> <input type="hidden" name="__trustedProperties" value="a:1:{s:7:&quot;newBook&quot;;a:6: <input type="hidden" name="__csrfToken" value="10fa21087d49e5bb37d9c91248ea693a"/> ...
  28. 28. speed!
  29. 29. Lazy Dependency Injection
  30. 30. class BookController extends ActionController { /** * @FlowInject * @var BookRepository */ protected $bookRepository;}
  31. 31. class BookController extends ActionController { … public function myAction() { // $this->bookRepository is instance of Dependency Proxy $this->bookRepository->findAll(); // $this->bookRepository is the real BookRepository }}
  32. 32. $greet = function($name) { printf("Hello %s", $name);};$greet(World);
  33. 33. class BookController extends BookController_Original implements ProxyInterface { /** * Autogenerated Proxy Method */ public function __construct() { $this->Flow_Proxy_injectProperties(); }
  34. 34. $bookRepository_reference = &$this->bookRepository;$this->bookRepository = Bootstrap::$staticObjectManager ->getLazyDependencyByHash(d0e87f8f658d7866eec63db44a6918b4, $bookRepository_reference);if ($this->bookRepository === NULL) { $this->bookRepository = Bootstrap::$staticObjectManager ->createLazyDependency(d0e87f8f658d7866eec63db44a6918b4, $bookRepository_reference, RobertLemkeExampleBookshopDomainRepositoryBookRepository, function() { return Bootstrap::$staticObjectManager->get( RobertLemkeExampleBookshopDomainRepositoryBookRepository ); });}
  35. 35. class BookController extends ActionController { … public function myAction() { $this->bookRepository->findAll(); }}
  36. 36. class DependencyProxy { … /** * Proxy magic call method which triggers the injection of the real dependency * and returns the result of a call to the original method in the dependency * * @param string $methodName Name of the method to be called * @param array $arguments An array of arguments to be passed to the method * @return mixed */ public function __call($methodName, array $arguments) { return call_user_func_array(array($this->_activateDependency(), $methodName),$arguments); } /** * Activate the dependency and set it in the object. * * @return object The real dependency object * @api */ public function _activateDependency() { $realDependency = $this->builder->__invoke(); foreach($this->propertyVariables as &$propertyVariable) { $propertyVariable = $realDependency; } return $realDependency; }
  37. 37. Accounts, Users, AuthenticationFlow distinguishes between accounts and persons: _ account: TYPO3FlowSecurityAccount _ person: TYPO3PartyDomainModelPersonA person (or machine) can have any number of accounts.
  38. 38. Creating Accounts _ always use the AccountFactory _ create a party (eg. a Person) separately _ assign the account to the party _ add account and party to their respective repositories
  39. 39. $account = $this->accountFactory->createAccountWithPassword( $accountIdentifier, $password, array($role));$this->accountRepository->add($account);$person = new Person();$person->addAccount($account);$name = new PersonName(, Robert, , Lemke);$person->setName($name);$this->partyRepository->add($person);
  40. 40. Roles
  41. 41. roles: User: [] Manager: [User] Editor: [User, TYPO3.Neos:Editor]
  42. 42. /** * Create a role and return a role instance for it. * * @param string $roleIdentifier * @return TYPO3FlowSecurityPolicyRole * @throws TYPO3FlowSecurityExceptionRoleExistsException */public function createRole($roleIdentifier) { $this->initializeRolesFromPolicy(); if (isset($this->systemRoles[$roleIdentifier])) { throw new RoleExistsException(sprintf(Could not create role %s because a system role wi } if (preg_match(/^[w]+((.[w]+)*:[w]+)+$/, $roleIdentifier) !== 1) { throw new InvalidArgumentException(sprintf(Could not create role %s because it does no } if ($this->roleRepository->findByIdentifier($roleIdentifier) !== NULL) { throw new RoleExistsException(sprintf(Could not create role %s because a role with that } $role = new Role($roleIdentifier); $this->roleRepository->add($roleIdentifier); return $role;}
  43. 43. Virtual Browser
  44. 44. /** * @FlowInject * @var TYPO3FlowHttpClientBrowser */protected $browser;/** * @return array */public function getBookInfo($isbn) { $this->browser->setRequestEngine(new CurlEngine()); $response = $this->browser->request( http://isbndb.com/api/books.xml?index1=isbn&value1= . $isbn); $xml = simplexml_load_string($response->getContent()); … return $bookInfo;}
  45. 45. Page Cache
  46. 46. /** * Shows a list of books * * @return void */public function indexAction() { $this->view->assign(books, $books);}
  47. 47. RobertLemke_Example_Bookshop_Html: frontend: TYPO3FlowCacheFrontendStringFrontend backend: TYPO3FlowCacheBackendFileBackend
  48. 48. /** * Shows a list of books * * @return string */public function indexAction() { $output = $this->htmlCache->get(BookController_index); if ($output === FALSE) { $books = $this->bookRepository->findAll(); $this->view->assign(books, $books); $output = $this->view->render(); $this->htmlCache->set(BookController_index, $output); } return $output;}
  49. 49. RobertLemkeExampleBookshopControllerBookController: properties: htmlCache: object: factoryObjectName: TYPO3FlowCacheCacheManager factoryMethodName: getCache arguments: 1: value: RobertLemke_Example_Bookshop_Html
  50. 50. Ask me anything * * technical
  51. 51. https://github.com/robertlemke
  52. 52. TYPO3 Flow Trainings andInhouse Workshops
  53. 53. Robert Lemke Blog
  54. 54. Robert Lemke_robertlemke.com@robertlemke

×