fluent development with flow3 1.0

94
San Francisco, USA Fluent Development with FLOW3 Karsten Dambekalns & Robert Lemke

Upload: robert-lemke

Post on 06-May-2015

3.294 views

Category:

Technology


1 download

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.This tutorial provides a comprehensive overview of the main features of FLOW3 and how you can get started with your first app.

TRANSCRIPT

Page 1: Fluent Development with FLOW3 1.0

San Francisco, USA

Fluent Development with FLOW3

Karsten Dambekalns & Robert Lemke

Page 2: Fluent Development with FLOW3 1.0

San Francisco, USA

co-lead of TYPO3 5.0 and FLOW3

34 years old

lives in Lübeck, Germany

1 wife, 3 sons, 1 espresso machine

likes canoeing

Karsten Dambekalns

Page 3: Fluent Development with FLOW3 1.0

San Francisco, USA

chief "architect" of TYPO3 5.0 and FLOW3

co-founder of the TYPO3 Association

35 years old

lives in Lübeck, Germany

1 wife, 1 daughter, 1 espresso machine

likes drumming

Robert Lemke

Page 4: Fluent Development with FLOW3 1.0

San Francisco, USA

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 5: Fluent Development with FLOW3 1.0

San Francisco, USA

Foundation for the Next Generation

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 6: Fluent Development with FLOW3 1.0

San Francisco, USA

Work in Progress

WARNING

The current documentation of FLOW3 does not cover the version in our Git master – a lot has changed since the last alpha release!

We are currently updating the manuals and tutorials for the 1.0 beta release though.

Page 7: Fluent Development with FLOW3 1.0

San Francisco, USA

Check Out from Git – Stable State

$ 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 8: Fluent Development with FLOW3 1.0

San Francisco, USA

Set File Permissions

$ ./Packages/Framework/FLOW3/Scripts/setfilepermissions.sh robert _www _wwwFLOW3 File Permission Script

