FLOW3-Workshop F3X12

77
Einführung in FLOW3 FLOW3 Experience 2012 Karsten Dambekalns 1

description

Folien zum FLOW3 Workshop von der F3X12

Transcript of FLOW3-Workshop F3X12

Page 1: FLOW3-Workshop F3X12

Einführung in

FLOW3

FLOW3 Experience 2012

Karsten Dambekalns

1

Page 2: FLOW3-Workshop F3X12

Co-Lead von TYPO3 Phoenix und FLOW3

34 Jahre alt

lebt in Lübeck

1 Frau, 3 Söhne, 1 Espressomaschine

fährt gern Kanadier und klettert

Karsten Dambekalns

2

Page 3: FLOW3-Workshop F3X12

Auf einen Blick

FLOW3 ist eine Web Application Platform

• ermöglicht eine neue Art von PHP-Entwicklung

• basiert auf PHP 5.3, vollständiger Namespaces Support

• modular, erweiterbar, paket-basiert

• frei & Open Source (LGPL v3)

• unterstützt von einem der größten Open SourceProjekte, mit mehr als 6000 Entwicklern

3

Page 4: FLOW3-Workshop F3X12

Grundlage für das Next-Generation CMS

TYPO3 Phoenix ist das komplett neue Enterprise CMS

• Content Repository, Workspaces, Versionierung, i18n, neues UI ...

• powered by FLOW3

• FLOW3 kompatible Code-Basis

• benutze TYPO3 Features ineigenen FLOW3 Applikationen

4

Page 5: FLOW3-Workshop F3X12

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.

5

Page 6: FLOW3-Workshop F3X12

Zugriffsrechte einrichten

$ sudo ./flow3 core:setfilepermissions karsten _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 karsten

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

Linux:

Mac OS X:

6

Page 7: FLOW3-Workshop F3X12

Datenbankverbindung einrichten

Configuration/Settings.yaml

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

# doctrine:# sqlLogger: 'TYPO3\FLOW3\Persistence\Doctrine\Logging\SqlLogger'

7

Page 8: FLOW3-Workshop F3X12

Konfiguration per Kontext

• FLOW3 bietet verschiedene Kontexte für Entwicklung, Test und Produktivbetrieb

• je nach Kontext konfigurieren: Datenbank, Logging, …

• Unterscheidung per Umgebungsvariable im Virtual Host und auf der Konsole:

$ ./flow3 helpFLOW3 1.1.0-dev ("Development" context)usage: ./flow3 <command identifier> …

$ FLOW3_CONTEXT=Production ./flow3 helpFLOW3 1.1.0-dev ("Production" context)usage: ./flow3 <command identifier> …

8

Page 9: FLOW3-Workshop F3X12

Virtual Host einrichten

Apache Virtual Host

<VirtualHost *:80> DocumentRoot /opt/local/apache2/htdocs/Talks/FLOW3/Web/ ServerName dev.flow3.kmac</VirtualHost>

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

9

Page 10: FLOW3-Workshop F3X12

Funktioniert's?

10

Page 11: FLOW3-Workshop F3X12

Git Submodule aktualisieren (bleeding edge)

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

11

Page 12: FLOW3-Workshop F3X12

Kommandozeile

$ ./flow3 helpFLOW3 1.1.0-dev ("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

configuration:show Show the active configuration settings

* 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 package:freeze Freeze a package package:unfreeze Unfreeze a package package:refreeze Refreeze a package

12

Page 13: FLOW3-Workshop F3X12

Kommandozeile

$ ./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)

13

Page 14: FLOW3-Workshop F3X12

Hallo Welt!

$ ./flow3 kickstart:package Acme.Demo

14

Page 15: FLOW3-Workshop F3X12

Hallo Welt!

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

15

Page 16: FLOW3-Workshop F3X12

Controller Kickstart

$ ./flow3 help kickstart:actioncontroller

Kickstart a new action controller

COMMAND: typo3.kickstart:kickstart:actioncontroller

USAGE: ./flow3 kickstart:actioncontroller [<options>] <package key> <controller name>

