FLOW3 Tutorial - T3CON11 Frankfurt

81
/** * Conference controller for the Acme.Demo package * * @scope singleton */ class ConferenceController extends ActionController { /** * @inject * @var \Acme\Demo\Domain\Repository\ConferenceRepository */ protected $conferenceRepository; /** * Shows a list of conferences * * @return void */ public function indexAction() { $this->view->assign('conferences', $this->conferenceRepository->findAll()); } /** * Shows a single conference object * FLOW3 Tutorial Bastian Waidelich & Robert Lemke

description

FLOW3 is an application framework which will change the way you code PHP. It aims to back up developers with security and infrastructure while they focus on the application logic. FLOW3 is one of the first application frameworks to choose Domain-Driven Design as its major underlying concept. This approach makes FLOW3 easy to learn and at the same time clean and flexible for even complex projects. Built with PHP 5.3 in mind from the beginning, it features namespaces and has an emphasis on clean, object-oriented code.Thanks to its Doctrine 2 integration, FLOW3 gives you access to a wide range of databases while letting you forget the fact that you’re using a database at all (think objects, not tables). FLOW3’s unique way of supporting Dependency Injection (no configuration necessary) lets you truly enjoy creating a stable and easy-to-test application architecture. Being the only Aspect-Oriented Programming capable PHP framework, FLOW3 allows you to cleanly separate cross cutting concerns like security from your main application logic.In this tutorial we’ll walk you through an imaginary project from scratch. During the journey we’ll visit all important areas of the framework like templating, routing, security and persistence. For every core concept we’ll provide a short introduction, so that the process is comprehensible to all experienced PHP developers.

Transcript of FLOW3 Tutorial - T3CON11 Frankfurt

Page 1: FLOW3 Tutorial - T3CON11 Frankfurt

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

/** * @inject * @var \Acme\Demo\Domain\Repository\ConferenceRepository */ protected $conferenceRepository;

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

/** * Shows a single conference object * * @param \Acme\Demo\Domain\Model\Conference $conference The conference to show * @return void */ public function showAction(Conference $conference) { $this->view->assign('conference', $conference); }

/** * Shows a form for creating a new conference object * * @return void */ public function newAction() { }

/** * Adds the given new conference object to the conference repository * * @param \Acme\Demo\Domain\Model\Conference $conference A new conference to add * @return void */ public function createAction(Conference $newConference) { $this->conferenceRepository->add($newConference); $this->flashMessageContainer->add('Created a new conference.'); $this->redirect('index'); }

/** * Shows a form for editing an existing conference object * * @param \Acme\Demo\Domain\Model\Conference $conference The conference to edit * @return void */ public function editAction(Conference $conference) { $this->view->assign('conference', $conference); }

FLOW3 Tutorial

Bastian Waidelich & Robert Lemke

Page 2: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

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

Robert Lemke

Page 3: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

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

Bastian Waidelich

Page 4: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 5: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

This Workshop

Afternoon

• Routing

• Validation

• Property Mapper

• Migrations

• Security / Login

• A Glimpse on TYPO3 Phoenix

Page 6: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 7: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 8: FLOW3 Tutorial - T3CON11 Frankfurt

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.

Page 9: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Set File Permissions

$ sudo ./flow3 core:setfilepermissions robert _www _wwwFLOW3 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.

$ sudo usermod -a -G www-data robert

$ sudo dscl . -append /Groups/_www GroupMembership robert

Linux:

Mac OS X:

Page 10: FLOW3 Tutorial - T3CON11 Frankfurt

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'

Page 11: FLOW3 Tutorial - T3CON11 Frankfurt

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>

Page 12: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Final Check

Page 13: FLOW3 Tutorial - T3CON11 Frankfurt

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.…

Page 14: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Command Line Use

$ ./flow3 helpFLOW3 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

help Display help for a command

package:create Create a new package package:delete Delete an existing package package:activate Activate an available package package:deactivate Deactivate a package package:list List available packages package:import Import a package from a remote location

routing:list List the known routes

security:importpublickey Import a public key security:importprivatekey Import a private key

PACKAGE "TYPO3.KICKSTART":------------------------------------------------------------------------------- kickstart:package Kickstart a new package kickstart:actioncontroller Kickstart a new action controller kickstart:commandcontroller Kickstart a new command controller kickstart:model Kickstart a new domain model kickstart:repository Kickstart a new domain repository

* = compile time command

See './flow3 help <commandidentifier>' for more information about a specific command.

Page 15: FLOW3 Tutorial - T3CON11 Frankfurt

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)