Checking permissions from here upwards ... (if a password prompt appears it's from sudo)Password:

Making sure Data and Web/_Resources exist ...Setting file permissions, this might take a minute ...

$

Page 9: Fluent Development with FLOW3 1.0

San Francisco, USA

Set Up Database

Configuration/Settings.yaml

# ## Global Settings ## #

FLOW3: persistence: backendOptions: driver: 'pdo_mysql' dbname: 'blog' user: 'bloguser' password: 'blogpassword' host: '127.0.0.1' path: '127.0.0.1' port: 3306 doctrine: dbal: sessionInitialization: 'SET NAMES utf8 COLLATE utf8_unicode_ci'

Page 10: Fluent Development with FLOW3 1.0

San Francisco, USA

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 11: Fluent Development with FLOW3 1.0

San Francisco, USA

Final Check

Page 12: Fluent Development with FLOW3 1.0

San Francisco, USA

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 5187430ee44d579ae2bac825e2a069c4cd3f38a4.Entering 'Packages/Application/TYPO3CR'First, rewinding head to replay your work on top of it...Fast-forwarded master to b1f5331aa51d390fa3d973404f31b9fd773f7059.Entering 'Packages/Application/Twitter'Current branch master is up to date.…

Page 13: Fluent Development with FLOW3 1.0

San Francisco, USA

Hello World!

Package.php

<?phpnamespace F3\Demo;

use \F3\FLOW3\Package\Package as BasePackage;

class Package extends BasePackage {}

$ ./flow3_dev flow3:package:create --package-key Demo

$ ./flow3_dev flow3:package:create Demo

Soon:

Today:

Page 14: Fluent Development with FLOW3 1.0

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 11

Live Hacking

Page 15: Fluent Development with FLOW3 1.0

San Francisco, USA

Hello World!

<?phpnamespace F3\Demo\Controller;

use \F3\FLOW3\MVC\Controller\ActionController;

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

?>

StandardController.php

Page 16: Fluent Development with FLOW3 1.0

San Francisco, USA

Hello World!

http://dev.flow3.rob/demo/standard/index?name=Robert

Hello Robert!

Page 17: Fluent Development with FLOW3 1.0

San Francisco, USA

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 \F3\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 \F3\Conference\Domain\Model\Participant $author * @return void * @author Robert Lemke <[email protected]> */ public function setAuthor(\F3\Conference\Domain\Model\Participant $author) { $this->author = $author; }

/** * Getter for the author of this paper * * @return \F3\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 \F3\Conference\Domain\Model\SessionType $proposedSessionType The proposed session type * @return void * @author Robert Lemke <[email protected]> */ public function setProposedSessionType(\F3\Conference\Domain\Model\SessionType $proposedSessionType) { $this->proposedSessionType = $proposedSessionType; }

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

Page 18: Fluent Development with FLOW3 1.0

San Francisco, USA

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 19: Fluent Development with FLOW3 1.0

San Francisco, USA

Domain-Driven Design

Ubiquitous Language

• important prerequisite for successful collaboration

• use the same words for

• discussion

• modeling

• development

• documentation

Page 20: Fluent Development with FLOW3 1.0

San Francisco, USA

Domain: Conference

Page 21: Fluent Development with FLOW3 1.0

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 12

Extreme Modeling

Page 22: Fluent Development with FLOW3 1.0

San Francisco, USA

Example Model: Paper

/** * A Paper * * @scope prototype * @entity */class Paper {

/** * @var \F3\Conference\Domain\Model\Account\Participant * @ManyToOne(cascade={"persist"}) * @validate NotEmpty */ protected $author;

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

Page 23: Fluent Development with FLOW3 1.0

San Francisco, USA

Example Model: Paper

/** * @var string * @Column(type="text") * @validate StringLength(minimum = 30, maximum = 150) */ protected $shortAbstract;

/** * @var string * @Column(type="text") * @validate StringLength(minimum = 100, maximum = 1000) */ protected $abstract;

/** * @var \F3\Conference\Domain\Model\Conference\SessionType * @ManyToOne(cascade={"persist"}) * @validate NotEmpty */ protected $proposedSessionType;

Page 24: Fluent Development with FLOW3 1.0

San Francisco, USA

Example Model: Paper

/** * @var \F3\Conference\Domain\Model\Conference\Track * @ManyToOne(cascade={"persist"}) * @validate NotEmpty */ protected $proposedTrack;

/** * @var \Doctrine\Common\Collections\ArrayCollection<\F3\Conference\Domain\Model\Comment> * @ManyToMany(cascade={"persist", "remove"}) */ protected $comments;

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

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

Page 25: Fluent Development with FLOW3 1.0

San Francisco, USA

Example Model: Paper

/** * @var string * @Column(type="text", nullable=true) */ protected $links;

/** * @var \Doctrine\Common\Collections\ArrayCollection<\F3\Conference\Domain\Model\Account\Participant> * @ManyToMany(cascade={"all"}) */ protected $speakers;

/** * one of the STATUS_* constants * @var string */ protected $status = self::STATUS_DRAFT;

Page 26: Fluent Development with FLOW3 1.0

San Francisco, USA

Example Model: Paper

/** * STATUS_* constants */ const STATUS_DRAFT = 'draft'; const STATUS_SUBMITTED = 'submitted'; const STATUS_REJECTED = 'rejected'; const STATUS_ACCEPTED = 'accepted'; const STATUS_SCHEDULED = 'scheduled';

public function __construct() { $this->comments = new \Doctrine\Common\Collections\ArrayCollection(); $this->speakers = new \Doctrine\Common\Collections\ArrayCollection(); }

/** * @param \F3\Conference\Domain\Model\Account\Participant $author * @return void */ public function setAuthor(\F3\Conference\Domain\Model\Account\Participant $author) { $this->author = $author; }

/** * @return \F3\Conference\Domain\Model\Account\Participant */ public function getAuthor() {

Page 27: Fluent Development with FLOW3 1.0

San Francisco, USA

Domain-Driven Design

Page 28: Fluent Development with FLOW3 1.0

San Francisco, USA

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)

• CouchDB is supported natively

Page 29: Fluent Development with FLOW3 1.0

San Francisco, USA

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 30: Fluent Development with FLOW3 1.0

San Francisco, USA

Advanced Queries

/** * Finds most recent posts excluding the given post * * @param \F3\Blog\Domain\Model\Post $post Post to exclude from result * @param integer $limit The number of posts to return at max * @return array All posts of the $post's blog except for $post */ public function findRecentExceptThis(\F3\Blog\Domain\Model\Post $post, $limit = 20) { $query = $this->createQuery(); $posts = $query->matching($query->equals('blog', $post->getBlog())) ->setOrderings(array('date' => \F3\FLOW3\Persistence\QueryInterface::ORDER_DESCENDING)) ->setLimit($limit) ->execute() ->toArray(); unset($posts[array_search($post, $posts)]); return $posts;

// this is an alternative way of doing this when extending the Doctrine 2 // specific repository and using DQL. return $this->entityManager ->createQuery('SELECT p FROM \F3\Blog\Domain\Model\Post p WHERE p.blog = :blog' .

'AND NOT p = :excludedPost ORDER BY p.date DESC') ->setMaxResults($limit) ->execute(array('blog' => $post->getBlog(), 'excludedPost' => $post)); }

PostRepository.php

Page 31: Fluent Development with FLOW3 1.0

San Francisco, USA

Purely Doctrine 2

<?phpnamespace My\Example;

/** * @Entity(repositoryClass="BugRepository") */class Bug {

/** * @var integer * @Id * @Column(type="integer") * @GeneratedValue */ public $id;

/** * @var string * @Column(type="string") */ public $description;

/** * @var \DateTime * @Column(type="datetime") */ public $created;

/** * @var User * @ManyToOne(targetEntity="User", inversedBy="assignedBugs") */ private $engineer;

/** * @var \Doctrine\Common\Collections\ArrayCollection<Product> * @ManyToMany(targetEntity="Product") */ private $products;}

?>

Page 32: Fluent Development with FLOW3 1.0

San Francisco, USA

Doctrine 2 in FLOW3

<?phpnamespace My\Example;

/** * @Entity(repositoryClass="BugRepository") */class Bug {

/** * @var integer * @Id * @Column(type="integer") * @GeneratedValue */ public $id;

/** * @var string * @Column(type="string") */ public $description;

/** * @var \DateTime * @Column(type="datetime") */ public $created;

/** * @var User * @ManyToOne(targetEntity="User", inversedBy="assignedBugs") */ private $engineer;

/** * @var \Doctrine\Common\Collections\ArrayCollection<Product> * @ManyToMany(targetEntity="Product") */ private $products;}

?>

Page 33: Fluent Development with FLOW3 1.0

San Francisco, USA

Purely Doctrine 2

/** * @var \DateTime * @Column(type="datetime") */ public $created;

/** * @var User * @ManyToOne(targetEntity="User", inversedBy="assignedBugs") */ private $engineer;

/** * @var \Doctrine\Common\Collections\ArrayCollection<Product> * @ManyToMany(targetEntity="Product") */ private $products;}

