Bastian Waidelich & Robert Lemke

/**
 * Conference controller for the Acme.Demo package
 *
 * @scope singleton
 */
class ConferenceController extends ActionController {

	    /**
	     * @inject
	     * @var AcmeDemoDomainRepositoryConferenceRepository
	     */
	    protected $conferenceRepository;

	    /**
	      * Shows a list of conferences
	      *
	      * @return void
	      */
	    public function indexAction() {
	    	    $this->view->assign('conferences', $this->conferenceRepository->findAll());
	

	
    FLOW3 Tutorial
     }

     /**
	     * Shows a single conference object
	     *
Hanau, Germany



Robert Lemke

chief "architect" of TYPO3 5.0 and FLOW3

co-founder of the TYPO3 Association

35 years old

lives in Lübeck, Germany

1 wife, 2 daughters, 1 espresso machine

likes drumming
Hanau, Germany



Bastian Waidelich

FLOW3 core team member since 2008

co-creator of Fluid

30 years old

lives in Cologne, Germany

0 wifes, ? daughters, 1 cafetera

likes climbing & guitar playing
Hanau, Germany



This Workshop

Morning
 • Installation

 • Kickstart & Hello World!

 • Commands

 • Depencency Injection

 • Persistence, Doctrine and Domain-Driven Design

 • Modelling of an example App

 • Kickstarting the example App
Hanau, Germany



This Workshop

Afternoon
 • Routing

 • Validation

 • Property Mapper

 • Migrations

 • Security / Login

 • A Glimpse on TYPO3 Phoenix
Hanau, Germany



At a Glance

FLOW3 is a web application framework
 • brings PHP development to a new level



 • made for PHP 5.3, full namespaces support

 • modular, extensible, package based

 • free & Open Source (LGPL v3)

 • backed by one of the largest Open Source projects

   with 6000+ contributors
Hanau, Germany



 Foundation for the Next Generation CMS


TYPO3 5.0 is the all-new
Enterprise CMS
 • content repository, workspaces,
   versions, i18n, ExtJS based UI ...

 • powered by FLOW3

 • compatible code base

 • use TYPO3 features in FLOW3
   standalone apps as you like
Hanau, Germany



Git Clone




$ git clone --recursive git://git.typo3.org/FLOW3/Distributions/Base.git .
Cloning into ....
remote: Counting objects: 3837, done.
remote: Compressing objects: 100% (2023/2023), done.
remote: Total 3837 (delta 2007), reused 2721 (delta 1465)
Receiving objects: 100% (3837/3837), 3.49 MiB | 28 KiB/s, done.
Resolving deltas: 100% (2007/2007), done.
Hanau, Germany



 Set File Permissions

  $ sudo ./flow3 core:setfilepermissions robert _www _www
  FLOW3 File Permission Script

  Checking permissions from here upwards.
  Making sure Data and Web/_Resources exist.
  Setting file permissions, trying to set ACLs via chmod ...
  Done.



Linux:


  $ sudo usermod -a -G www-data robert


Mac OS X:

  $ sudo dscl . -append /Groups/_www GroupMembership robert
Hanau, Germany



Set Up Database Connection
Configuration/Settings.yaml



 #                                                                  #
 # Global Settings                                                  #
 #                                                                  #

 TYPO3:
   FLOW3:
     persistence:
        backendOptions:
          dbname: 'demo'
          user: 'demo'
          password: 'password'
          host: '127.0.0.1'

      # only on Windows:
      core:
        phpBinaryPathAndFilename: 'C:/path/to/php.exe'
Hanau, Germany



Set Up Virtual Host

Apache Virtual Host



  <VirtualHost *:80>
       DocumentRoot /opt/local/apache2/htdocs/Talks/FLOW3/Web/
       ServerName dev.flow3.rob
       SetEnv FLOW3_CONTEXT Development
  </VirtualHost>

  <VirtualHost *:80>
       DocumentRoot /opt/local/apache2/htdocs/Talks/FLOW3/Web/
       ServerName flow3.rob
       SetEnv FLOW3_CONTEXT Production
  </VirtualHost>
Hanau, Germany



Final Check
Hanau, Germany



Update from Git to Latest State


$ git submodule foreach "git checkout master"

-✂-----✂-----✂-----✂-----✂-----✂-----✂-----✂-----✂-----✂-----✂-----✂-

$ git submodule foreach "git pull --rebase"

Entering 'Build/Common'
First, rewinding head to replay your work on top of it...
Fast-forwarded master to 6f27f1784240b414e966ce0e5a12e23cb2f7ab02.
Entering 'Packages/Application/TYPO3'
First, rewinding head to replay your work on top of it...
Fast-forwarded master to 5187430ee44d579ae2bac825e2a069c4cd3Acme8a4.
Entering 'Packages/Application/TYPO3CR'
First, rewinding head to replay your work on top of it...
Fast-forwarded master to b1f5331aa51d390fa3d973404Acme1b9fd773f7059.
Entering 'Packages/Application/Twitter'
Current branch master is up to date.
…
Hanau, Germany



Command Line Use

$ ./flow3 help
FLOW3 1.0.0 ("Development" context)
usage: ./flow3 <command identifier>

The following commands are currently available:

PACKAGE "TYPO3.FLOW3":
-------------------------------------------------------------------------------
* flow3:cache:flush                        Flush all caches
  cache:warmup                             Warm up caches

* flow3:core:setfilepermissions            Adjust file permissions for CLI and
                                           web server access
* flow3:core:shell                         Run the interactive Shell

  doctrine:validate                        Validate the class/table mappings
  doctrine:create                          Create the database schema
  doctrine:update                          Update the database schema
  doctrine:entitystatus                    Show the current status of entities
                                           and mappings
  doctrine:dql                             Run arbitrary DQL and display
                                           results
  doctrine:migrationstatus                 Show the current migration status
  doctrine:migrate                         Migrate the database schema
  doctrine:migrationexecute                Execute a single migration
  doctrine:migrationversion                Mark/unmark a migration as migrated
  doctrine:migrationgenerate               Generate a new migration
Hanau, Germany



Command Line Use

$ ./flow3 help kickstart:package

Kickstart a new package

COMMAND:
  typo3.kickstart:kickstart:package

USAGE:
  ./flow3 kickstart:package <package key>

ARGUMENTS:
  --package-key           The package key, for example "MyCompany.MyPackageName"

DESCRIPTION:
  Creates a new package and creates a standard Action Controller and a sample
  template for its Index Action.

  For creating a new package without sample code use the package:create command.

SEE ALSO:
  typo3.flow3:package:create (Create a new package)
Hanau, Germany



Hello World!




               $ ./flow3 kickstart:package Acme.Demo
H e ll o Wo r ld !

 5         1                1   1
         Ro bert Lem ke
         D.P. F l u x t r
        time ();
Hanau, Germany



Hello World!

StandardController.php

   <?php
   namespace AcmeDemoController;

   use TYPO3FLOW3MVCControllerActionController;

   class StandardController extends ActionController {
   	
   	 /**
   	   * @param string $name
   	   * @return string
   	   */
   	 public function indexAction($name) {
   	 	 return "Hello $name!";
   	 }
   }

   ?>