ARGUMENTS: --package-key The package key of the package for the new controller with an optional subpackage, (e.g. "MyCompany.MyPackage/Admin"). --controller-name The name for the new controller. This may also be a comma separated list of controller names.

OPTIONS: --generate-actions Also generate index, new, create, edit, update and delete actions. --generate-templates Also generate the templates for each action. --generate-related Also create the mentioned package, related model and repository if neccessary. --force Overwrite any existing controller or template code. Regardless of this flag, the package, model and repository will never be overwritten.

DESCRIPTION: Generates an Action Controller with the given name in the specified package. In its default mode it will create just the controller containing a sample indexAction. By specifying the --generate-actions flag, this command will also create a set of actions. If no model or repository exists which matches the controller name (for example "CoffeeRepository" for "CoffeeController"), an error will be shown. Likewise the command exits with an error if the specified package does not exist. By using the --generate-related flag, a missing package, model or repository can be created alongside, avoiding such an error. By specifying the --generate-templates flag, this command will also create matching Fluid templates for the actions created. This option can only be used in combination with --generate-actions. The default behavior is to not overwrite any existing code. This can be overridden by specifying the --force flag.

SEE ALSO: typo3.kickstart:kickstart:commandcontroller (Kickstart a new command controller)

16

Page 17: FLOW3-Workshop F3X12

Eigene Commands

$ ./flow3 kickstart:commandcontroller Acme.Demo Test

namespace Acme\Demo\Controller;use TYPO3\FLOW3\Mvc\Controller\CommandController;

class TestCommandController extends CommandController { /** * An example command * * @param string $requiredArgument This argument is required * @param string $optionalArgument This argument is optional * @return void */ public function exampleCommand($name) { $this->outputLine("Hello %s!", array($name)); }}

17

Page 18: FLOW3-Workshop F3X12

Das Wesentliche im Blick

Domain-Driven DesignEine Methode die ...

• zu aussagekräftigen Modellenverhilft

• eine gemeinsames Vokabularetabliert

• das Design von komplexen Anwendungen erleichtert

/** * 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; }}?>

18

Page 19: FLOW3-Workshop F3X12

Domain-Driven Design

Domain Aktivität oder Geschäftsdomäne des Nutzers

Domain-Driven Design bedeutet

• Fokus auf die Domäne und Domänen-Logik

• sorgfältiges Mapping der Konzepte auf das Model

• etablieren einer gemeinsamen Sprache innerhalbdes gesamten Projekt-Teams

19

Page 20: FLOW3-Workshop F3X12

Domain-Driven Design

Ubiquitous Language

• allgemeingegenwärtige Begriffe sind wichtig für die Kommunitation aller Beteiligten

• benutze dieselben Begriffe für

• Diskussionen

• Modeling

• Entwicklung

• Dokumentation

20

Page 21: FLOW3-Workshop F3X12

Domain-Driven Design

Standardwerk

Spannend undunterhaltsam

21

Page 22: FLOW3-Workshop F3X12

Object Management

Dependency Injection

• anstatt eine Instanz einer Klasse zu erzeugen oder sie aktiv zu holen, wird sie injected

• fördert lose Kopplung und starke Kohäsion

‣ stabilerer, wiederverwendbarer Code

22

Page 23: FLOW3-Workshop F3X12

Object Management

FLOW3's Ansatz für Dependency Injection

• eine der ersten PHP Implementierungen(2006 begonnen, seitdem ständig verbessert)

• Object Management für den gesamten Lebenszyklusaller Objekte

• keine unnötige Konfiguration wenn die Informationen automatisch ermittelt werden können (Autowiring)

• intuitive Nutzung ohne böse (magische) Überraschungen

• schnell! (wie selbstgemacht oder schneller)

23

Page 24: FLOW3-Workshop F3X12

<?php namespace Acme\Demo\Controller;

use TYPO3\FLOW3\MVC\Controller\ActionController;use Acme\Demo\Service\GreeterService;

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

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

Constructor Injection

24

Page 25: FLOW3-Workshop F3X12

Setter Injection

<?php namespace Acme\Demo\Controller;

use TYPO3\FLOW3\MVC\Controller\ActionController;use Acme\Demo\Service\GreeterService;

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

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

25

Page 26: FLOW3-Workshop F3X12

<?php namespace Acme\Demo\Controller;

use TYPO3\FLOW3\Annotations as FLOW3;use TYPO3\FLOW3\MVC\Controller\ActionController;use Acme\Demo\Service\GreeterService;

class DemoController extends ActionController { /** * @var \Acme\Demo\Service\GreeterService * @FLOW3\Inject */ protected $greeterService; /** * @param string $name */ public function helloAction($name) { return $this->greeterService->hello($name); }}