Page 16: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Hello World!

$ ./flow3 kickstart:package Acme.Demo

Page 17: FLOW3 Tutorial - T3CON11 Frankfurt

Robert LemkeD.P. Fluxtr

time();

5 1 11

Hello World!

Page 18: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Hello World!

<?phpnamespace Acme\Demo\Controller;

use \TYPO3\FLOW3\MVC\Controller\ActionController;

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

?>

StandardController.php

Page 19: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Tackling the Heart of Software Development

Domain-Driven DesignA methodology which ...

• results in rich domain models

• provides a common language across the project team

• simplify the design of complex applications

FLOW3 is the first PHP framework tailored to Domain-Driven Design

/** * Paper submitted by a speaker * * @scope prototype * @entity */class Paper {

/** * @var Participant */ protected $author;

/** * @var string */ protected $title;

/** * @var string */ protected $shortAbstract;

/** * @var string */ protected $abstract;

/** * @var \SplObjectStorage */ protected $materials;

/** * @var \Acme\Conference\Domain\Model\SessionType * @validate NotEmpty */ protected $proposedSessionType;

/** * Constructs a new Paper * * @author Robert Lemke <[email protected]> */ public function __construct() { $this->materials = new \SplObjectStorage; }

/** * Sets the author of this paper * * @param \Acme\Conference\Domain\Model\Participant $author * @return void * @author Robert Lemke <[email protected]> */ public function setAuthor(\Acme\Conference\Domain\Model\Participant $author) { $this->author = $author; }

/** * Getter for the author of this paper * * @return \Acme\Conference\Domain\Model\Participant * @author Robert Lemke <[email protected]> */ public function getAuthor() { return $this->author; }

/** * Setter for title * * @param string $title The title of this paper * @return void * @author Robert Lemke <[email protected]> */ public function setTitle($title) { $this->title = $title; }

/** * Getter for title * * @return string The title of this paper * @author Robert Lemke <[email protected]> */ public function getTitle() { return $this->title; }

/** * Setter for the short abstract * * @param string $shortAbstract The short abstract for this paper * @return void * @author Robert Lemke <[email protected]> */ public function setShortAbstract($shortAbstract) { $this->shortAbstract = $shortAbstract; }

/** * Getter for the short abstract * * @return string The short abstract * @author Robert Lemke <[email protected]> */ public function getShortAbstract() { return $this->shortAbstract; }

/** * Setter for abstract * * @param string $abstract The abstract of this paper * @return void * @author Robert Lemke <[email protected]> */ public function setAbstract($abstract) { $this->abstract = $abstract; }

/** * Getter for abstract * * @return string The abstract * @author Robert Lemke <[email protected]> */ public function getAbstract() { return $this->abstract; }

/** * Returns the materials attached to this paper * * @return \SplObjectStorage The materials * @author Robert Lemke <[email protected]> */ public function getMaterials() { return $this->materials; }

/** * Setter for the proposed session type * * @param \Acme\Conference\Domain\Model\SessionType $proposedSessionType The proposed session type * @return void * @author Robert Lemke <[email protected]> */ public function setProposedSessionType(\Acme\Conference\Domain\Model\SessionType $proposedSessionType) { $this->proposedSessionType = $proposedSessionType; }

/** * Getter for the proposed session type * * @return \Acme\Conference\Domain\Model\SessionType The proposed session type * @author Robert Lemke <[email protected]> */ public function getProposedSessionType() { return $this->proposedSessionType; }}?>

Page 20: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 21: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Domain-Driven Design

Ubiquitous Language

• important prerequisite for successful collaboration

• use the same words for

• discussion

• modeling

• development

• documentation

Page 22: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Domain-Driven Design

Page 23: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Domain: Conference

Page 24: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Domain: Conference

Page 25: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Domain: Conference

Page 26: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Domain: Conference