?>

Page 34: Fluent Development with FLOW3 1.0

San Francisco, USA

Doctrine 2 in FLOW3

/** * @var \DateTime * @Column(type="datetime") */ public $created;

/** * @var User * @ManyToOne(targetEntity="User", inversedBy="assignedBugs") */ private $engineer;

/** * @var \Doctrine\Common\Collections\ArrayCollection<Product> * @ManyToMany(targetEntity="Product") */ private $products;}

?>

Page 35: Fluent Development with FLOW3 1.0

San Francisco, USA

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 36: Fluent Development with FLOW3 1.0

San Francisco, USA

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 gathered automatically (autowiring)

• intuitive use and no bad magical surprises

• fast! (like hardcoded or faster)

Page 37: Fluent Development with FLOW3 1.0

San Francisco, USA

<?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 ' . $name, 200, array('Content-Type' => 'text/plain')); }}

Constructor Injection: Symfony 2Warning: might contain errors

(I'm no Symfony expert ...)

Page 38: Fluent Development with FLOW3 1.0

San Francisco, USA

<?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 39: Fluent Development with FLOW3 1.0

San Francisco, USA

<?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 40: Fluent Development with FLOW3 1.0

San Francisco, USA

Constructor Injection

Page 41: Fluent Development with FLOW3 1.0

San Francisco, USA

<?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 42: Fluent Development with FLOW3 1.0

San Francisco, USA

<?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 43: Fluent Development with FLOW3 1.0

San Francisco, USA

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 44: Fluent Development with FLOW3 1.0

San Francisco, USA

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 45: Fluent Development with FLOW3 1.0

San Francisco, USA

class Customer {

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

...}

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

Object Management

Page 46: Fluent Development with FLOW3 1.0

San Francisco, USA

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 47: Fluent Development with FLOW3 1.0

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 13

Birth of a Blog

Page 48: Fluent Development with FLOW3 1.0

San Francisco, USA

The Zen of Templating

FLOW3 comes with an elegant, flexible and secure templating engine: Fluid

• templates are valid HTML

• templates contain no PHP code

• object access, control structures, loops ...

• designer-friendly

• extensible (view helpers, widgets)

Page 49: Fluent Development with FLOW3 1.0

San Francisco, USA

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 50: Fluent Development with FLOW3 1.0

San Francisco, USA

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 51: Fluent Development with FLOW3 1.0

San Francisco, USA

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 52: Fluent Development with FLOW3 1.0

San Francisco, USA

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 53: Fluent Development with FLOW3 1.0

San Francisco, USA

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 54: Fluent Development with FLOW3 1.0

San Francisco, USA

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 55: Fluent Development with FLOW3 1.0

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 18

Fluent Fluid

Page 56: Fluent Development with FLOW3 1.0

San Francisco, USA

Forms

<?phpnamespace F3\Blog\Domain\Model;

/** * A blog post * * @scope prototype * @entity */class Post {

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

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

/** * @var string * @validate Html */ protected $content;

/** * @var F3\Blog\Domain\Model\Image */ protected $image;

Page 57: Fluent Development with FLOW3 1.0

San Francisco, USA

Forms

<h2>Create a new post</h2>

<f:form action="create" object="{newPost}" name="newPost" enctype="multipart/form-data"> <label for="title">Title</label><br /> <f:form.textbox property="title" id="title" /><br />

<label for="content">Content</label><br /> <f:form.textarea property="content" rows="5" cols="40" id="content" /><br />

<label for="image">Image resource</label><br /> <f:form.textbox property="image.title" value="My image title" /> <f:form.upload property="image.originalResource" /></f:form>

Page 58: Fluent Development with FLOW3 1.0

San Francisco, USA

Forms

<?phpnamespace F3\Blog\Controller;use \F3\FLOW3\MVC\Controller\ActionController;

class PostController extends ActionController {

/** * @inject * @var \F3\Blog\Domain\Repository\PostRepository */ protected $postRepository;

/** * Creates a new post * * @param \F3\Blog\Domain\Model\Post $newPostadded to the repository * @return void */ public function createAction(\F3\Blog\Domain\Model\Post $newPost) { $this->blog->addPost($newPost); $this->flashMessageContainer->add('Your new post was created.'); $this->redirect('index'); }

}?>

Page 59: Fluent Development with FLOW3 1.0

San Francisco, USA

Fluent Development with FLOW3 (PART TWO)

Karsten Dambekalns & Robert Lemke

Page 60: Fluent Development with FLOW3 1.0
Page 61: Fluent Development with FLOW3 1.0

San Francisco, USA

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 62: Fluent Development with FLOW3 1.0

San Francisco, USA

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 63: Fluent Development with FLOW3 1.0

San Francisco, USA

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 64: Fluent Development with FLOW3 1.0

San Francisco, USA

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 65: Fluent Development with FLOW3 1.0

San Francisco, USA

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 66: Fluent Development with FLOW3 1.0

San Francisco, USA

Schema Management

Automatic database updates

• when first running FLOW3 the schema will be created

• when a model has changed, the schema is updated

• be careful with existing data, updates can be destructive

• for production you should manually manage schema changes

Page 67: Fluent Development with FLOW3 1.0

San Francisco, USA

Schema Management

Manual database updates

• for simple situations this can be good enough:

• useful when

• you need to use an existing database dump

• using SQLite, due to limited schema change functionality

$ ./flow3_dev flow3:doctrine:create

$ ./flow3_dev flow3:doctrine:update

Page 68: Fluent Development with FLOW3 1.0

San Francisco, USA

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 69: Fluent Development with FLOW3 1.0

San Francisco, USA

Schema Management

Migrations Workflow

• use schema auto update in early development until your model is ready for a first “freeze”, then switch off schema auto update and drop your tables

• create migration diff and customize it

• migrate to create the tables

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

$ ./flow3_dev flow3:doctrine:migrate

Page 70: Fluent Development with FLOW3 1.0

San Francisco, USA

Schema Management

Migrations Workflow

$ ./flow3_dev flow3:doctrine:migrationstatus

== Configuration >> Name: Doctrine Database Migrations >> Database Driver: pdo_mysql >> Database Name: blog >> Configuration Source: manually configured >> Version Table Name: flow3_doctrine_migrationstatus >> Migrations Namespace: F3\FLOW3\Persistence\Doctrine\Migrations >> Migrations Directory: /Users/karsten/Sites/blog/Configuration/Doctrine/Migrations >> Current Version: 2011-06-08 07:43:24 (20110608074324) >> Latest Version: 2011-06-08 07:43:24 (20110608074324) >> Executed Migrations: 1 >> Available Migrations: 1 >> New Migrations: 0

== Migration Versions >> 2011-06-08 07:43:24 (20110608074324) migrated

Page 71: Fluent Development with FLOW3 1.0

San Francisco, USA

Schema Management

Migrations Workflow

• rinse and repeat: from now on create a new migration whenever you changed your model classes

• generated migrations most probably need to be adjusted

• e.g. renaming a model means renaming a table, not dropping and creating

• data migration needs to be added

• remember: good migrations make your user’s day

Page 72: Fluent Development with FLOW3 1.0

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 18

Schematic Demo

Page 73: Fluent Development with FLOW3 1.0

San Francisco, USA

Command Line Support

Page 74: Fluent Development with FLOW3 1.0

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 18

Shebang!

Page 75: Fluent Development with FLOW3 1.0

San Francisco, USA

Command Line Support

<?phpnamespace F3\FLOW3\Command;

/** * Package command controller to handle packages from CLI (create/activate/deactivate packages) * * @scope singleton */class PackageCommandController extends \F3\FLOW3\MVC\Controller\CommandController {

/** * @inject * @var F3\FLOW3\Package\PackageManagerInterface */ protected $packageManager;

/** * Creates a new package * * Creates a new package with the given package key. The package key * should be the vendor namespace segments. * * @param string $packageKey The package key of the package to create * @return string */ public function createCommand($packageKey) { if (!$this->packageManager->isPackageKeyValid($packageKey)) { $this->response->appendContent('The package key "' . $packageKey . '" is not valid.');

Page 76: Fluent Development with FLOW3 1.0

San Francisco, USA

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 77: Fluent Development with FLOW3 1.0

San Francisco, USA

Security Policy

Page 78: Fluent Development with FLOW3 1.0

San Francisco, USA

Security

Cross-Site Request Forgery

• enables an attacker to execute privileged operations without being authenticated

• the risk lies in using malicious links or forms while still being authenticated

• imagine a link coming in through an URL shortener...

Page 79: Fluent Development with FLOW3 1.0

San Francisco, USA

Security

Avoiding Cross-Site Request Forgery

• add a (truly!) random string token to each link or form

• make sure this token is correct before executing anything

• change the token as often as possible to make it impossible to send you a working malicious link while you’re logged in

• in most cases, we can assume that it should be enough to generate one token when you log in – that’s the default

Page 80: Fluent Development with FLOW3 1.0

San Francisco, USA

Security

CSRF Protection in FLOW3

• you must not forget to add that token to any link

• FLOW3 automatically adds the CSRF token to each

• link you generate

• each form you create with Fluid

• and checks it for every call to a protected action

• the protection can be disabled using @skipCsrfProtection on an action

Page 81: Fluent Development with FLOW3 1.0

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 18

Users and Login

Page 82: Fluent Development with FLOW3 1.0

San Francisco, USA

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 83: Fluent Development with FLOW3 1.0

San Francisco, USA

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 84: Fluent Development with FLOW3 1.0

K. Dambekalns & R. LemkeD.P. Fluxtr

time();

5 1 18

The Wizard of AOP

Page 85: Fluent Development with FLOW3 1.0

San Francisco, USA

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 86: Fluent Development with FLOW3 1.0

San Francisco, USA

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 87: Fluent Development with FLOW3 1.0

San Francisco, USA

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 88: Fluent Development with FLOW3 1.0

San Francisco, USA

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 89: Fluent Development with FLOW3 1.0

San Francisco, USA

Speed and Performance

For the snappy user experience:

• multi-layered, tagged caches

• various cache backends (file, Memcached, APC, Redis, PDO, ...)

• reverse-proxy support (Varnish, ESI) in the works

• code compilation

• regular benchmarks

• focus on good scalability

Page 90: Fluent Development with FLOW3 1.0

San Francisco, USA

More Features

• Resource Management (CDNs, private resources, ...)

• Logging

• File Monitoring

• Configuration Management

• Routing

• REST / SOAP

• ...

Page 91: Fluent Development with FLOW3 1.0

San Francisco, USA

Roadmap

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

Page 92: Fluent Development with FLOW3 1.0

San Francisco, USA

Discover the source code of the conference app

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

Page 93: Fluent Development with FLOW3 1.0

San Francisco, USA

Try out the blog app

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

Page 94: Fluent Development with FLOW3 1.0

San Francisco, USA

Thank You!

• These slides: http://slideshare.net/robertlemke

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

• Follow us on Twitter: @t3rob (Robert) @k_fish (Karsten)

• Give us feedback:

[email protected] / [email protected]

• http://joind.in/3535