Property Injection

26

Page 27: FLOW3-Workshop F3X12

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

Objects.yaml

27

Page 28: FLOW3-Workshop F3X12

class Customer {

/** * @FLOW3\Inject * @var CustomerNumberGenerator */ protected $customerNumberGenerator;

...}

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

Object Management

28

Page 29: FLOW3-Workshop F3X12

Object Management

<?phpdeclare(ENCODING = 'utf-8');namespace Acme\Conference\Domain\Model\Conference;/** * Autogenerated Proxy Class * @TYPO3\FLOW3\Annotations\Scope(“prototype”) * @ TYPO3\FLOW3\Annotations\Entity */class Paper extends Paper_Original implements \TYPO3\FLOW3\Object\Proxy\ProxyInterface, \Acme\FLOW3\Persistence\Aspect\PersistenceMagicInterface { /** * @var string * @Doctrine\ORM\Mapping\Id * @Doctrine\ORM\Mapping\Column(length="40") * introduced by TYPO3\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 erzeugt Proxy Klassenum DI und AOP zu ermöglichen

• new Operator wird unterstützt

• Proxy Klassen werden on-the-fly erzeugt

• im Production Kontext ist sämtlicher Code statisch

29

Page 30: FLOW3-Workshop F3X12

Persistenz

Objekt Persistenz im Fluss

• basiert auf Doctrine 2

• nahtlose Integration in FLOW3

• bietet alle Doctrine 2 Features

• nutzt UUIDs

• Low Level Persistence API:

• ermöglichte eingene Persistenz Mechanismen (anstelle von Doctrine 2)

• CouchDB

30

Page 31: FLOW3-Workshop F3X12

Persistenz Basics

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

// Update a customer: $customer->setName("I, Robot"); $this->customerRepository->update($customer);

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

• Repository von FLOW3 per DI geben lassen

• Domänenobjekte (fast) wie ohne Framework behandeln

31

Page 32: FLOW3-Workshop F3X12

Doctrine und Validierung mit Annotations

namespace TYPO3\Blog\Domain\Model;use TYPO3\FLOW3\Annotations as FLOW3;use Doctrine\ORM\Mapping as ORM;

/** * @FLOW3\Entity */class Blog {

/** * @var string * @FLOW3\Validate(“Text”) * @FLOW3\Validate(type=”StringLength”, options={“minimum” = 1, “maximum” = 80}) * @ORM\Column(length=80) */ protected $title;

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

...

}

32

Page 33: FLOW3-Workshop F3X12

Persistenz-relevante Annotations

FLOW3\Entity Deklariert eine Klasse als "Entity"

ORM\Column Nimmt Einfluss auf das Datenbankfeld das mit der Class Property zusammenhängt. Besonders sinnvoll bei Text-Inhalten (type="text").

ORM\ManyToOne ORM\ OneToMany ORM\ ManyToManyORM\ OneToOne

Definiert Relationen zu Class-Properties anderer Entities. Im Gegensatz zu reinem Doctrine muss targetEntity nicht angegeben werden sondern wird aus der @var Annotation übernommen.

cascade kaskadiert Operationen auf alle zusammengehörigen Objekte innerhalb des Aggregates. Wird ebenfalls automatisch gesetzt.

33

Page 34: FLOW3-Workshop F3X12

Persistenz-relevante Annotations

var Definiert den Typ, Collections werden in spitzen Klammern definiert:\Doctrine\Common\Collections\Collection<\TYPO3\Conference\Domain\Model\Comment>

FLOW3\Transient Die Property wird ignoriert – also weder persistiert noch wiederhergstellt

FLOW3\Identity Markiert die Property als Teil der Identität

ORM\Id Definiert die Property, die als Primärschlüssel in der Datenbank dient. In FLOW3 wird dies automatisch im Hintergrund definiert.

34

Page 35: FLOW3-Workshop F3X12

Nutzung von Repositories

Das generische Basis-Repository unterstützt jedes Backend, das Doctrine-Basis-Repository bietet Zugriff auf Doctrine-Spezifika.

Die Nutzung der Basis-Repositories von FLOW3

• Stellt grundlegende Methoden breit:findAll(), countAll(), remove(), removeAll()

• Bietet automatische Methoden um nach Properties zu suchen:findByPropertyName($value), findOneByPropertyName($value)

Eigene, spezialisierte Finder-Methoden werden einfach dem eigenen Repository hinzugefügt.

35

Page 36: FLOW3-Workshop F3X12

Eigene Abfragen mit dem QOM

class PostRepository extends \FLOW3\Persistence\Repository {

/** * Finds most recent posts excluding the given post * * @param \TYPO3\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(\TYPO3\Blog\Domain\Model\Post $post, $limit = 20) { $query = $this->createQuery(); $posts = $query->matching($query->equals('blog', $post->getBlog())) ->setOrderings(array( 'date' => \TYPO3\FLOW3\Persistence\QueryInterface::ORDER_DESCENDING )) ->setLimit($limit) ->execute() ->toArray();

unset($posts[array_search($post, $posts)]); return $posts; }}

PostRepository.php

36

Page 37: FLOW3-Workshop F3X12

Eigene Abfragen mit DQL

class PostRepository extends \FLOW3\Persistence\Doctrine\Repository {

/** * Finds most recent posts excluding the given post * * @param \TYPO3\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(\TYPO3\Blog\Domain\Model\Post $post, $limit = 20) { // this is an alternative way of doing this when extending the Doctrine 2 // specific repository and using DQL. $query = $this->entityManager->createQuery('SELECT p FROM \TYPO3\Blog\Domain\Model\Post p WHERE p.blog = :blog AND NOT p = :excludedPost ORDER BY p.date DESC');

return $query ->setMaxResults($limit) ->execute(array('blog' => $post->getBlog(), 'excludedPost' => $post)); }}

PostRepository.php

37

Page 38: FLOW3-Workshop F3X12

Schema Management

Doctrine 2 Migrations

• Migrationen ermöglichen Schema Versionierung und das Deployment von Änderungen

• Migrationen sind der empfohlene Weg für Datanbank Anpassungen

• Kann auch zum Deplyoment und Update bestehender Daten genutzt werden

• Tools für das Erstellen und Deployen von Migrationen sind in FLOW3 enthalten

38

Page 39: FLOW3-Workshop F3X12

Schema Management

Ausführen von Migrationen

• notwendig nach Neuinstallation oder Upgrades:

$ ./flow3 doctrine:migrate

39

Page 40: FLOW3-Workshop F3X12

Schema Management

Migrations-Status prüfen

$ ./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: TYPO3\FLOW3\Persistence\Doctrine\Migrations >> Migrations Directory: /…/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

40

Page 41: FLOW3-Workshop F3X12

Schema Management

Migrationen erstellen

$ ./flow3 doctrine:migrationgenerateGenerated new migration class!

Next Steps:- Move …/Version20120329190824.php to YourPackage/Migrations/Mysql/- Review and adjust the generated migration.- (optional) execute the migration using ./flow3 doctrine:migrate

41

Page 42: FLOW3-Workshop F3X12

Schema Management

/** * Rename FLOW3 tables to follow FQCN */class Version20110824124835 extends AbstractMigration {

/** * @param Schema $schema * @return void */ public function up(Schema $schema) { $this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");

$this->addSql("RENAME TABLE flow3_policy_role TO typo3_flow3_security_policy_role"); $this->addSql("RENAME TABLE flow3_resource_resource TO typo3_flow3_resource_resource"); $this->addSql("RENAME TABLE flow3_resource_resourcepointer TO typo3_flow3_resource_resourcepointer"); $this->addSql("RENAME TABLE flow3_resource_securitypublishingconfiguration TO typo3_flow3_security_authorization_resource_securitypublis_6180a"); $this->addSql("RENAME TABLE flow3_security_account TO typo3_flow3_security_account"); }

Migrations-Dateien enthalten meist wirklich einfachen Code

42

Page 43: FLOW3-Workshop F3X12

Schema Management

$ ./flow3 doctrine:create

$ ./flow3 doctrine:update

Schema aktualisieren ohne Migrations zu verwenden

• Für mache Situationen reichen Updates ohne Migrations

• Hilfreich bei

• der Nutzung existierender Datenbank-Dumps

• fehlenden Migrations für die genutzte Datenbank

• SQLite (beschränkte Unterstützung für Schema-Änderungen)

43

Page 44: FLOW3-Workshop F3X12

Templating-Zen

FLOW3 bietet eine elegante, flexible und sichere Templating-Engine: Fluid

• Templates sind valides HTML

• Templates enthalten keinen PHP-Code

• Object-Zugriff, Kontrollstrukturen, Schleifen…

• Designer-Kompatibel

• Erweiterbar (ViewHelper, Widgets)

44

Page 45: FLOW3-Workshop F3X12

Fluid

Beispiel einer String-Zuweisung an eine Fluid-Variable:

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

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

45

Page 46: FLOW3-Workshop F3X12

Fluid

Variablen können auch Objekte sein:

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

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

46

Page 47: FLOW3-Workshop F3X12

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

47

Page 48: FLOW3-Workshop F3X12

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

48

Page 49: FLOW3-Workshop F3X12

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

49

Page 50: FLOW3-Workshop F3X12

Fluid

ViewHelper – hier der link.action ViewHelper:

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

50

Page 51: FLOW3-Workshop F3X12

Formulare

<?phpnamespace TYPO3\Blog\Domain\Model;

/** * A blog post * * @FLOW3\Scope(“prototype”) * @FLOW3\Entity */class Post {

/** * @var string * @FLOW3\Validate(type=“StringLength”, options={“minimum” = 10}) */ protected $title;

/** * @var string * @FLOW3\Validate(type=“StringLength”, options={“maximum” = 50}) */ protected $author;

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

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

51

Page 52: FLOW3-Workshop F3X12

Formulare

<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.textfield 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.textfield property="image.title" value="My image title" /> <f:form.upload property="image.originalResource" /></f:form>

52

Page 53: FLOW3-Workshop F3X12

Formulare

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

class PostController extends ActionController {

/** * @FLOW3\Inject * @var \TYPO3\Blog\Domain\Repository\PostRepository */ protected $postRepository;

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

}?>

53

Page 54: FLOW3-Workshop F3X12

Validierung

Validierung behandelt verschiedene Dinge

• hereinkommende Daten müssen abgesichert werden

• kein böses Markup in Content vom Client

• Die Integrität des Domain Model muss sichergestellt werden

• Eine E-Mail muss (syntaktisch) korrekt sein

• Kreditkarten-Nummern sollten nur aus Zahlen bestehen

54

Page 55: FLOW3-Workshop F3X12

Validierung

Validierung in FLOW3

• keiner möchte solche Prüfungen in seinen Controllern implementieren

• FLOW3 trennt die Validierung von den Aufgaben des Controllers

• kein PHP-Code für die Validierung notwendig

• Regeln werden durch Annotations definiert

55

Page 56: FLOW3-Workshop F3X12

Validierung

Validierungs-Modelle

• Base PropertiesMinimale Anforderungen an individuelle Properties eines Models

• Base ModelMinimale Anforderungen an eine Kombination von Properties eines Models, Prüfung ggf. durch eigenen Validator

• SupplementalZusätzliche Anforderungen an ein Model in spezifischen Situationen (z.B. für eine bestimmte Action-Methode)

56

Page 57: FLOW3-Workshop F3X12

Validierung

Base Properties

• Validierungsregeln direkt an den Properties

/** * @var string * @FLOW3\Validate(type=”StringLength”, options={“minimum” = 10}) */ protected $title;

/** * @var string * @FLOW3\Validate(type=”StringLength”, options={“maximum” = 50}) */ protected $author;

57

Page 58: FLOW3-Workshop F3X12

Validierung

Validatoren

• Validatoren aus FLOW3 mit verkürztem Namen ansprechen

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

• Eigene Validatoren müssen das ValidatorInterface implementieren

• Um sie zu nutzen, den fully qualified class name angeben

/** * @var \My\Stuff\Domain\Model\Stuff * @FLOW3\Validate(type=”My\Stuff\Domain\Validator\StuffValidator”) */ protected $stuff;

58

Page 59: FLOW3-Workshop F3X12

Property Mapper

Eigenschaften von A nach B übertragen

• ermöglicht komplette oder teilweise Kopien von Objekten und Objektstrukturen

• wird vom MVC-Framework für das Mapping von rohen GET- und POST-Argumenten auf Argument-Objekte verwendet

59

Page 60: FLOW3-Workshop F3X12

Property Mapper

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

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

60

Page 61: FLOW3-Workshop F3X12

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>

Bilder Upload

Resourcen werden wie andere Properties auch in Formular eingebunden::

61

Page 62: FLOW3-Workshop F3X12

Property Mapper

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

->allowCreationForSubProperty('authorPicture'); $this->arguments['blog']->getPropertyMappingConfiguration()

->allowModificationForSubProperty('authorPicture'); }

Verschachtelte Objektstrukturen erlauben

Aus Sicherheitsgründen ist dies standardmäßig abgeschaltet

62

Page 63: FLOW3-Workshop F3X12

Security

Touchless Security, Flow-Style

• Security wird zentralisiert umgesetzt (durch AOP)

• Basiert auf unseren Erfahrungen im TYPO3-Projekt und der Spring Security (Java framework)

• Bietet Authentifizierung, Authorisierung, Rollen, ACLs, …

• Kann beliebige Methoden-Aufrufe abfangen

• Filtert den Zugriff auf Content durch das Umschreiben von Abfragen in der Persistenz

• Erweiterbar um neue Mechanismen zu Authentifizierung und Authorisierung

63

Page 64: FLOW3-Workshop F3X12

Security Policy

# ## Security policy definition ## ## This file contains the security policy configuration for the ## Conference package #

resources: methods: TYPO3_Conference_AccountActions: 'method(TYPO3\Conference\Controller\Account\(Overview|SpeakerProfile)Controller->.*Action())' TYPO3_Conference_MyPapersActions: 'method(TYPO3\Conference\Controller\Conference\PaperController->(myPapers|show|new|create|edit|update|submit|delete)Action())' TYPO3_Conference_PaperReviewActions: 'method(TYPO3\Conference\Controller\Conference\PaperController->(review|show|edit|update|voting|updateVote)Action())' TYPO3_Conference_PaperVotingResultActions: 'method(TYPO3\Conference\Controller\Conference\PaperController->(votingResults|acceptPapers|export)Action())'

roles: Conference_Visitor: [] Speaker: [Conference_Visitor] ConfirmedSpeaker: [Conference_Visitor] TrackChair: [Conference_Visitor] Administrator: [Conference_Visitor]

acls: Conference_Visitor: methods: TYPO3_Conference_AccountActions: GRANT Speaker: methods: TYPO3_Conference_MyPapersActions: GRANT TrackChair: methods: TYPO3_Conference_PaperReviewActions: GRANT Administrator: methods: TYPO3_Conference_PaperReviewActions: GRANT TYPO3_Conference_PaperVotingResultActions: GRANT

64

Page 65: FLOW3-Workshop F3X12

Security

Cross-Site Request Forgery

• ermöglicht einem Angreifer die Ausführung privilegierter Operationen ohne selbst authentifiziert zu sein

• die Gefahr liegt in der Nutzung von manipulierten Links oder Formularen während man am System angemeldet ist

• URL-Shortener bieten eine gute Basis für solche Angriffe…

65

Page 66: FLOW3-Workshop F3X12

Security

Cross-Site Request Forgery verhindern

• Ein (wirklich!) zufälliges Token an jeden Link und jedes Formular anhängen

• und die Korrektheit dieses Tokens vor jeder Aktion überprüfen

• Das Token so oft wie möglich ändern um zu verhindern das ein gültiger Link geschickt werden kann während der Benutzer angemeldet ist

• In den meisten Fällen reicht es aus, bei jedem Login ein neues Token zu erzeugen – das ist die Standard-Einstellung in FLOW3

66

Page 67: FLOW3-Workshop F3X12

Security

CSRF-Schutz in FLOW3

• Man darf das Token nie vergessen

• FLOW3 fügt das CSRF-Token automatisch zu jedem

• Link der generiert wird und

• jedem mit Fluid erzeugten Formular hinzu

• und prüft das Token vor jeder Action-Methode

• Der CSRF-Schutz kann durch @FLOW3\SkipCsrfProtection je Methode abgeschaltet werden

67

Page 68: FLOW3-Workshop F3X12

AOP

Aspekt-Orientierte Programmierung

• ist ein Programmier-Paradigma

• kapselt Zuständigkeiten um die Modularisierung zu verbessern

• OOP modularisiert Zuständigkeiten in Objekte

• AOP modularisiert cross-cutting concerns in Aspekten

• FLOW3 macht die Nutzung von AOP in PHP einfach (und überhaupt erst möglicht)

68

Page 69: FLOW3-Workshop F3X12

AOP

FLOW3 nutzt AOP für ...

• Persistenz

• Logging

• Debugging

• Security

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

*/class PersistenceMagicAspect { /** * @pointcut classTaggedWith(entity) || classTaggedWith(valueobject) */ public function isEntityOrValueObject() {} /** * @var string * @Id * @Column(length="40") * @introduce TYPO3\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 \TYPO3\FLOW3\AOP\JoinPointInterface $joinPoint The current join point

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

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

}

69

Page 70: FLOW3-Workshop F3X12

Signal-Slot Event Handling

Signal

• kann jederzeit ausgelöst werden

• kann frei vom Entwickler definiert werden

Slot

• wird aufgerufen wenn ein Signal ausgelöst wurde

• jede Methode kann als Slot genutzt werden

Jedes Signal kann mit jedem Slot verbunden werden

70

Page 71: FLOW3-Workshop F3X12

Signal-Slot Event Handling

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

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

71

Page 72: FLOW3-Workshop F3X12

Signal-Slot Event Handling

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

Im Bootstrap werden Signals mit Slots verdrahtet:

72

Page 73: FLOW3-Workshop F3X12

Signal-Slot Event Handling

/** * @param \TYPO3\Blog\Domain\Model\Comment $comment * @param \TYPO3\Blog\Domain\Model\Post $post * @return void */ public function sendNewCommentNotification( \TYPO3\Blog\Domain\Model\Comment $comment, \TYPO3\Blog\Domain\Model\Post $post) { $mail = new \TYPO3\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(); }

Jede Methode kann ein Slot sein:

73

Page 74: FLOW3-Workshop F3X12

Signal-Slot Event Handling

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

Slots können auch statische Methoden sein:

74

Page 75: FLOW3-Workshop F3X12

Speed und Performance

Für den ungeduldigen Nutzer:

• multi-layered, tagged Caches

• Diverse Cache-Backends (File, Memcached, APC, Redis, PDO, ...)

• Unterstützung für Reverse-Proxy (Varnish, ESI) ist in Arbeit

• Code-Kompilierung

• Regelmäßige Benchmarks

• Fokus auf gute Skalierbarkeit

75

Page 76: FLOW3-Workshop F3X12

Mehr Features

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

• Logging

• File Monitoring

• Configuration Management

• Routing

• REST / SOAP

• ...

76