TYPO3 Flow and the Joy of Development (FOSDEM 2013)

Post on 19-May-2015

26.934 views 1 download

description

Six years ago, the TYPO3 community was seeking for a framework as a foundation for their new CMS. There was none satisfying their wishlist of features and architecture and thus a new one was made - top notch, built without the pressure of day to day work. In the meantime TYPO3 Flow has become one of the “serious” PHP frameworks which is built on two paradigms: harness the complexity of enterprise applications but at the same time be concise and developer friendly. Or in short: Flow brings back the joy of development in PHP. This session introduces some of the main features of TYPO3 Flow 2.0 and gives you an idea about how it relates to the well established frameworks on the market.

Transcript of TYPO3 Flow and the Joy of Development (FOSDEM 2013)

The Joy of Development

TEXT HERE

project founder ofFlow and Neos

coach, coder, consultant

Lübeck, Germany

1 wife, 2 daughters, 1 espresso machine

likes drumming

2005

modelviewcontroller

HTTP

Network Working Group R. FieldingRequest for Comments: 2616 UC IrvineObsoletes: 2068 J. GettysCategory: Standards Track Compaq/W3C J. Mogul Compaq H. Frystyk W3C/MIT L. Masinter Xerox P. Leach Microsoft T. Berners-Lee W3C/MIT June 1999

Hypertext Transfer Protocol -- HTTP/1.1

Status of this Memo

This document specifies an Internet standards track protocol for the Internet community, and requests discussion and suggestions for improvements. Please refer to the current edition of the "Internet Official Protocol Standards" (STD 1) for the standardization state and status of this protocol. Distribution of this memo is unlimited.

Copyright Notice

Copyright (C) The Internet Society (1999). All Rights Reserved.

Abstract

The Hypertext Transfer Protocol (HTTP) is an application-level protocol for distributed, collaborative, hypermedia information systems. It is a generic, stateless, protocol which can be used for many tasks beyond its use for hypertext, such as name servers and distributed object management systems, through extension of its request methods, error codes and headers [47]. A feature of HTTP is the typing and negotiation of data representation, allowing systems to be built independently of the data being transferred.

HTTP has been in use by the World-Wide Web global information initiative since 1990. This specification defines the protocol referred to as "HTTP/1.1", and is an update to RFC 2068 [33].

HTTP/1.1 has been designed to allow implementations of applications that do not depend on knowledge of ranges.

4 HTTP Message

4.1 Message Types

HTTP messages consist of requests from client to server and responses from server to client.

HTTP-message = Request | Response ; HTTP/1.1 messages

Request (section 5) and Response (section 6) messages use the generic message format of RFC 822 [9] for transferring entities (the payload of the message). Both types of message consist of a start-line, zero or more header fields (also known as "headers"), an empty line (i.e., a line with nothing preceding the CRLF) indicating the end of the header fields, and possibly a message-body.

generic-message = start-line *(message-header CRLF) CRLF [ message-body ] start-line = Request-Line | Status-Line

In the interest of robustness, servers SHOULD ignore any empty line(s) received where a Request-Line is expected. In other words, if the server is reading the protocol stream at the beginning of a message and receives a CRLF first, it should ignore the CRLF.

Certain buggy HTTP/1.0 client implementations generate extra CRLF's after a POST request. To restate what is explicitly forbidden by the BNF, an HTTP/1.1 client MUST NOT preface or follow a request with an extra CRLF.

