Robert Lemke_


The Real World
Beyond the Blog Example
project founder of TYPO3 Flow and TYPO3 Neos

co-founder of the TYPO3 Association

coach, coder, consultant

36 years old

                      TEXT HERE
lives in Lübeck, Germany

1 wife, 2 daughters, 1 espresso machine

likes drumming
"the leftovers talks"
TEXT HERE
Application Structure
Request / Response
    and MVC
$context = getenv('FLOW_CONTEXT') ?: (getenv('REDIRECT_FLOW_CONTEXT') ?: 'Development');
$bootstrap = new TYPO3FlowCoreBootstrap($context);
$bootstrap->run();
/**
 * 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();
}
/**
 * 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();
}
/**
  * 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();
           }
        }
     }
}
/**
 * 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);
    }

}
/**
  * 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();
           }
        }
     }
}
/**
 * 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();
}
/**
 * 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);
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));
   }
Forms
TEXT HERE
HTTP Caches
$this->response->getHeaders()
  ->setCacheControlDirective('s-max-age', 100);
Safe Request / method tunneling
Network Working Group                                           R. Fielding
Request for Comments: 2616                                        UC Irvine
Obsoletes: 2068                                                   J. Gettys
Category: 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.1


Status 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
9.1 Safe and Idempotent Methods

9.1.1 Safe Methods

Implementors should be aware that the software represents the user in
their interactions over the Internet, and should be careful to allow the
user to be aware of any actions they might take which may have an
unexpected significance to themselves or others.

In particular, the convention has been established that the GET and HEAD
methods SHOULD NOT have the significance of taking an action other than
retrieval. These methods ought to be considered "safe". This allows user
agents to represent other methods, such as POST, PUT and DELETE, in a
special way, so that the user is made aware of the fact that a possibly
unsafe action is being requested.

Naturally, it is not possible to ensure that the server does not generate
side-effects as a result of performing a GET request; in fact, some
dynamic resources consider that a feature. The important distinction here
is that the user did not request the side-effects, so therefore cannot be
held accountable for them.

9.1.2 Idempotent Methods
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="__trustedProperties" value="a:1:{s:7:&quot;newBook&quot;;a:6:
    <input type="hidden" name="__csrfToken" value="10fa21087d49e5bb37d9c91248ea693a"/>

    ...
speed!
Lazy Dependency Injection
class BookController extends ActionController {

    /**
     * @FlowInject
     * @var BookRepository
     */
    protected $bookRepository;

}
class BookController extends ActionController {

    …

    public function myAction() {

        // $this->bookRepository is instance of Dependency Proxy

        $this->bookRepository->findAll();

        // $this->bookRepository is the real BookRepository

    }

}
$greet = function($name) {
   printf("Hello %s", $name);
};

$greet('World');
class BookController extends BookController_Original implements ProxyInterface {

   /**
     * Autogenerated Proxy Method
     */
   public function __construct() {
        $this->Flow_Proxy_injectProperties();
   }
$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'
       );
   });

}
class BookController extends ActionController {

    …

    public function myAction() {
       $this->bookRepository->findAll();
    }

}
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;
   }
Accounts, Users, Authentication

Flow distinguishes between accounts and persons:
 _ account: TYPO3FlowSecurityAccount
 _ person: TYPO3PartyDomainModelPerson


A person (or machine) can have any number of accounts.
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
$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);
Roles
roles:
  User: []
  Manager: ['User']
  Editor: ['User', 'TYPO3.Neos:Editor']
/**
 * 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;
}
Virtual Browser
/**
 * @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;
}
Page Cache
/**
  * Shows a list of books
  *
  * @return void
  */
public function indexAction() {
     $this->view->assign('books', $books);
}
RobertLemke_Example_Bookshop_Html:
  frontend: TYPO3FlowCacheFrontendStringFrontend
  backend: TYPO3FlowCacheBackendFileBackend