Page 27: FLOW3 Tutorial - T3CON11 Frankfurt

Robert LemkeD.P. Fluxtr

time();

5 1 11

Kickstarting "Conference"

Page 28: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Domain: Conference

Page 29: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 30: FLOW3 Tutorial - T3CON11 Frankfurt

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)

Page 31: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

<?phpnamespace Acme\DemoBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpFoundation\RedirectResponse;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;use Acme\DemoBundle\GreeterService;

class DemoController extends Controller { /** * @var \Acme\DemoBundle\GreeterService */ protected $greeterService;

/** * @param \Acme\DemoBundle\GreeterService */ 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')); }}

Constructor Injection: Symfony 2Warning: might contain errors

(I'm no Symfony expert ...)

Page 32: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

<?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="Acme\DemoBundle\GreeterService" public="false" /> <service id="acme.demo.democontroller" class="Acme\DemoBundle\Controller\DemoController"> <argument type="service" id="acme.demo.greeterservice" /> </service> </services></container>

Constructor Injection: Symfony 2Warning: might contain errors

(I'm no Symfony expert ...)

Page 33: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

<?php namespace F3\Demo\Controller;

use F3\FLOW3\MVC\Controller\ActionController;use F3\Demo\Service\GreeterService;

class DemoController extends ActionController { /** * @var \F3\Demo\Service\GreeterService */ protected $greeterService;

/** * @param \F3\Demo\Service\GreeterService */ public function __construct(\F3\Demo\Service\GreeterService $greeterService) { $this->greeterService = $greeterService; } /** * @param string $name */ public function helloAction($name) { return 'Hello ' . $name; }}

Constructor Injection

Page 34: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Constructor Injection

Page 35: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

<?php namespace F3\Demo\Controller;

use F3\FLOW3\MVC\Controller\ActionController;use F3\Demo\Service\GreeterService;

class DemoController extends ActionController { /** * @var \F3\Demo\Service\GreeterService */ protected $greeterService;

/** * @param \F3\Demo\Service\GreeterService */ public function injectGreeterService(\F3\Demo\Service\GreeterService $greeterService) { $this->greeterService = $greeterService; } /** * @param string $name */ public function helloAction($name) { return 'Hello ' . $name; }}

Setter Injection

Page 36: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

<?php namespace F3\Demo\Controller;

use F3\FLOW3\MVC\Controller\ActionController;use F3\Demo\Service\GreeterService;

class DemoController extends ActionController { /** * @var \F3\Demo\Service\GreeterService * @inject */ protected $greeterService; /** * @param string $name */ public function helloAction($name) { return 'Hello ' . $name; }}

Property Injection

Page 37: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

F3\FLOW3\Security\Cryptography\RsaWalletServiceInterface: className: F3\FLOW3\Security\Cryptography\RsaWalletServicePhp scope: singleton properties: keystoreCache: object: factoryObjectName: F3\FLOW3\Cache\CacheManager factoryMethodName: getCache arguments: 1: value: FLOW3_Security_Cryptography_RSAWallet

Objects.yaml

Page 38: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

class Customer {

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

...}

$customer = new Customer();$customer->getCustomerNumber();

Object Management

Page 39: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Object Management

<?phpdeclare(ENCODING = 'utf-8');namespace F3\Conference\Domain\Model\Conference;/** * Autogenerated Proxy Class * @scope prototype * @entity */class Paper extends Paper_Original implements \F3\FLOW3\Object\Proxy\ProxyInterface, \F3\FLOW3\Persistence\Aspect\PersistenceMagicInterface { /** * @var string * @Id * @Column(length="40") * introduced by F3\FLOW3\Persistence\Aspect\PersistenceMagicAspect */ protected $FLOW3_Persistence_Identifier = NULL; private $FLOW3_AOP_Proxy_targetMethodsAndGroupedAdvices = array(); private $FLOW3_AOP_Proxy_groupedAdviceChains = array(); private $FLOW3_AOP_Proxy_methodIsInAdviceMode = array();

/** * Autogenerated Proxy Method */ public function __construct() { $this->FLOW3_AOP_Proxy_buildMethodsAndAdvicesArray(); if (isset($this->FLOW3_AOP_Proxy_methodIsInAdviceMode['__construct'])) { parent::__construct(); } else {

FLOW3 creates proxy classesfor realizing DI and AOP magic

• new operator is supported

• proxy classes are created on the fly

• in production context all code is static

Page 40: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Your Own Commands

$ ./flow3 kickstart:commandcontroller Acme.Demo Test

Page 41: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 42: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 43: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Validation

Validation Models

• BasePropertiesrules defining the minimum requirements on individual properties of a model

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

• Supplementalrules defining additional requirements on a model for a specific situation (e.g. a certain action method)

Page 44: FLOW3 Tutorial - T3CON11 Frankfurt

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;

Page 45: FLOW3 Tutorial - T3CON11 Frankfurt

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 \Dambekalns\Stuff\Domain\Model\Stuff * @validate \Dambekalns\Stuff\Domain\Validator\StuffValidator */ protected $stuff;

Page 46: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 47: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Property Mapper

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

$article = $mapper->convert($sourceArray, 'Acme.Demo\Domain\Model\Article');

Page 48: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Resource Management

<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>

Image Upload

Resources are handled like other properties in a form:

Page 49: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Property Mapper

/** * @return void */ public function initializeUpdateAction() { $this->arguments['article']->getPropertyMappingConfiguration()

->allowCreationForSubProperty('picture'); $this->arguments['article']->getPropertyMappingConfiguration()

->allowModificationForSubProperty('picture'); }

Allow nested object structures

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

Page 50: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 51: FLOW3 Tutorial - T3CON11 Frankfurt

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);

Page 52: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Validation and Doctrine Annotations

namespace TYPO3\Blog\Domain\Model;

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

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

/** * @var \Doctrine\Common\Collections\Collection<\TYPO3\Blog\Domain\Model\Post> * @OneToMany(mappedBy="blog") * @OrderBy({"date" = "DESC"}) */ protected $posts;

...

}

Page 53: FLOW3 Tutorial - T3CON11 Frankfurt

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 @OneToMany @ManyToMany@OneToOne

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

cascade can be used to cascade operation to related objects.

Page 54: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

@var Defines the type of a property, collections can be typed using angle brackets:\Doctrine\Common\Collections\Collection<\TYPO3\Conference\Domain\Model\Comment>

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

@identity Marks the property as part of an objects identity

Persistence-related Annotations

Page 55: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Custom Queries using the Query Object Model

/** * A PostRepository */class PostRepository extends \TYPO3\FLOW3\Persistence\Repository {

/** * Finds posts by the specified tag and blog * * @param \TYPO3\Blog\Domain\Model\Tag $tag * @param \TYPO3\Blog\Domain\Model\Blog $blog The blog the post must refer to * @return \TYPO3\FLOW3\Persistence\QueryResultInterface The posts */ public function findByTagAndBlog(\TYPO3\Blog\Domain\Model\Tag $tag, \TYPO3\Blog\Domain\Model\Blog $blog) { $query = $this->createQuery(); return $query->matching( $query->logicalAnd( $query->equals('blog', $blog), $query->contains('tags', $tag) ) ) ->setOrderings(array( 'date' => \TYPO3\FLOW3\Persistence\QueryInterface::ORDER_DESCENDING) ) ->execute(); }}

Page 56: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 57: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Schema Management

Running Migrations

• needed after installation or upgrade:

$ ./flow3 doctrine:migrate

Page 58: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Schema Management

$ ./flow3 doctrine:create

$ ./flow3 doctrine:update

Manual database updates

• for simple situations this can be good enough:

• useful when

• you are just starting a project and have never released

Page 59: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Schema Management

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

Generating migrations

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

• Migrations need to be moved to their “owning” package manually

Page 60: FLOW3 Tutorial - T3CON11 Frankfurt

Robert LemkeD.P. Fluxtr

time();

5 1 18

Migrations

Page 61: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Fluid

Example for assigning a string to a Fluid variable:

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

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

Page 62: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Fluid

Variables can also be objects:

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

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

Page 63: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Fluid

if-then-else:

<!-- 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>

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

Page 64: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Fluid

for-each:

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

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

Page 65: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Fluid

for-each:

<!-- 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>

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

Page 66: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Fluid

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

<!-- in the Fluid template: --> {namespace f=F3\Fluid\ViewHelpers}

<f:link.action action="delete" arguments="{post: post, really: 'yes'}"> Delete this post </f:link.action>

Page 67: FLOW3 Tutorial - T3CON11 Frankfurt

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 18

Fluent Fluid

Page 68: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 69: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Security Policy

Page 70: FLOW3 Tutorial - T3CON11 Frankfurt

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 18

Users and Login

Page 71: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 72: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

AOP

FLOW3 uses AOP for ...

• persistence magic

• logging

• debugging

• security

/** * @aspect * @introduce F3\FLOW3\Persistence\Aspect\PersistenceMagicInterface, F3\FLOW3\Persistence\Aspect\

*/class PersistenceMagicAspect { /** * @pointcut classTaggedWith(entity) || classTaggedWith(valueobject) */ public function isEntityOrValueObject() {} /** * @var string * @Id * @Column(length="40") * @introduce F3\FLOW3\Persistence\Aspect\PersistenceMagicAspect->isEntityOrValueObject && filter

*/ protected $FLOW3_Persistence_Identifier; /** * After returning advice, making sure we have an UUID for each and every entity.

* * @param \F3\FLOW3\AOP\JoinPointInterface $joinPoint The current join point

* @return void * @before classTaggedWith(entity) && method(.*->__construct()) */ public function generateUUID(\F3\FLOW3\AOP\JoinPointInterface $joinPoint) {

$proxy = $joinPoint->getProxy(); \F3\FLOW3\Reflection\ObjectAccess::setProperty($proxy, 'FLOW3_Persistence_Identifier',

}

Page 73: FLOW3 Tutorial - T3CON11 Frankfurt

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 18

The Wizard of AOP

Page 74: FLOW3 Tutorial - T3CON11 Frankfurt

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

Page 75: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Signal-Slot Event Handling

/** * @param \F3\Blog\Domain\Model\Post $post * @param \F3\Blog\Domain\Model\Comment $newComment * @return void */ public function createAction(\F3\Blog\Domain\Model\Post $post, \F3\Blog\Domain\Model\Comment $newComment) { $post->addComment($newComment); $this->emitCommentCreated($newComment, $post); … }

/** * @param \F3\Blog\Domain\Model\Comment $comment * @param \F3\Blog\Domain\Model\Post $post * @return void * @signal */ protected function emitCommentCreated(\F3\Blog\Domain\Model\Comment $comment, \F3\Blog\Domain\Model\Post $post) {}

Page 76: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Signal-Slot Event Handling

/** * Invokes custom PHP code directly after the package manager has been * initialized. * * @param \F3\FLOW3\Core\Bootstrap $bootstrap The current bootstrap * @return void */ public function boot(\F3\FLOW3\Core\Bootstrap $bootstrap) { $dispatcher = $bootstrap->getSignalSlotDispatcher(); $dispatcher->connect( 'F3\Blog\Controller\CommentController', 'commentCreated', 'F3\Blog\Service\Notification', 'sendNewCommentNotification' ); }

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

Page 77: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Signal-Slot Event Handling

/** * @param \F3\Blog\Domain\Model\Comment $comment * @param \F3\Blog\Domain\Model\Post $post * @return void */ public function sendNewCommentNotification(\F3\Blog\Domain\Model\Comment $comment, \F3\Blog\Domain\Model\Post $post) { $mail = new \F3\SwiftMailer\Message(); $mail ->setFrom(array('[email protected] ' => 'John Doe')) ->setTo(array('[email protected] ' => 'Karsten Dambekalns')) ->setSubject('New comment on blog post "' . $post->getTitle() . '"') ->setBody($comment->getContent()) ->send(); }

Any method can be a slot:

Page 78: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Roadmap

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

Page 79: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Conference App

git://git.typo3.org/TYPO3v5/Distributions/Conference.git

Page 80: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Blog App

git://git.typo3.org/FLOW3/Applications/Blog.git

Page 81: FLOW3 Tutorial - T3CON11 Frankfurt

Hanau, Germany

Thank You & Have Fun!

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

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

• Twitter: @robertlemke / @mrbasti

• Feedback: [email protected] / [email protected]