Hanau, Germany



Tackling the Heart of Software Development

                                         /**
Domain-Driven Design                      * Paper submitted by
                                          *
                                                               a speaker

                                          * @scope prototype
                                          * @entity
A methodology which ...                   */
                                        class Paper {

 • results in rich domain models        	    /**
                                        	     * @var Participant
                                        	     */
 • provides a common language           	    protected $author;

   across the project team          	       /**
                                    	        * @var string
                                    	        */
 • simplify the design of complex   	       protected $title;
   applications                     	       /**
                                    	        * @var string
                                    	        */
                                    	       protected $shortAbstra
                                                                   ct;
FLOW3 is the first PHP framework
                                    	       /**
tailored to Domain-Driven Design    	        * @var string
                                    	        */
                                    	       protected $abstract;
Hanau, Germany



Domain-Driven Design

Domain
 activity or business of the user

Domain-Driven Design
 is about

 • focussing on the domain and domain logic

 • accurately mapping the concepts to software

 • forming a ubiquitous language among the
   project members
Hanau, Germany



Domain-Driven Design

Ubiquitous Language
 • important prerequisite for successful
   collaboration

 • use the same words for

   • discussion

   • modeling

   • development

   • documentation
Hanau, Germany



Domain-Driven Design
Hanau, Germany



Domain: Conference
Hanau, Germany



Domain: Conference
Hanau, Germany



Domain: Conference
Hanau, Germany



Domain: Conference
K ic k s t a rt ing "C o n f e re n c e"

 5          1                1   1
         Ro bert Lem ke
          D.P. F l u x t r
        time ();
Hanau, Germany



Domain: Conference
Hanau, Germany



Object Management

Dependency Injection
 • a class doesn't create or retrieve the instance
   of another class but get's it injected

 • fosters loosely-coupling and high cohesion

 ‣ more stable, reusable code
Hanau, Germany



Object Management

FLOW3's take on Dependency Injection
 • one of the first PHP implementations
   (started in 2006, improved ever since)

 • object management for the whole lifecycle of all objects

 • no unnecessary configuration if information can be
   gatered automatically (autowiring)

 • intuitive use and no bad magical surprises

 • fast! (like hardcoded or faster)
Hanau, Germany

                                                                             War
Constructor Injection: Symfony 2                                                 nin
                                                                                     g
                                                                                  (I'm
                                                                                         :m
                                                                                               igh
                                                                                         no           t co
                                                                                              Sym
                                                                                                  f          nta
                                                                                                   ony
                                                                                                         exp     in     erro
    <?php                                                                                                    ert ..
                                                                                                                   .)       rs
namespace AcmeDemoBundleController;

use   SymfonyBundleFrameworkBundleControllerController;
use   SymfonyComponentHttpFoundationRedirectResponse;
use   SensioBundleFrameworkExtraBundleConfigurationRoute;
use   SensioBundleFrameworkExtraBundleConfigurationTemplate;
use   AcmeDemoBundleGreeterService;

class DemoController extends Controller {
	
	   /**
	    * @var AcmeDemoBundleGreeterService
	    */
	   protected $greeterService;

	     /**
	       * @param AcmeDemoBundleGreeterService
	       */
	     public function __construct($greeterService = NULL) {
	     	    $this->greeterService = $greeterService;
	     }
	
    /**
      * @Route("/hello/{name}", name="_demo_hello")
      */
    public function helloAction($name) {
    	    return new Response('Hello ' . $this->greeterService->greet($name), 200, array('Content-
Type' => 'text/plain'));
    }
Hanau, Germany

                                                                               War
  Constructor Injection: Symfony 2                                                 nin
                                                                                       g
                                                                                    (I'm
                                                                                           :m
                                                                                                 igh
                                                                                           no           t co
                                                                                                Sym
                                                                                                    f          nta
                                                                                                     ony
                                                                                                           exp     in     erro
                                                                                                               ert ..
                                                                                                                     .)       rs




   <?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 http://symfony.com/schema/dic/services/
services-1.0.xsd">

    <services>
        <service id="acme.demo.greeterservice" class="AcmeDemoBundleGreeterService" public="false" />
        <service id="acme.demo.democontroller" class="AcmeDemoBundleControllerDemoController">
             <argument type="service" id="acme.demo.greeterservice" />
        </service>
    </services>
</container>
Hanau, Germany



Constructor Injection

    <?php
namespace F3DemoController;

use F3FLOW3MVCControllerActionController;
use F3DemoServiceGreeterService;

class DemoController extends ActionController {
	
	   /**
	    * @var F3DemoServiceGreeterService
	    */
	   protected $greeterService;

	   /**
	     * @param F3DemoServiceGreeterService
	     */
	   public function __construct(F3DemoServiceGreeterService $greeterService) {
	   	    $this->greeterService = $greeterService;
	   }
	
    /**
      * @param string $name
      */
    public function helloAction($name) {
    	
    	     return 'Hello ' . $name;
    }
}
Hanau, Germany



Constructor Injection
Hanau, Germany



Setter Injection

<?php
namespace F3DemoController;

use F3FLOW3MVCControllerActionController;
use F3DemoServiceGreeterService;

class DemoController extends ActionController {
	
	   /**
	    * @var F3DemoServiceGreeterService
	    */
	   protected $greeterService;

	   /**
	     * @param F3DemoServiceGreeterService
	     */
	   public function injectGreeterService(F3DemoServiceGreeterService $greeterService) {
	   	    $this->greeterService = $greeterService;
	   }
	
    /**
      * @param string $name
      */
    public function helloAction($name) {
    	    	   return 'Hello ' . $name;
    }
}
Hanau, Germany



Property Injection

<?php
namespace F3DemoController;

use F3FLOW3MVCControllerActionController;
use F3DemoServiceGreeterService;

class DemoController extends ActionController {
	
	   /**
	     * @var F3DemoServiceGreeterService
	     * @inject
	     */
	   protected $greeterService;
	
    /**
      * @param string $name
      */
    public function helloAction($name) {
    	
    	     return 'Hello ' . $name;
    }
}
Hanau, Germany



Objects.yaml


   F3FLOW3SecurityCryptographyRsaWalletServiceInterface:
     className: F3FLOW3SecurityCryptographyRsaWalletServicePhp
     scope: singleton
     properties:
       keystoreCache:
         object:
           factoryObjectName: F3FLOW3CacheCacheManager
           factoryMethodName: getCache
           arguments:
             1:
                value: FLOW3_Security_Cryptography_RSAWallet
Hanau, Germany



Object Management

    class Customer {

	   /**
	    * @inject
	    * @var CustomerNumberGenerator
	    */
	   protected $customerNumberGenerator;

	   ...
}

$customer = new Customer();
$customer->getCustomerNumber();
Hanau, Germany



Object Management
                                     <?php
                                     declare(ENCODING = 'u
                                                           tf-8');
                                     namespace F3Confere
                                                          nceDomain   ModelConference;
                                    /**
FLOW3 creates proxy classes          * Autogenerated Prox
                                                           y Class
for realizing DI and AOP magic       * @scope prototype
                                     * @entity
                                     */
                                   class Paper extends
 • new operator is supported       F3FLOW3Persistenc
                                                         Paper_Original implem
                                                         eAspectPersistence
                                                                               ents F3FLOW3Object
                                                                              MagicInterface {
                                                                                                     Pr

                                   	     /**
 • proxy classes are created      	
                                   	      * @var string
                                          * @Id
   on the fly                      	
                                  	
                                          * @Column(length="40
                                                               ")
                                          * introduced by F3F
                                                               LOW3PersistenceAsp
                                  	       */                                        ectPersistenceMagic

 • in production context all      	     protected $FLOW3_Per
                                                             sistence_Identifier
                                                                                  = NULL;

   code is static                	      private $FLOW3_AOP_P
                                                             roxy_targetMethodsAn
                                                                                  dGroupedAdvices = ar
                                                                                                       ra
                                 	     private $FLOW3_AOP_P
                                                             roxy_groupedAdviceCh
                                                                                  ains = array();
                                 	     private $FLOW3_AOP_P
                                                            roxy_methodIsInAdvic
                                                                                 eMode = array();

                                 	    /**
                                 	     * Autogenerated Prox
                                                            y Method
                                 	     */
                                 	    public function __co
                                                           nstruct()    {
Hanau, Germany



Your Own Commands




      $ ./flow3 kickstart:commandcontroller Acme.Demo Test
Hanau, Germany



Validation

Validation is about different things

• incoming data needs to be validated for security reasons

 • no evil markup in submitted content

• domain model integrity needs to be ensured

 • an email needs to be (syntactically) valid

 • credit card numbers should consist only of digits
Hanau, Germany



Validation

Validation in FLOW3

• you do not want to code checks into your controllers

• FLOW3 separates validation from your controller’s concerns

 • no PHP code needed for validation

 • declared through annotations
Hanau, Germany



Validation

Validation Models

• BaseProperties
  rules defining the minimum requirements on individual properties of a
  model

• BaseModel
  rules or custom validators enforcing the minimum requirements on the
  combination of properties of a model

• Supplemental
  rules defining additional requirements on a model for a specific
  situation (e.g. a certain action method)
Hanau, Germany



Validation

Base Properties

• Validation rules defined directly at the properties


  	   /**
  	    * @var string
  	    * @validate StringLength(minimum = 10, maximum = 100)
  	    */
  	   protected $title;

  	   /**
  	    * @var string
  	    * @validate StringLength(minimum = 1, maximum = 50)
  	    */
  	   protected $author;
Hanau, Germany



Validation

Validators

• validators provided by FLOW3 can be used through their short name

 • Count, Float, NotEmpty, RegularExpression, Uuid, DateTime,
   NumberRange, StringLength, Alphanumeric, Integer, Number, String,
   EmailAddress, Label, Raw, Text

• custom validators need to implement the ValidatorInterface

• use them by specifying the fully qualified class name
 	   /**
 	    * @var DambekalnsStuffDomainModelStuff
 	    * @validate DambekalnsStuffDomainValidatorStuffValidator
 	    */
 	   protected $stuff;
Hanau, Germany



Property Mapper

Transfer properties from A to B
 • Allows for complete or partial copying of objects and object
   graphs

 • Is used by the MVC framework for the mapping of raw GET and
   POST data to Argument objects
Hanau, Germany



    Property Mapper




	   $articleArray = array(
	   	 'headline' => 'Hello World!',
	   	 'story' => 'Just a demo ...'
	   );

	   $article = $mapper->convert($sourceArray, 'Acme.DemoDomainModelArticle');
Hanau, Germany



 Resource Management

 Image Upload
 Resources are handled like other properties in a form:



	 <f:form method="blog" action="update" object="{blog}" name="blog"
enctype="multipart/form-data">
	 	 <f:if condition="{blog.authorPicture}">
	 	 	 <img src="{f:uri.resource(resource: blog.authorPicture)}" />
	 	 </f:if>
	 	 <label for="authorPicture">Author picture</label>
	 	 <f:form.upload property="authorPicture" id="authorPicture" />
	 	 <f:form.submit value="Update"/>
	 </f:form>
Hanau, Germany



    Property Mapper

    Allow nested object structures
    For security reasons the creation of nested structure through the
    property mapper is disabled by default

	   /**
	     * @return void
	     */
	   public function initializeUpdateAction() {
	   	 $this->arguments['article']->getPropertyMappingConfiguration()
            ->allowCreationForSubProperty('picture');
	   	 $this->arguments['article']->getPropertyMappingConfiguration()
            ->allowModificationForSubProperty('picture');
	   }
Hanau, Germany



Persistence

Object Persistence in the Flow
 • based on Doctrine 2

 • seamless integration into FLOW3

 • provides all the great Doctrine 2 features

 • uses UUIDs

 • low level persistence API

   • allows for own, custom persistence
     backends (instead of Doctrine 2)

   • e.g. CouchDB, Solr
Hanau, Germany



    Basic Object Persistence




	   	 // Create a new customer and persist it:
	   $customer = new Customer("Robert");
	   $this->customerRepository->add($customer);

	   	 // Find an existing customer:
	   $otherCustomer = $this->customerRepository->findByFirstName("Karsten");
	
	   	 // and delete it:
	   $this->customerRepository->remove($otherCustomer);
Hanau, Germany



    Validation and Doctrine Annotations

namespace TYPO3BlogDomainModel;

/**
 * A Blog object
 *
 * @Entity
 */
class Blog {

    /**
     * @var string
     * @validate Text, StringLength(minimum = 1, maximum = 80)
     * @Column(length="80")
     */
    protected $title;

    /**
     * @var DoctrineCommonCollectionsCollection<TYPO3BlogDomainModelPost>
     * @OneToMany(mappedBy="blog")
     * @OrderBy({"date" = "DESC"})
     */
    protected $posts;

    ...

}
Hanau, Germany



Persistence-related Annotations


@Entity        Declares a class as "entity"

@Column        Controls the database column related to the class
               property. Very useful for longer text content
               (type="text" !)

@ManyToOne     Defines relations to other entities. Unlike with
@OneToMany     vanilla Doctrine targetEntity does not have to be
@ManyToMany    given but will be reused from the @var
@OneToOne      annotation.

               cascade can be used to cascade operation to
               related objects.
Hanau, Germany



Persistence-related Annotations




@var           Defines the type of a property, collections can be
               typed using angle brackets:
               DoctrineCommonCollectionsCollection<TYPO3ConferenceDomainModelComment>


@transient     The property will be ignored, it will neither be
               persisted nor reconstituted

@identity      Marks the property as part of an objects identity
Hanau, Germany



    Custom Queries using the Query Object Model
/**
 * A PostRepository
 */
class PostRepository extends TYPO3FLOW3PersistenceRepository {

    /**
      * Finds posts by the specified tag and blog
      *
      * @param TYPO3BlogDomainModelTag $tag
      * @param TYPO3BlogDomainModelBlog $blog The blog the post must refer to
      * @return TYPO3FLOW3PersistenceQueryResultInterface The posts
      */
    public function findByTagAndBlog(TYPO3BlogDomainModelTag $tag,
        TYPO3BlogDomainModelBlog $blog) {
          $query = $this->createQuery();
          return $query->matching(
              $query->logicalAnd(
                  $query->equals('blog', $blog),
                  $query->contains('tags', $tag)
              )
          )
          ->setOrderings(array(
              'date' => TYPO3FLOW3PersistenceQueryInterface::ORDER_DESCENDING)
          )
          ->execute();
    }
}
Hanau, Germany



Schema Management

Doctrine 2 Migrations
• Migrations allow schema versioning and
  change deployment

• Migrations are the recommended way for
  DB updates

• Tools to create and deploy migrations are
  integrated with FLOW3
Hanau, Germany



Schema Management

Running Migrations
• needed after installation or upgrade:


$ ./flow3 doctrine:migrate
Hanau, Germany



Schema Management

Manual database updates
• for simple situations this can be good enough:


$ ./flow3 doctrine:create

$ ./flow3 doctrine:update




• useful when

 • you are just starting a project and have never released
Hanau, Germany



Schema Management

Generating migrations

$ ./flow3 doctrine:migrationgenerate
Generated new migration class to "…/Version20110608074324.php"
from schema differences.
$




• Generated migrations can contain errors and should be checked
  and adjusted as needed

• Migrations need to be moved to their “owning” package manually
M ig rat io n s

 5        8                1   1
        Ro bert Lem ke
        D.P. F l u x t r
       time ();
Hanau, Germany



Fluid


Example for assigning a string to a Fluid variable:

	   	 // in the action controller:
	   $this->view->assign('title', 'Welcome to Fluid');




	   <!-- in the Fluid template: -->
	   <head>
	   	 <title>{title}</title>
	   </head>
Hanau, Germany



Fluid


Variables can also be objects:

	   	 // in the action controller:
	   $this->view->assign('conference', $conference);




	   <!-- in the Fluid template: -->
	   <div class="venue">
	   	 <p>Venue Street: {conference.venue.street}</p>
	   </div>
Hanau, Germany



Fluid


if-then-else:

	   	 // in the action controller:
	   $this->view->assign('post', $blogPost);




	   <!-- in the Fluid template: -->
	   <f:if condition="{post.comments}">
	   	 <f:then>There are some comments.</f:then>
	   	 <f:else>There are no comments.</f:else>		
	   </f:if>
Hanau, Germany



Fluid


for-each:

	   	 // in the action controller:
	   $this->view->assign('ages', array("Karsten" => 34, "Robert" => 35));




	   <!-- in the Fluid template: -->
	   <ul>
	   	 <f:for each="{ages}" as="age" key="name">
	   	 	 <li>{name} is {age} year old.</li>
	   	 </f:for>
	   </ul>
Hanau, Germany



Fluid


for-each:

	   	 // in the action controller:
	   $this->view->assign('post', $blogPost);




	   <!-- in the Fluid template: -->
	   <f:if condition="{post.comments}">
	   	 <ul>
	   	 	 <f:for each="{post.comments}" as="comment" >
	   	 	 	 <li>{post.title}</li>
	   	 	 </f:for>
	   	 </ul>	 	 	
	   </f:if>
Hanau, Germany



Fluid


View helpers – in this case the link.action view helper:


	   <!-- in the Fluid template: -->
	   {namespace f=F3FluidViewHelpers}

	   <f:link.action action="delete" arguments="{post: post, really: 'yes'}">
	   	 Delete this post
	   </f:link.action>
F lue n t F lu id

 5         8                1   1
         K. Damb ek aln s & R. Lem ke
         D.P. F l u x t r
        time ();
Hanau, Germany



Security

Touchless Security, Flow-Style
 • security is handled at a central place (through AOP)

 • third-party code is as secure as possible by default

 • modeled after our experiences in the TYPO3 project and
   Spring Security (Java framework)

 • provides authentication, authorization, validation, filtering ...

   • can intercept arbitrary method calls

   • transparently filters content through query-rewriting

 • extensible for new authentication or authorization mechanisms
Hanau, Germany



Security Policy
Us e rs a n d L o g in

 5         8                1   1
        K. Damb ek aln s & R. Lem ke
         D.P. F l u x t r
        time ();
Hanau, Germany



AOP

Aspect-Oriented Programming
 • programming paradigm

 • separates concerns to improve modularization

 • OOP modularizes concerns into objects

 • AOP modularizes cross-cutting concerns into aspects



 • FLOW3 makes it easy (and possible at all) to use AOP in PHP
Hanau, Germany



AOP
                                 /**
                                  * @aspect
FLOW3 uses AOP for ...            * @introduce
                                  */
                                                  F3FLOW3Pers
                                                                istenceAspec
                                                                              tPersistence
                                class Persist                                               MagicInterfac
                                                enceMagicAspe                                              e, F3FLO
                                                              ct {
 • persistence magic           	
                               	
                                       /**
                                        * @pointcut c
                                                      lassTaggedWit
                               	        */                          h(entity) ||
                                                                                  classTaggedWi
                              	                                                                 th(valueobjec
 • logging                            public functi
                                                     on isEntityOr
                                                                   ValueObject()
                                                                                  {}
                                                                                                               t)

                              	       /**
                             	         * @var string

 • debugging                 	
                             	
                                       * @Id
                                       * @Column(len
                                                     gth="40")
                             	        * @introduce
                                                     F3FLOW3Pers
                            	         */                           istenceAspec
                                                                                 tPersistence
 • security                 	       protected $FL
                                                   OW3_Persisten
                                                                 ce_Identifier
                                                                               ;
                                                                                               MagicAspect->
                                                                                                              isEnti

                           	        /**
                           	         * After retur
                                                    ning advice,
                           	         *                            making sure w
                                                                                e have an UUI
                           	         * @param F3                                            D for each an
                                                    FLOW3AOPJoi                                            d every
                          	         * @return voi                 nPointInterfa
                                                   d                            ce $joinPoint
                          	         * @before cla                                              The current j
                                                   ssTaggedWith(                                              oin po
                          	         */                           entity) && me
                                                                               thod(.*->__co
                         	        public functi                                              nstruct())
                                                  on generateUU
                         	        	      $proxy = $joi          ID(F3FLOW3
                                                       nPoint->getPr          AOPJoinPoint
                         	       	                                   oxy();                 Interface $jo
                                         F3FLOW3Ref                                                     inPoint)
                         	                             lectionObjec
                                 }                                   tAccess::setP
                                                                                   roperty($prox
                                                                                                 y , 'FLOW3_Per
                                                                                                                siste
Th e Wiz a rd o f AOP

 5       8                1   1
      K. Damb ek aln s & R. Lem ke
       D.P. F l u x t r
      time ();
Hanau, Germany



Signal-Slot Event Handling

Signal

  • can be fired on any event

  • can be freely defined by the developer

Slot

  • is invoked when a signal is emitted

  • any method can be used as a slot



any signal can be wired to any slot
Hanau, Germany



Signal-Slot Event Handling

   /**
     * @param F3BlogDomainModelPost $post
     * @param F3BlogDomainModelComment $newComment
     * @return void
     */
   public function createAction(F3BlogDomainModelPost $post,
           F3BlogDomainModelComment $newComment) {
        $post->addComment($newComment);
        $this->emitCommentCreated($newComment, $post);
        …
   }




   /**
    * @param F3BlogDomainModelComment $comment
    * @param F3BlogDomainModelPost $post
    * @return void
    * @signal
    */
   protected function emitCommentCreated(F3BlogDomainModelComment $comment,
       F3BlogDomainModelPost $post) {}
Hanau, Germany



Signal-Slot Event Handling

Signals are wired to Slots in a package’s bootstrap:


 /**
   * Invokes custom PHP code directly after the package manager has been
   * initialized.
   *
   * @param F3FLOW3CoreBootstrap $bootstrap The current bootstrap
   * @return void
   */
 public function boot(F3FLOW3CoreBootstrap $bootstrap) {
      $dispatcher = $bootstrap->getSignalSlotDispatcher();
      $dispatcher->connect(
          'F3BlogControllerCommentController', 'commentCreated',
          'F3BlogServiceNotification', 'sendNewCommentNotification'
      );
 }
Hanau, Germany



Signal-Slot Event Handling

Any method can be a slot:

  /**
   * @param F3BlogDomainModelComment $comment
   * @param F3BlogDomainModelPost $post
   * @return void
   */
  public function sendNewCommentNotification(F3BlogDomainModelComment $comment,
         F3BlogDomainModelPost $post) {

      $mail = new F3SwiftMailerMessage();
      $mail
          ->setFrom(array('john@doe.org ' => 'John Doe'))
          ->setTo(array('karsten@typo3.org ' => 'Karsten Dambekalns'))
          ->setSubject('New comment on blog post "' . $post->getTitle() . '"')
          ->setBody($comment->getContent())
          ->send();
  }
Hanau, Germany



Roadmap

http://forge.typo3.org/projects/flow3-distribution-base/roadmap
Hanau, Germany



Conference App

git://git.typo3.org/TYPO3v5/Distributions/Conference.git
Hanau, Germany



Blog App

git://git.typo3.org/FLOW3/Applications/Blog.git
Hanau, Germany



Thank You & Have Fun!

 • FLOW3: http://flow3.typo3.org

 • Blog: http://robertlemke.de/blog

 • Twitter: @robertlemke / @mrbasti

 • Feedback: robert@typo3.org / bastian@typo3.org

FLOW3 Tutorial - T3CON11 Frankfurt

  • 1.
    Bastian Waidelich &Robert Lemke /** * Conference controller for the Acme.Demo package * * @scope singleton */ class ConferenceController extends ActionController { /** * @inject * @var AcmeDemoDomainRepositoryConferenceRepository */ protected $conferenceRepository; /** * Shows a list of conferences * * @return void */ public function indexAction() { $this->view->assign('conferences', $this->conferenceRepository->findAll()); FLOW3 Tutorial } /** * Shows a single conference object *
  • 2.
    Hanau, Germany Robert Lemke chief"architect" of TYPO3 5.0 and FLOW3 co-founder of the TYPO3 Association 35 years old lives in Lübeck, Germany 1 wife, 2 daughters, 1 espresso machine likes drumming
  • 3.
    Hanau, Germany Bastian Waidelich FLOW3core team member since 2008 co-creator of Fluid 30 years old lives in Cologne, Germany 0 wifes, ? daughters, 1 cafetera likes climbing & guitar playing
  • 4.
    Hanau, Germany This Workshop Morning • Installation • Kickstart & Hello World! • Commands • Depencency Injection • Persistence, Doctrine and Domain-Driven Design • Modelling of an example App • Kickstarting the example App
  • 5.
    Hanau, Germany This Workshop Afternoon • Routing • Validation • Property Mapper • Migrations • Security / Login • A Glimpse on TYPO3 Phoenix
  • 6.
    Hanau, Germany At aGlance FLOW3 is a web application framework • brings PHP development to a new level • made for PHP 5.3, full namespaces support • modular, extensible, package based • free & Open Source (LGPL v3) • backed by one of the largest Open Source projects with 6000+ contributors
  • 7.
    Hanau, Germany Foundationfor the Next Generation CMS TYPO3 5.0 is the all-new Enterprise CMS • content repository, workspaces, versions, i18n, ExtJS based UI ... • powered by FLOW3 • compatible code base • use TYPO3 features in FLOW3 standalone apps as you like
  • 8.
    Hanau, Germany Git Clone $git clone --recursive git://git.typo3.org/FLOW3/Distributions/Base.git . Cloning into .... remote: Counting objects: 3837, done. remote: Compressing objects: 100% (2023/2023), done. remote: Total 3837 (delta 2007), reused 2721 (delta 1465) Receiving objects: 100% (3837/3837), 3.49 MiB | 28 KiB/s, done. Resolving deltas: 100% (2007/2007), done.
  • 9.
    Hanau, Germany SetFile Permissions $ sudo ./flow3 core:setfilepermissions robert _www _www FLOW3 File Permission Script Checking permissions from here upwards. Making sure Data and Web/_Resources exist. Setting file permissions, trying to set ACLs via chmod ... Done. Linux: $ sudo usermod -a -G www-data robert Mac OS X: $ sudo dscl . -append /Groups/_www GroupMembership robert
  • 10.
    Hanau, Germany Set UpDatabase Connection Configuration/Settings.yaml # # # Global Settings # # # TYPO3: FLOW3: persistence: backendOptions: dbname: 'demo' user: 'demo' password: 'password' host: '127.0.0.1' # only on Windows: core: phpBinaryPathAndFilename: 'C:/path/to/php.exe'
  • 11.
    Hanau, Germany Set UpVirtual Host Apache Virtual Host <VirtualHost *:80> DocumentRoot /opt/local/apache2/htdocs/Talks/FLOW3/Web/ ServerName dev.flow3.rob SetEnv FLOW3_CONTEXT Development </VirtualHost> <VirtualHost *:80> DocumentRoot /opt/local/apache2/htdocs/Talks/FLOW3/Web/ ServerName flow3.rob SetEnv FLOW3_CONTEXT Production </VirtualHost>
  • 12.
  • 13.
    Hanau, Germany Update fromGit to Latest State $ git submodule foreach "git checkout master" -✂-----✂-----✂-----✂-----✂-----✂-----✂-----✂-----✂-----✂-----✂-----✂- $ git submodule foreach "git pull --rebase" Entering 'Build/Common' First, rewinding head to replay your work on top of it... Fast-forwarded master to 6f27f1784240b414e966ce0e5a12e23cb2f7ab02. Entering 'Packages/Application/TYPO3' First, rewinding head to replay your work on top of it... Fast-forwarded master to 5187430ee44d579ae2bac825e2a069c4cd3Acme8a4. Entering 'Packages/Application/TYPO3CR' First, rewinding head to replay your work on top of it... Fast-forwarded master to b1f5331aa51d390fa3d973404Acme1b9fd773f7059. Entering 'Packages/Application/Twitter' Current branch master is up to date. …
  • 14.
    Hanau, Germany Command LineUse $ ./flow3 help FLOW3 1.0.0 ("Development" context) usage: ./flow3 <command identifier> The following commands are currently available: PACKAGE "TYPO3.FLOW3": ------------------------------------------------------------------------------- * flow3:cache:flush Flush all caches cache:warmup Warm up caches * flow3:core:setfilepermissions Adjust file permissions for CLI and web server access * flow3:core:shell Run the interactive Shell doctrine:validate Validate the class/table mappings doctrine:create Create the database schema doctrine:update Update the database schema doctrine:entitystatus Show the current status of entities and mappings doctrine:dql Run arbitrary DQL and display results doctrine:migrationstatus Show the current migration status doctrine:migrate Migrate the database schema doctrine:migrationexecute Execute a single migration doctrine:migrationversion Mark/unmark a migration as migrated doctrine:migrationgenerate Generate a new migration
  • 15.
    Hanau, Germany Command LineUse $ ./flow3 help kickstart:package Kickstart a new package COMMAND: typo3.kickstart:kickstart:package USAGE: ./flow3 kickstart:package <package key> ARGUMENTS: --package-key The package key, for example "MyCompany.MyPackageName" DESCRIPTION: Creates a new package and creates a standard Action Controller and a sample template for its Index Action. For creating a new package without sample code use the package:create command. SEE ALSO: typo3.flow3:package:create (Create a new package)
  • 16.
    Hanau, Germany Hello World! $ ./flow3 kickstart:package Acme.Demo
  • 17.
    H e llo Wo r ld ! 5 1 1 1 Ro bert Lem ke D.P. F l u x t r time ();
  • 18.
    Hanau, Germany Hello World! StandardController.php <?php namespace AcmeDemoController; use TYPO3FLOW3MVCControllerActionController; class StandardController extends ActionController { /** * @param string $name * @return string */ public function indexAction($name) { return "Hello $name!"; } } ?>
  • 19.
    Hanau, Germany Tackling theHeart of Software Development /** Domain-Driven Design * Paper submitted by * a speaker * @scope prototype * @entity A methodology which ... */ class Paper { • results in rich domain models /** * @var Participant */ • provides a common language protected $author; across the project team /** * @var string */ • simplify the design of complex protected $title; applications /** * @var string */ protected $shortAbstra ct; FLOW3 is the first PHP framework /** tailored to Domain-Driven Design * @var string */ protected $abstract;
  • 20.
    Hanau, Germany Domain-Driven Design Domain activity or business of the user Domain-Driven Design is about • focussing on the domain and domain logic • accurately mapping the concepts to software • forming a ubiquitous language among the project members
  • 21.
    Hanau, Germany Domain-Driven Design UbiquitousLanguage • important prerequisite for successful collaboration • use the same words for • discussion • modeling • development • documentation
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
    K ic ks t a rt ing "C o n f e re n c e" 5 1 1 1 Ro bert Lem ke D.P. F l u x t r time ();
  • 28.
  • 29.
    Hanau, Germany Object Management DependencyInjection • a class doesn't create or retrieve the instance of another class but get's it injected • fosters loosely-coupling and high cohesion ‣ more stable, reusable code
  • 30.
    Hanau, Germany Object Management FLOW3'stake on Dependency Injection • one of the first PHP implementations (started in 2006, improved ever since) • object management for the whole lifecycle of all objects • no unnecessary configuration if information can be gatered automatically (autowiring) • intuitive use and no bad magical surprises • fast! (like hardcoded or faster)
  • 31.
    Hanau, Germany War Constructor Injection: Symfony 2 nin g (I'm :m igh no t co Sym f nta ony exp in erro <?php ert .. .) rs namespace AcmeDemoBundleController; use SymfonyBundleFrameworkBundleControllerController; use SymfonyComponentHttpFoundationRedirectResponse; use SensioBundleFrameworkExtraBundleConfigurationRoute; use SensioBundleFrameworkExtraBundleConfigurationTemplate; use AcmeDemoBundleGreeterService; class DemoController extends Controller { /** * @var AcmeDemoBundleGreeterService */ protected $greeterService; /** * @param AcmeDemoBundleGreeterService */ public function __construct($greeterService = NULL) { $this->greeterService = $greeterService; } /** * @Route("/hello/{name}", name="_demo_hello") */ public function helloAction($name) { return new Response('Hello ' . $this->greeterService->greet($name), 200, array('Content- Type' => 'text/plain')); }
  • 32.
    Hanau, Germany War Constructor Injection: Symfony 2 nin g (I'm :m igh no t co Sym f nta ony exp in erro ert .. .) rs <?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 http://symfony.com/schema/dic/services/ services-1.0.xsd"> <services> <service id="acme.demo.greeterservice" class="AcmeDemoBundleGreeterService" public="false" /> <service id="acme.demo.democontroller" class="AcmeDemoBundleControllerDemoController"> <argument type="service" id="acme.demo.greeterservice" /> </service> </services> </container>
  • 33.
    Hanau, Germany Constructor Injection <?php namespace F3DemoController; use F3FLOW3MVCControllerActionController; use F3DemoServiceGreeterService; class DemoController extends ActionController { /** * @var F3DemoServiceGreeterService */ protected $greeterService; /** * @param F3DemoServiceGreeterService */ public function __construct(F3DemoServiceGreeterService $greeterService) { $this->greeterService = $greeterService; } /** * @param string $name */ public function helloAction($name) { return 'Hello ' . $name; } }
  • 34.
  • 35.
    Hanau, Germany Setter Injection <?php namespaceF3DemoController; use F3FLOW3MVCControllerActionController; use F3DemoServiceGreeterService; class DemoController extends ActionController { /** * @var F3DemoServiceGreeterService */ protected $greeterService; /** * @param F3DemoServiceGreeterService */ public function injectGreeterService(F3DemoServiceGreeterService $greeterService) { $this->greeterService = $greeterService; } /** * @param string $name */ public function helloAction($name) { return 'Hello ' . $name; } }
  • 36.
    Hanau, Germany Property Injection <?php namespaceF3DemoController; use F3FLOW3MVCControllerActionController; use F3DemoServiceGreeterService; class DemoController extends ActionController { /** * @var F3DemoServiceGreeterService * @inject */ protected $greeterService; /** * @param string $name */ public function helloAction($name) { return 'Hello ' . $name; } }
  • 37.
    Hanau, Germany Objects.yaml F3FLOW3SecurityCryptographyRsaWalletServiceInterface: className: F3FLOW3SecurityCryptographyRsaWalletServicePhp scope: singleton properties: keystoreCache: object: factoryObjectName: F3FLOW3CacheCacheManager factoryMethodName: getCache arguments: 1: value: FLOW3_Security_Cryptography_RSAWallet
  • 38.
    Hanau, Germany Object Management class Customer { /** * @inject * @var CustomerNumberGenerator */ protected $customerNumberGenerator; ... } $customer = new Customer(); $customer->getCustomerNumber();
  • 39.
    Hanau, Germany Object Management <?php declare(ENCODING = 'u tf-8'); namespace F3Confere nceDomain ModelConference; /** FLOW3 creates proxy classes * Autogenerated Prox y Class for realizing DI and AOP magic * @scope prototype * @entity */ class Paper extends • new operator is supported F3FLOW3Persistenc Paper_Original implem eAspectPersistence ents F3FLOW3Object MagicInterface { Pr /** • proxy classes are created * @var string * @Id on the fly * @Column(length="40 ") * introduced by F3F LOW3PersistenceAsp */ ectPersistenceMagic • in production context all protected $FLOW3_Per sistence_Identifier = NULL; code is static private $FLOW3_AOP_P roxy_targetMethodsAn dGroupedAdvices = ar ra private $FLOW3_AOP_P roxy_groupedAdviceCh ains = array(); private $FLOW3_AOP_P roxy_methodIsInAdvic eMode = array(); /** * Autogenerated Prox y Method */ public function __co nstruct() {
  • 40.
    Hanau, Germany Your OwnCommands $ ./flow3 kickstart:commandcontroller Acme.Demo Test
  • 41.
    Hanau, Germany Validation Validation isabout different things • incoming data needs to be validated for security reasons • no evil markup in submitted content • domain model integrity needs to be ensured • an email needs to be (syntactically) valid • credit card numbers should consist only of digits
  • 42.
    Hanau, Germany Validation Validation inFLOW3 • you do not want to code checks into your controllers • FLOW3 separates validation from your controller’s concerns • no PHP code needed for validation • declared through annotations
  • 43.
    Hanau, Germany Validation Validation Models •BaseProperties rules defining the minimum requirements on individual properties of a model • BaseModel rules or custom validators enforcing the minimum requirements on the combination of properties of a model • Supplemental rules defining additional requirements on a model for a specific situation (e.g. a certain action method)
  • 44.
    Hanau, Germany Validation Base Properties •Validation rules defined directly at the properties /** * @var string * @validate StringLength(minimum = 10, maximum = 100) */ protected $title; /** * @var string * @validate StringLength(minimum = 1, maximum = 50) */ protected $author;
  • 45.
    Hanau, Germany Validation Validators • validatorsprovided by FLOW3 can be used through their short name • Count, Float, NotEmpty, RegularExpression, Uuid, DateTime, NumberRange, StringLength, Alphanumeric, Integer, Number, String, EmailAddress, Label, Raw, Text • custom validators need to implement the ValidatorInterface • use them by specifying the fully qualified class name /** * @var DambekalnsStuffDomainModelStuff * @validate DambekalnsStuffDomainValidatorStuffValidator */ protected $stuff;
  • 46.
    Hanau, Germany Property Mapper Transferproperties from A to B • Allows for complete or partial copying of objects and object graphs • Is used by the MVC framework for the mapping of raw GET and POST data to Argument objects
  • 47.
    Hanau, Germany Property Mapper $articleArray = array( 'headline' => 'Hello World!', 'story' => 'Just a demo ...' ); $article = $mapper->convert($sourceArray, 'Acme.DemoDomainModelArticle');
  • 48.
    Hanau, Germany ResourceManagement Image Upload Resources are handled like other properties in a form: <f:form method="blog" action="update" object="{blog}" name="blog" enctype="multipart/form-data"> <f:if condition="{blog.authorPicture}"> <img src="{f:uri.resource(resource: blog.authorPicture)}" /> </f:if> <label for="authorPicture">Author picture</label> <f:form.upload property="authorPicture" id="authorPicture" /> <f:form.submit value="Update"/> </f:form>
  • 49.
    Hanau, Germany Property Mapper Allow nested object structures For security reasons the creation of nested structure through the property mapper is disabled by default /** * @return void */ public function initializeUpdateAction() { $this->arguments['article']->getPropertyMappingConfiguration() ->allowCreationForSubProperty('picture'); $this->arguments['article']->getPropertyMappingConfiguration() ->allowModificationForSubProperty('picture'); }
  • 50.
    Hanau, Germany Persistence Object Persistencein the Flow • based on Doctrine 2 • seamless integration into FLOW3 • provides all the great Doctrine 2 features • uses UUIDs • low level persistence API • allows for own, custom persistence backends (instead of Doctrine 2) • e.g. CouchDB, Solr
  • 51.
    Hanau, Germany Basic Object Persistence // Create a new customer and persist it: $customer = new Customer("Robert"); $this->customerRepository->add($customer); // Find an existing customer: $otherCustomer = $this->customerRepository->findByFirstName("Karsten"); // and delete it: $this->customerRepository->remove($otherCustomer);
  • 52.
    Hanau, Germany Validation and Doctrine Annotations namespace TYPO3BlogDomainModel; /** * A Blog object * * @Entity */ class Blog { /** * @var string * @validate Text, StringLength(minimum = 1, maximum = 80) * @Column(length="80") */ protected $title; /** * @var DoctrineCommonCollectionsCollection<TYPO3BlogDomainModelPost> * @OneToMany(mappedBy="blog") * @OrderBy({"date" = "DESC"}) */ protected $posts; ... }
  • 53.
    Hanau, Germany Persistence-related Annotations @Entity Declares a class as "entity" @Column Controls the database column related to the class property. Very useful for longer text content (type="text" !) @ManyToOne Defines relations to other entities. Unlike with @OneToMany vanilla Doctrine targetEntity does not have to be @ManyToMany given but will be reused from the @var @OneToOne annotation. cascade can be used to cascade operation to related objects.
  • 54.
    Hanau, Germany Persistence-related Annotations @var Defines the type of a property, collections can be typed using angle brackets: DoctrineCommonCollectionsCollection<TYPO3ConferenceDomainModelComment> @transient The property will be ignored, it will neither be persisted nor reconstituted @identity Marks the property as part of an objects identity
  • 55.
    Hanau, Germany Custom Queries using the Query Object Model /** * A PostRepository */ class PostRepository extends TYPO3FLOW3PersistenceRepository { /** * Finds posts by the specified tag and blog * * @param TYPO3BlogDomainModelTag $tag * @param TYPO3BlogDomainModelBlog $blog The blog the post must refer to * @return TYPO3FLOW3PersistenceQueryResultInterface The posts */ public function findByTagAndBlog(TYPO3BlogDomainModelTag $tag, TYPO3BlogDomainModelBlog $blog) { $query = $this->createQuery(); return $query->matching( $query->logicalAnd( $query->equals('blog', $blog), $query->contains('tags', $tag) ) ) ->setOrderings(array( 'date' => TYPO3FLOW3PersistenceQueryInterface::ORDER_DESCENDING) ) ->execute(); } }
  • 56.
    Hanau, Germany Schema Management Doctrine2 Migrations • Migrations allow schema versioning and change deployment • Migrations are the recommended way for DB updates • Tools to create and deploy migrations are integrated with FLOW3
  • 57.
    Hanau, Germany Schema Management RunningMigrations • needed after installation or upgrade: $ ./flow3 doctrine:migrate
  • 58.
    Hanau, Germany Schema Management Manualdatabase updates • for simple situations this can be good enough: $ ./flow3 doctrine:create $ ./flow3 doctrine:update • useful when • you are just starting a project and have never released
  • 59.
    Hanau, Germany Schema Management Generatingmigrations $ ./flow3 doctrine:migrationgenerate Generated new migration class to "…/Version20110608074324.php" from schema differences. $ • Generated migrations can contain errors and should be checked and adjusted as needed • Migrations need to be moved to their “owning” package manually
  • 60.
    M ig ratio n s 5 8 1 1 Ro bert Lem ke D.P. F l u x t r time ();
  • 61.
    Hanau, Germany Fluid Example forassigning a string to a Fluid variable: // in the action controller: $this->view->assign('title', 'Welcome to Fluid'); <!-- in the Fluid template: --> <head> <title>{title}</title> </head>
  • 62.
    Hanau, Germany Fluid Variables canalso be objects: // in the action controller: $this->view->assign('conference', $conference); <!-- in the Fluid template: --> <div class="venue"> <p>Venue Street: {conference.venue.street}</p> </div>
  • 63.
    Hanau, Germany Fluid if-then-else: // in the action controller: $this->view->assign('post', $blogPost); <!-- in the Fluid template: --> <f:if condition="{post.comments}"> <f:then>There are some comments.</f:then> <f:else>There are no comments.</f:else> </f:if>
  • 64.
    Hanau, Germany Fluid for-each: // in the action controller: $this->view->assign('ages', array("Karsten" => 34, "Robert" => 35)); <!-- in the Fluid template: --> <ul> <f:for each="{ages}" as="age" key="name"> <li>{name} is {age} year old.</li> </f:for> </ul>
  • 65.
    Hanau, Germany Fluid for-each: // in the action controller: $this->view->assign('post', $blogPost); <!-- in the Fluid template: --> <f:if condition="{post.comments}"> <ul> <f:for each="{post.comments}" as="comment" > <li>{post.title}</li> </f:for> </ul> </f:if>
  • 66.
    Hanau, Germany Fluid View helpers– in this case the link.action view helper: <!-- in the Fluid template: --> {namespace f=F3FluidViewHelpers} <f:link.action action="delete" arguments="{post: post, really: 'yes'}"> Delete this post </f:link.action>
  • 67.
    F lue nt F lu id 5 8 1 1 K. Damb ek aln s & R. Lem ke D.P. F l u x t r time ();
  • 68.
    Hanau, Germany Security Touchless Security,Flow-Style • security is handled at a central place (through AOP) • third-party code is as secure as possible by default • modeled after our experiences in the TYPO3 project and Spring Security (Java framework) • provides authentication, authorization, validation, filtering ... • can intercept arbitrary method calls • transparently filters content through query-rewriting • extensible for new authentication or authorization mechanisms
  • 69.
  • 70.
    Us e rsa n d L o g in 5 8 1 1 K. Damb ek aln s & R. Lem ke D.P. F l u x t r time ();
  • 71.
    Hanau, Germany AOP Aspect-Oriented Programming • programming paradigm • separates concerns to improve modularization • OOP modularizes concerns into objects • AOP modularizes cross-cutting concerns into aspects • FLOW3 makes it easy (and possible at all) to use AOP in PHP
  • 72.
    Hanau, Germany AOP /** * @aspect FLOW3 uses AOP for ... * @introduce */ F3FLOW3Pers istenceAspec tPersistence class Persist MagicInterfac enceMagicAspe e, F3FLO ct { • persistence magic /** * @pointcut c lassTaggedWit */ h(entity) || classTaggedWi th(valueobjec • logging public functi on isEntityOr ValueObject() {} t) /** * @var string • debugging * @Id * @Column(len gth="40") * @introduce F3FLOW3Pers */ istenceAspec tPersistence • security protected $FL OW3_Persisten ce_Identifier ; MagicAspect-> isEnti /** * After retur ning advice, * making sure w e have an UUI * @param F3 D for each an FLOW3AOPJoi d every * @return voi nPointInterfa d ce $joinPoint * @before cla The current j ssTaggedWith( oin po */ entity) && me thod(.*->__co public functi nstruct()) on generateUU $proxy = $joi ID(F3FLOW3 nPoint->getPr AOPJoinPoint oxy(); Interface $jo F3FLOW3Ref inPoint) lectionObjec } tAccess::setP roperty($prox y , 'FLOW3_Per siste
  • 73.
    Th e Wiza rd o f AOP 5 8 1 1 K. Damb ek aln s & R. Lem ke D.P. F l u x t r time ();
  • 74.
    Hanau, Germany Signal-Slot EventHandling Signal • can be fired on any event • can be freely defined by the developer Slot • is invoked when a signal is emitted • any method can be used as a slot any signal can be wired to any slot
  • 75.
    Hanau, Germany Signal-Slot EventHandling /** * @param F3BlogDomainModelPost $post * @param F3BlogDomainModelComment $newComment * @return void */ public function createAction(F3BlogDomainModelPost $post, F3BlogDomainModelComment $newComment) { $post->addComment($newComment); $this->emitCommentCreated($newComment, $post); … } /** * @param F3BlogDomainModelComment $comment * @param F3BlogDomainModelPost $post * @return void * @signal */ protected function emitCommentCreated(F3BlogDomainModelComment $comment, F3BlogDomainModelPost $post) {}
  • 76.
    Hanau, Germany Signal-Slot EventHandling Signals are wired to Slots in a package’s bootstrap: /** * Invokes custom PHP code directly after the package manager has been * initialized. * * @param F3FLOW3CoreBootstrap $bootstrap The current bootstrap * @return void */ public function boot(F3FLOW3CoreBootstrap $bootstrap) { $dispatcher = $bootstrap->getSignalSlotDispatcher(); $dispatcher->connect( 'F3BlogControllerCommentController', 'commentCreated', 'F3BlogServiceNotification', 'sendNewCommentNotification' ); }
  • 77.
    Hanau, Germany Signal-Slot EventHandling Any method can be a slot: /** * @param F3BlogDomainModelComment $comment * @param F3BlogDomainModelPost $post * @return void */ public function sendNewCommentNotification(F3BlogDomainModelComment $comment, F3BlogDomainModelPost $post) { $mail = new F3SwiftMailerMessage(); $mail ->setFrom(array('john@doe.org ' => 'John Doe')) ->setTo(array('karsten@typo3.org ' => 'Karsten Dambekalns')) ->setSubject('New comment on blog post "' . $post->getTitle() . '"') ->setBody($comment->getContent()) ->send(); }
  • 78.
  • 79.
  • 80.
  • 81.
    Hanau, Germany Thank You& Have Fun! • FLOW3: http://flow3.typo3.org • Blog: http://robertlemke.de/blog • Twitter: @robertlemke / @mrbasti • Feedback: robert@typo3.org / bastian@typo3.org