/**
  * 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;
}
RobertLemkeExampleBookshopControllerBookController:
  properties:
    htmlCache:
      object:
        factoryObjectName: TYPO3FlowCacheCacheManager
        factoryMethodName: getCache
        arguments:
          1:
             value: 'RobertLemke_Example_Bookshop_Html'
Ask me anything *



                * technical
https://github.com/robertlemke
TYPO3 Flow Trainings and
Inhouse Workshops
Robert Lemke Blog
Robert Lemke_
robertlemke.com
@robertlemke

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

  • 1.
    Robert Lemke_ The RealWorld Beyond the Blog Example
  • 2.
    project founder ofTYPO3 Flow and TYPO3 Neos co-founder of the TYPO3 Association coach, coder, consultant 36 years old TEXT HERE lives in Lübeck, Germany 1 wife, 2 daughters, 1 espresso machine likes drumming
  • 3.
  • 4.
  • 5.
  • 7.
  • 8.
    $context = getenv('FLOW_CONTEXT')?: (getenv('REDIRECT_FLOW_CONTEXT') ?: 'Development'); $bootstrap = new TYPO3FlowCoreBootstrap($context); $bootstrap->run();
  • 9.
    /** * Bootstrapsthe 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(); }
  • 10.
    /** * Handlesa 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(); }
  • 11.
    /** *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(); } } } }
  • 12.
    /** * Bookcontroller 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); } }
  • 13.
    /** *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(); } } } }
  • 14.
    /** * Handlesa 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(); }
  • 15.
    /** * GeneratePdfaction * * @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);
  • 16.
    namespace AcmeDemo; class InvoiceControllerextends 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)); }
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
    Safe Request /method tunneling
  • 22.
    Network Working Group R. Fielding Request for Comments: 2616 UC Irvine Obsoletes: 2068 J. Gettys Category: 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.1 Status 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
  • 23.
    9.1 Safe andIdempotent Methods 9.1.1 Safe Methods Implementors should be aware that the software represents the user in their interactions over the Internet, and should be careful to allow the user to be aware of any actions they might take which may have an unexpected significance to themselves or others. In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested. Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them. 9.1.2 Idempotent Methods
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
    <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"/> ...
  • 29.
  • 30.
  • 31.
    class BookController extendsActionController { /** * @FlowInject * @var BookRepository */ protected $bookRepository; }
  • 32.
    class BookController extendsActionController { … public function myAction() { // $this->bookRepository is instance of Dependency Proxy $this->bookRepository->findAll(); // $this->bookRepository is the real BookRepository } }
  • 33.
    $greet = function($name){ printf("Hello %s", $name); }; $greet('World');
  • 34.
    class BookController extendsBookController_Original implements ProxyInterface { /** * Autogenerated Proxy Method */ public function __construct() { $this->Flow_Proxy_injectProperties(); }
  • 35.
    $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' ); }); }
  • 36.
    class BookController extendsActionController { … public function myAction() { $this->bookRepository->findAll(); } }
  • 37.
    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; }
  • 38.
    Accounts, Users, Authentication Flowdistinguishes between accounts and persons: _ account: TYPO3FlowSecurityAccount _ person: TYPO3PartyDomainModelPerson A person (or machine) can have any number of accounts.
  • 39.
    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
  • 40.
    $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);
  • 41.
  • 42.
    roles: User:[] Manager: ['User'] Editor: ['User', 'TYPO3.Neos:Editor']
  • 45.
    /** * Createa 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; }
  • 46.
  • 47.
    /** * @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; }
  • 48.
  • 49.
    /** *Shows a list of books * * @return void */ public function indexAction() { $this->view->assign('books', $books); }
  • 50.
    RobertLemke_Example_Bookshop_Html: frontend:TYPO3FlowCacheFrontendStringFrontend backend: TYPO3FlowCacheBackendFileBackend
  • 51.
    /** *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; }
  • 52.
    RobertLemkeExampleBookshopControllerBookController: properties: htmlCache: object: factoryObjectName: TYPO3FlowCacheCacheManager factoryMethodName: getCache arguments: 1: value: 'RobertLemke_Example_Bookshop_Html'
  • 53.
    Ask me anything* * technical
  • 54.
  • 55.
    TYPO3 Flow Trainingsand Inhouse Workshops
  • 56.
  • 57.