TYPO3 Flow: Beyond the Blog Example (Inspiring Flow 2013)
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

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

on

  • 4,261 views

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

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

Statistics

Views

Total Views
4,261
Views on SlideShare
4,261
Embed Views
0

Actions

Likes
4
Downloads
21
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

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

  • 1. Robert Lemke_The Real WorldBeyond the Blog Example
  • 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. "the leftovers talks"
  • 4. TEXT HERE
  • 5. Application Structure
  • 6. Request / Response and MVC
  • 7. $context = getenv(FLOW_CONTEXT) ?: (getenv(REDIRECT_FLOW_CONTEXT) ?: Development);$bootstrap = new TYPO3FlowCoreBootstrap($context);$bootstrap->run();
  • 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. /** * 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. /** * 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. /** * 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. /** * 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. /** * 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. /** * 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. 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. Forms
  • 17. TEXT HERE
  • 18. HTTP Caches
  • 19. $this->response->getHeaders() ->setCacheControlDirective(s-max-age, 100);
  • 20. Safe Request / method tunneling
  • 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. 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. no automatic persistence
  • 24. CSRF
  • 25. <a href="http://myserver.com/book/amazing-apps-with-flow/delete">Delete Book</a>
  • 26. <a href="http://myserver.com/book/amazing-apps-with-flow/delete?__csrfToken=abcdef1234567890">Delete Book</a>
  • 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. speed!
  • 29. Lazy Dependency Injection
  • 30. class BookController extends ActionController { /** * @FlowInject * @var BookRepository */ protected $bookRepository;}
  • 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. $greet = function($name) { printf("Hello %s", $name);};$greet(World);
  • 33. class BookController extends BookController_Original implements ProxyInterface { /** * Autogenerated Proxy Method */ public function __construct() { $this->Flow_Proxy_injectProperties(); }
  • 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. class BookController extends ActionController { … public function myAction() { $this->bookRepository->findAll(); }}
  • 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. Accounts, Users, AuthenticationFlow distinguishes between accounts and persons: _ account: TYPO3FlowSecurityAccount _ person: TYPO3PartyDomainModelPersonA person (or machine) can have any number of accounts.
  • 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. $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. Roles
  • 41. roles: User: [] Manager: [User] Editor: [User, TYPO3.Neos:Editor]
  • 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. Virtual Browser
  • 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. Page Cache
  • 46. /** * Shows a list of books * * @return void */public function indexAction() { $this->view->assign(books, $books);}
  • 47. RobertLemke_Example_Bookshop_Html: frontend: TYPO3FlowCacheFrontendStringFrontend backend: TYPO3FlowCacheBackendFileBackend
  • 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. RobertLemkeExampleBookshopControllerBookController: properties: htmlCache: object: factoryObjectName: TYPO3FlowCacheCacheManager factoryMethodName: getCache arguments: 1: value: RobertLemke_Example_Bookshop_Html
  • 50. Ask me anything * * technical
  • 51. https://github.com/robertlemke
  • 52. TYPO3 Flow Trainings andInhouse Workshops
  • 53. Robert Lemke Blog
  • 54. Robert Lemke_robertlemke.com@robertlemke