/** * Represents a HTTP request */class Request extends Message {

/** * @var string */ protected $method = 'GET';

/** * @var \TYPO3\Flow\Http\Uri */ protected $uri;

/** * @var \TYPO3\Flow\Http\Uri */ protected $baseUri;

/** * @var array */ protected $arguments;

/** * @var array<\TYPO3\Flow\Http\Cookie> */ protected $cookies;

/** * Data similar to that which is typically provided by $_SERVER * * @var array */ protected $server;

/** * The "http" settings * * @var array */ protected $settings;

/** * URI for the "input" stream wrapper which can be modified for testing purposes * * @var string */ protected $inputStreamUri = 'php://input';

/** * Constructs a new Request object based on the given environment data. * * @param array $get Data similar to that which is typically provided by $_GET * @param array $post Data similar to that which is typically provided by $_POST * @param array $files Data similar to that which is typically provided by $_FILES * @param array $server Data similar to that which is typically provided by $_SERVER

$request->getHeader('User-Agent'); # C64

$request->setHeader('X-Coffee', 'too few');

$now = new \DateTime();$response->setLastModified($now);

$response->getHeaders()->setCacheControlDirective('s-max-age', 100);

# set cookie in response:$response->setCookie(new Cookie('counter', 1));

# on next request, retrieve cookie:$cookie = $request->getCookie('counter');

$response = $browser->request('http://robertlemke.com/home');$content = $response->getContent();

$request = Request::create($storageUri, 'PUT');$request->setContent(fopen('myfavoritemovie.m4v', 'rb'));$request->setHeader('X-Category', 'Sissy');

$reponse = $browser->sendRequest($request);

Model

/** * A Book * * @Flow\Scope(“prototype”) * @Flow\Entity */class Book {

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

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

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

/** * @var integer */ protected $price;

* @author Robert Lemke <robert@typo3.org> */ public function __construct() { $this->materials = new \SplObjectStorage; }

Domain-Driven DesignA methodology which ...

• results in rich domain models

• provides a common language across the project team

• simplify the design of complex applications

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

<?phpnamespace RoeBooks\Shop\Domain\Model;use TYPO3\Flow\Annotations as Flow;use Doctrine\ORM\Mapping as ORM;

/** * A Book * * @Flow\Entity */class Book {

/** * The title * @var string * @Flow\Validate(type="StringLength", options={ "minimum"=1, "maximum"=100 }) */ protected $title;

/** * The price * @var integer * @Flow\Validate(type="NumberRange", options={ "minimum"=1, "maximum"=1000 }) */ protected $price;

/** * The description * @var string * @ORM\Column(type="text") */ protected $description;

/** * Get the Book's title * * @return string The Book's title */ public function getTitle() { return $this->title; }

/** * Sets this Book's title * * @param string $title The Book's title * @return void */ public function setTitle($title) { $this->title = $title; }

/** * A repository for Books * * @Flow\Scope("singleton") */class BookRepository extends Repository {

public function findBestSellers() { ... }

}

# Add a book$bookRepository->add($book);

# Remove a book$bookRepository->remove($book);

# Update a book$bookRepository->update($book);

# Find one specific book$book = $bookRepository->findOneByTitle('Lord of the Rings');

# Find multiple books by property$books = $bookRepository->findByCategory('Fantasy');

# Find books through custom find method$bestsellingBooks = $bookRepository->findBestSellers();

TEXT HERE

TEXT HERE

Controller

class HelloWorldController extends ActionController {

/** * @return string */ public function greetAction() { return 'Hello World!'; }

}

TEXT HERE

Hello World!

/** * An action which sends greetings to $name * * @param string $name The name to mention * @return string */ public function greetAction($name) { return "Hello $name!"; }

Hello Robert!

dev.demo.local/acme.demo/helloworld/greet.html?name=Robertdev.demo.local/acme.demo/helloworld/greet.html?name=Robert

View

<html lang="en"> <head> <title>Templating</title> </head> <body>

Our templating engineis called

Fluid </body></html>

/** * @param string $name * @return void */ public function greetAction($name) { $this->view->assign('name', $name); }

<html> <head> <title>Fluid Example</title> </head> <body> <p>Hello, {name}!</p> </body></html>

/** * Displays a list of best selling books * * @return void */public function indexAction() { $books = $this->bookRepository->findBestSellers(); $this->view->assign('books', $books);}

<ul> <f:for each="{books}" as="book"> <li>{book.title} by {book.author.name}</li> </f:for></ul>

<html xmlns:f="http://typo3.org/ns/TYPO3/Fluid/ViewHelpers">

<f:form action="create" name="newBook"> <ol> <li> <label for="name">Name</label> <f:form.textfield property="name" id="name" /> </li> <li> <f:form.submit value="Create" /> </li> </ol></f:form>

/** * Adds the given new book to the BookRepository * * @param \Acme\Demo\Domain\Model\Book $newBook * @return void */ public function createAction(Book $newBook) { $this->bookRepository->add($newBook); $this->addFlashMessage('Created a new book.'); $this->redirect('index'); }

Resources

Static Resources

Static Resources

Static Resources

Persistent Resources

Persistent Resources

Dependency Injection

<?php

class SomeService { protected static $instance; public function getInstance() { if (self::$instance === NULL) { self::$instance = new self; } return self::$instance; }}

class SomeOtherController { public function action() { $service = SomeService::getInstance(); … } }

?>

class ServiceLocator { protected static $services = array(); public function getInstance($name) { return self::$service[$name]; }

}

class SomeOtherController { public function action() { $service = ServiceLocate::getInstance("SomeService"); … } }

Flow'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)

class BookController extends ActionController {

/** * @var BookRepository */ protected $bookRepository; /** * @param BookRepository $bookRepository */ public function __construct(BookRepository $bookRepository) { $this->bookRepository = $bookRepository; } }

class BookController extends ActionController {

/** * @var BookRepository */ protected $bookRepository; /** * @param BookRepository $bookRepository */ public function injectBookRepository(BookRepository $bookRepository) { $this->bookRepository = $bookRepository; } }

class BookController extends ActionController {

/** * @Flow\Inject * @var BookRepository */ protected $bookRepository;

}

Aspect-Oriented Programming

/** * An action which sends greetings to $name * * @param string $name The name to mention * @return string */ public function greetAction($name) { return "Hello $name!"; }

Hello Robert!

dev.demo.local/acme.demo/helloworld/greet.html?name=Robertdev.demo.local/acme.demo/helloworld/greet.html?name=Robert

/** * @Flow\Aspect */class DemoAspect {

/** * @param \TYPO3\Flow\Aop\JoinPointInterface $joinPoint * @return void * @Flow\Around("method(.*->greetAction())") */ public function demoAdvice(JoinPointInterface $joinPoint) { $name = $joinPoint->getMethodArgument('name'); return sprintf('%s, you are running out of time!'); }}

Robert, you are running out of time!

dev.demo.local/acme.demo/helloworld/greet.html?name=Robertdev.demo.local/acme.demo/helloworld/greet.html?name=Robert

Security

resources: methods: BookManagementMethods: 'method(.*Controller->(new|create|edit|update|delete)Action())'

roles: Customer: [] Administrator: []

acls: Administrator: methods: BookManagementMethods: GRANT

Access Denied (in Development context)

Sessions

/** * A Basket * * @Flow\Scope("session") */class Basket { /** * The books * @var array */ protected $books; /** * Adds a book to the basket * * @param \RoeBooks\Shop\Domain\Model\Basketook $book * @return void * @Flow\Session(autoStart=true) */ public function addBook (Book $book) { $this->books[] = $book; }

TEXT HERE

TEXT HERE

TEXT HERE

Rossmann

• second biggest drug store in Germany

• 5,13 billion ! turnover

• 31,000 employees

Customer Database

Amadeus

•world’s biggest e-ticket provider

• 217 markets

• 948 million billable transactions / year

• 2,7 billion ! revenue

Social Media Suite

World of Textile

• textile print and finishing

• 30,000 articles / day

• 180 employees

E-Commerce Platform

2.0

neos.typo3.org

?