The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation...

259

Transcript of The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation...

Page 1: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 2: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 3: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The format – Talks then Hacking

Follow along with the sandbox

Page 4: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

What is Symfony2?

Page 5: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

A web framework

Page 6: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

A web framework is a software that providesgeneric components that ease application development

and team work.

Page 7: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

A framework helps developers create flexible and extensible applications, write quality and maintainable code.

Page 8: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Symfony2 is built on top of PHP 5.3

It especially uses the new namespace system

Page 9: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 10: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

git clone https://github.com/jmikola/top-shelf-php.git

Page 11: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

IDEs Integration

Eclipse: https://github.com/pulse00/Twig-Eclipse-Plugin

Netbeans: https://github.com/blogsh/Twig-netbeans

PHPStorm: As of 2.1

VIM: http://jinja.pocoo.org/2/documentation/integration

TextMate: https://github.com/Anomareh/PHP-Twig.tmbundle

Page 12: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Install the standard distribution

Page 13: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

php app/check.php

Requirements checks

Page 14: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 15: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 16: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

# web/app_dev.phprequire_once __DIR__.'/../app/AppKernel.php';

use Symfony\Component\HttpFoundation\Request;

$kernel = new AppKernel('dev', true);$kernel->handle(Request::createFromGlobals())->send();

The front controller is the single entry point of the application

The front controller

Page 17: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

http://www.domain.tld/web/app_dev.php/

http://www.domain.tld/web/app_dev.php/hello/Fabien

http://www.domain.tld/web/app_dev.php/hello/Toto

The front controller

Every resource the user wants to access is available from the front controller

Page 18: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

http://www.domain.tld/

http://www.domain.tld/hello/Fabien

http://www.domain.tld/hello/Toto

If the virtual host is correctly configured to make the web/ folder as the web root directory, URI becomes as follow.

The front controller

Page 19: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

<VirtualHost *:80> ServerName www.domain.tld DocumentRoot "/path/to/sandbox/web" DirectoryIndex app.php <Directory "/path/to/sandbox/web"> AllowOverride All Allow from All </Directory></VirtualHost>

Production configuration sample for Apache

In production environment, make sure your Apache is configured to make the web/ folder as the web root directory of your application.

Page 20: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

# web/.htaccess<IfModule mod_rewrite.c>

RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ app.php [QSA,L]

</IfModule>

Production configuration sample for Apache

The web/.htaccess file redirects every request on the front controller.

Page 21: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 22: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

๏ app/ is the application folder

๏ src/ is the libraries folder

๏ web/ is the general public folder

The app/ folder contains the configuration and generated files

The src/ folder contains the PHP code

The web/ folder contains front controllers and web assets (images, Javascripts, stylesheets, ...)

.|-- LICENSE|-- README|-- app/| |-- AppCache.php| |-- AppKernel.php| |-- cache/| |-- config/| |-- console| |-- logs/| |-- autoload.php| |-- check.php| `-- phpunit.xml.dist|-- bin/|-- src/| `-- Acme/|-- vendor/`-- web/ |-- config.php |-- app.php `-- app_dev.php

Architecture

Page 23: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

web/should be the web root directory

app/cache/ and app/logs/

must be writable by the web server

Architecture

Page 24: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

An Application is a directorycontaining the configurationfor a given set of Bundles

Architecture

Page 25: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

A Bundle is a structured set of files(PHP files, stylesheets, JavaScripts, images, ...)

that implements a single feature (a blog, a forum, ...)and which can be easily shared with other developers.

Architecture

Page 26: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Accessing a Resource

Page 27: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Simply browse the following URIhttp://…/…/app_dev.php/hello/Fabien

Virtual path to the resource the user wants to access

Page 28: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Symfony2 provides a routing mechanism that converts a typical URI into a web response

Page 29: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

๏To link URIs to the application internal actions

๏To improve SEO optimizations and bookmarks

๏To be able to create or change URIs with ease

๏To avoid to show sensible information

๏To give meaningful URIs to the end user

Architecture

Page 30: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

๏They show sensible information

๏They mention variable names and values

๏They are not meaningful and optimized for SEO engines

http://www.domain.com/blog.php?action=show&article_id=123

Default URLs have some problems…

Page 31: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

๏Clean and smart URIs to give meaningful information

๏No sensible information or variables

๏Easy URIs configuration in YAML, PHP or XML

http://www.domain.com/blog/2010/09/15/symfony2-rocks

URL rewriting is better !

Page 32: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The Router is responsible to match

a Pattern with a corresponding Controller.

Page 33: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The Router is responsible to match

a Pattern with a corresponding Controller.

Page 34: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

A Controller is responsible to process a

Request and to return a Response

Page 35: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

How does the routing work?

Page 36: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 37: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 38: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 39: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

How to process a request?

Page 40: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The controller is responsible to convert a request into a response

Generating a response

namespace Sensio\HelloBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpFoundation\Response;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class HelloController extends Controller{ /** @Route("/hello/{name}", name="greet") */ public function indexAction($name) { return new Response(sprintf('Hello %s!', $name)); }}

Page 41: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

namespace Sensio\HelloBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class HelloController extends Controller{ /** @Route("/hello/{name}", name="greet") */ public function indexAction($name) { return $this->render('SensioHelloBundle:Hello:index.html.twig', array( 'name' => $name )); }}

Generating a response

Unlike previous examples, the render() method decouples the application logic of the controller from the rendering of the view layer.

Page 42: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class HelloController extends Controller{ /** * @Route("/hello/{name}", name="greet") * @Template("SensioHelloBundle:Hello:index.html.twig") */ public function indexAction($name) { return array('name' => $name); }}

Variables will be sent to the template thanks to the array

Generating a response

The rendered template can also be mapped with a special annotation coming from the SensioFrameworkExtraBundle bundle.

Page 43: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Variables will be sent to the template thanks to the array

Generating a response

If the logical path to the template follows the following naming convention (BundleName:ControllerName:actionName.html.twig), the logical path can be omitted from the @Template annotation.

class HelloController extends Controller{ /** * @Route("/hello/{name}", name="greet") * @Template() */ public function indexAction($name) { return array('name' => $name); }}

The route name to generate links or uris.

Page 44: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 45: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Diving into the view layer

Page 46: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Twig fundamentals

Page 47: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

What is Twig?

Twig is a modern template engine for PHP

Fast: Twig compiles templates down to plain optimized PHP code. The overhead compared to regular PHP code was reduced to the very minimum.

Secure: Twig has a sandbox mode to evaluate untrusted template code. This allows Twig to be used as a template language for applications where users may modify the template design.

Flexible: Twig is powered by a fexible lexer and parser. This allows the developer to define its own custom tags and filters, and create its own DSL.

Page 48: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Twig has several tags (markers) to indicate the parser how to process the code. Every marker starts by an opening brace character – {– and ends with a closing brace – } .

Tag Meaning

{{ a_variable }} Outputs an escaped string

{# Some commented code #} Comments a piece of code

{% if glass is empty %} Evaluates an expression (block, loop, condition…)

Twig syntax

Page 49: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Simply use the double curly braces statement, {{ }}, which is equivalent to the echo / print statement in PHP.

{{ }} always outputs something!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"><html lang="en"> <head> <title>My Webpage</title> </head> <body> <p> Hello, my name is {{ name }}! </p> </body></html>

Printing variables

Page 50: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Twig accepts the following syntax to deal with both objects and arrays

# foo is an array|object and bar a valid index|property|method{{ foo.bar }}

# foo is an array and 0 a valid index# foo is an object that implements ArrayAccess interface{{ foo.0 }}

# foo is an array and bar a valid index.# foo is an object that implements ArrayAccess interface{{ foo['bar'] }}

# bar is a variable containing the index in the foo array{{ foo[bar] }}

Dealing with objects and arrays

Page 51: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

When using foo.bar

Check if foo is an array and bar a valid element;

If not, and if foo is an object, check that bar is a valid property;

If not, and if foo is an object, check that bar is a valid method;

if bar is the constructor - use __construct() instead;● If not, and if foo is an object, check that getBar is a valid method;● If not, and if foo is an object, check that isBar is a valid method;● If not, return a null value.

How Twig deals with variables?

Page 52: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

When using foo[‘bar’]

Check if foo is an array and bar a valid element;

If not, return a null value.

# foo is an array and 0 a valid index{{ foo.0 }}

# foo is an array and bar a valid index.{{ foo['bar'] }}

# bar is a variable containing the index in the foo array{{ foo[bar] }}

How Twig deals with variables?

Page 53: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The « for » statement loops over each item in a sequence. For example, to display a list of users provided in a variable called users:

The for() loop accepts any array or objects that implements the Traversable interface.

<h1>Members</h1>

<ul> {% for user in users %} <li>{{ user.username }}</li> {% endfor %}</ul>

For loop

Page 54: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Iterating over a sequence of numbers

Iterating over a sequence of letters

The .. operator can take any expression at both sides.

If you need a step different from 1, you can use the range function instead.

{% for i in 0..10 %} * {{ i }}{% endfor %}

{% for letter in 'a'..'z' %} * {{ letter }}{% endfor %}

{% for letter in 'a'|upper..'z'|upper %} * {{ letter }}{% endfor %}

{% for i in range(0, 10, 2) %} * {{ i }}{% endfor %}

For loop

Page 55: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Inside of a for loop block you can access some special variables. Instead, note that you can’t break or continue in a loop.

loop.index The current iteration of the loop. (1 indexed)

loop.index0 The current iteration of the loop. (0 indexed)

loop.revindex The number of iterations from the end of the loop (1 indexed)

loop.revindex0 The number of iterations from the end of the loop (0 indexed)

loop.first True if first iteration

loop.last True if last iteration

loop.length The number of items in the sequence

loop.context The parent context

For loop

Page 56: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

If the array is empty or null, you can output something else instead.

If you want to iterate over the array keys, simple use the keys filter.

<ul>

{% for user in users %} <li>{{ user.username }}</li> {% else %} <li><em>no user found</em></li> {% endfor %}

</ul>

<h1>Members</h1>

<ul>

{% for key in users|keys %} <li>{{ key }}</li> {% endfor %}

</ul>

For loop

Page 57: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Of course, you can grab both key and value in a row.

<h1>Members</h1>

<ul>

{% for key, user in users %} <li>{{ key }}: {{ user.username }}</li> {% endfor %}

</ul>

For loop

Page 58: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Twig also brings an « if » conditional statement to perform decisions.

The « is defined » statement is called a « test » in Twig vocabulary. It checks that the variable is defined or not.

{% if users is defined %} <ul> {% for user in users %} <li>{{ user.username }}</li> {% endfor %} </ul>{% endif %}

Conditional statements

Page 59: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Of course, you can expand the « if » conditional statement to « elseif » and « else » clauses as shown in the following snippet.

{% if kenny.sick %}

Kenny is sick.

{% elseif kenny.dead %}

You killed Kenny! You bastard!!!

{% else %}

Kenny looks okay --- so far

{% endif %}

Conditional statements

Page 60: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Experimenting Twig

Page 61: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 62: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The controller

Implement your first controller to render « Hello World ».

# src/Acme/TodoBundle/Controller/DefaultController.phpnamespace Sensio\Bundle\TrainingBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpFoundation\Response;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class DefaultController extends Controller{ /** @Route("/hello/{name}", name="greet") */ public function indexAction($name) { return new Response(sprintf('Hello %s!', $name)); }}

Page 63: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 64: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 65: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 66: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Simplify the action code by adding a new extra annotation to the method php documentation to specify which template to render.

# src/Acme/TodoBundle/Controller/DefaultController.phpuse Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class DefaultController extends Controller{ /** * @Route("/hello/{name}", name="greet") * @Template("AcmeTodoBundle:Default:index.html.twig") */ public function indexAction($name) { return array('name' => $name); }}

Page 67: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Simplify the @Template annotation to let Symfony guess the template to render based on coding convention.

# src/Acme/TodoBundle/Controller/DefaultController.phpuse Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class DefaultController extends Controller{ /** * @Route("/hello/{name}", name="greet") * @Template() */ public function indexAction($name) { return array('name' => $name); }}

Page 68: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 69: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 70: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 71: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 72: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 73: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 74: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 75: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 76: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Assetic presented by Kris WallsmithAsset Management for PHP 5.3

Page 77: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Lots of awesome tools:CoffeeScript

Compass Framework

CSSEmbed

Google Closure Compiler

JSMin

LESS

Packer

SASS

Sprockets

Stylus

YUI Compressor

Page 78: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Assetic makes using these easy

Page 79: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

# /path/to/web/js/core.php$core = new FileAsset('/path/to/jquery.js');

$core->load();

header('Content-Type: text/javascript');

echo $core->dump();

Page 80: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

# /path/to/web/js/core.php

$core = new AssetCollection(array(

new FileAsset('/path/to/jquery.js'),

new GlobAsset('/path/to/js/core/*.js'),

));

$core->load();

header('Content-Type: text/javascript');

echo $core->dump();

Page 81: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

# /path/to/web/js/core.php

$core = new AssetCollection(array(

new FileAsset('/path/to/jquery.js'),

new GlobAsset('/path/to/js/core/*.js'),

), array(

new YuiCompressorJsFilter('/path/to/yui.jar'),

));

$core->load();

header('Content-Type: text/javascript');

echo $core->dump();

Page 82: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

<script src="js/core.php"></script>

Page 83: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Assetic isAssets & Filters

Filters

Page 84: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Inspired by Python’s webassets

https://github.com/miracle2k/webassets

Page 85: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Assets have lazy, mutable content

Page 86: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

A filter acts on an asset’s contents during “load”

and “dump”

Page 87: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Assets can be gathered in collections

Page 88: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

A collection is an asset

Page 89: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 90: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Basic Asset Classes•AssetCollection

•AssetReference

•FileAsset

•GlobAsset

•HttpAsset

•StringAsset

Page 91: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Core Filter ClassesCoffeeScriptFilter

CompassFilter

CssEmbedFilter

CssImportFilter

CssMinFilter

CssRewriteFilter

GoogleClosure\CompilerApiFilter

GoogleClosure\CompilerJarFilter

JpegoptimFilter

JpegtranFilter

LessFilter

LessphpFilter

OptiPngFilter

PackagerFilter

Page 92: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Core Filter ClassesPngoutFilter

Sass\SassFilter

Sass\ScssFilter

SprocketsFilter

StylusFilter

Yui\CssCompressorFilter

Yui\JsCompressorFilter

More to come…

Page 93: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Twig Integration

Page 94: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

{% javascripts 'js/*.coffee' filter='coffee,?yui_js' %}

<script src="{{ asset_url }}"></script>

{% endjavascripts %}

Page 95: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

<script src="js/92429d8.js"></script>

Page 96: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

{% javascripts 'js/*.coffee' filter='coffee,?closure'

debug=true %}

<script src="{{ asset_url }}"></script>

{% endjavascripts %}

Page 97: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

<script src="js/92429d8_1.js"></script>

<script src="js/92429d8_2.js"></script>

<script src="js/92429d8_3.js"></script>

Page 98: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

AsseticBundleSymfony2 integration

Page 99: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

assetic:

debug: %kernel.debug%

use_controller: %kernel.debug%

filters:

coffee: ~

yui_js:

jar: /path/to/yui.jar

Page 100: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

{# when use_controller=true #}

<script src="{{ path('assetic_foo') }}"...

Page 101: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

# routing_dev.yml_assetic: resource: .

type: assetic

Page 102: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

{# when use_controller=false #}<script src="{{ asset('js/core.js') }}"></script>

Page 103: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The Symfony2 Assets Helper

•Multiple asset domains

•Cache buster

Page 104: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

framework:

templating:

assets_version: 1.2.3

assets_base_urls:

- http://assets1.domain.com

- http://assets2.domain.com

- http://assets3.domain.com

- http://assets4.domain.com

Page 105: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

<link href="http://assets3.domain.com/css/all.css?1.2.3" ...

Page 106: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

assetic:dump

Page 107: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$ php app/console assetic:dump web/

Page 108: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

assetic:dump --watchDump static assets in the background as you develop

Page 109: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Error Management

Page 110: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Error Management

Symfony2 is HTTP compliant as it’s able to send the corresponding status code depending on the leveraged error or exception when the request is handled.

Page 111: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 112: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 113: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 114: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 115: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Persisting data between HTTP requests

Page 116: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Persisting data between HTTP requests

Cookies and sessions were invented to offer a mean to simulate persistence between two different HTTP requests as the HTTP is a stateless protocol.

Page 117: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The Request object API

# Getting the request service$request = $this->getRequest();

# Wether the request comes from an Ajax call$request->isXmlHttpRequest();

# Find the preferred language based on Accept-Language header$request->getPreferredLanguage(array('en', 'fr'));

# Get a $_GET parameter$request->query->get('page');

# Get a $_POST parameter$request->request->get('content');

# Get a $_COOKIE parameter$request->cookies->get('remember-me');

# Get a $_SERVER parameter$request->server->get('SCRIPT_NAME');

Page 118: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

{# Wether the request comes from an Ajax call #}{% if app.request.isXmlHttpRequest %}

{# Find the preferred language based on Accept-Language header #}{{ app.request.getPreferredLanguage(['en', 'fr']) }}

{# Get a $_GET parameter #}{{ app.request.query.get('page') }}

{# Get a parameter #}{{ app.request.parameter.get('content') }}

{# Get a $_COOKIE parameter #}{{ app.request.cookies.get('remember-me') }}

{# Get a $_SERVER parameter #}{{ app.request.server.get('SCRIPT_NAME') }}

The Request object from Twig

Page 119: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

# Getting a response$response = new Response('<html>...</html>');$response = $this->render('FooBundle:Bar:template.html.twig');

# Triggering a redirect response$response = new RedirectResponse('http://www.domain.tld/job/8');$response = $this->redirect($this->generateUrl('home'));

# Fixing HTTP Expiration headers$response->setExpires(new \DateTime('2011-10-01 11:10:00'));$response->setMaxAge(120);$response->setSharedMaxAge(120);

# Fixing HTTP Validation headers$response->setLastModified(new \DateTime('now'));$response->setETag('a1b2c3');

The Response object API

Page 120: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 121: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

More with Templates

Page 122: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Create a new « menu.html.twig » template in the « AcmeTodoBundle » bundle that contains the following code.

Include the menu in the header and footer sections of the layout.

{# src/Acme/TodoBundle/Resources/views/menu.html.twig #}<div class="navigation"> <a href="#">Home</a> | <a href="#">About</a> | <a href="#">Contact</a></div>

{# src/Acme/TodoBundle/Resources/views/layout.html.twig #}{% block body %}

<div id="header">{% include 'AcmeTodoBundle::menu.html.twig' %}</div>

<h1>Training Application</h1> {% block content %}{% endblock %} <div id="footer">{% include 'AcmeTodoBundle::menu.html.twig' %}</div>

{% endblock %}

Page 123: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 124: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Diving into the Model layer

Page 125: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Symfony2 is a Model View Controller framework!

Page 126: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The Client makes a Request on the Server…

Page 127: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The Request hits the Front Controller.

The Front Controller dispatches to the corresponding Controller…

Page 128: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The Controller handles the Request, calls the Model, passes data to the View,

and finally returns a Response…

Page 129: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The Response is sent to the Client.

Page 130: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

In the MVC pattern, the Model is the most important layer as it stores data and business logic to access and modify them.

Page 131: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Doctrine MongoDB ODMKris Wallsmith

Page 132: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

This is MongoDB…

Page 133: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$mongo = new Mongo();

$db = $mongo->pdxphp;

$db->people->save(array(

'name' => 'Kris Wallsmith',

));

Page 134: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$cursor = $db->people->find();

print_r(iterator_to_array($cursor));

Page 135: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Array( [4cbdffdae84ded424f000000] => Array (

[_id] => MongoId Object

[name] => Kris Wallsmith ))

Page 136: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

MongoDB is where youput your arrays for later.

Page 137: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$db->people->save(array(

'name' => 'Sam Keen',

'roles' => array(

'organizer',

'presenter',

),

));

Page 138: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$query = array('roles' => 'presenter');

$cursor = $db->people->find($query);

print_r(iterator_to_array($cursor));

Page 139: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Array( [4cbe03cfe84dedb850010000] => Array ( [_id] => MongoId Object [name] => Sam Keen [roles] => Array ( [0] => organizer [1] => presenter ) ))

Page 140: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Me too!

Page 141: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$query = array(

'name' => 'Kris Wallsmith',

);

$kris = $db->people->findOne($query);

$kris['roles'] = array('presenter');

$db->people->save($kris);

Page 142: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$query = array('roles' => 'presenter');

$fields = array('name');

$cursor = $db->people->find($query, $fields);

print_r(iterator_to_array($cursor));

Page 143: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Array( [4cbe0a9de84ded7952010000] => Array ( [_id] => MongoId Object [name] => Sam Keen ) [4cbe0a9de84ded7952000000] => Array ( [_id] => MongoId Object [name] => Kris Wallsmith ))

Page 144: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Be surgical.

Page 145: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$query = array('roles' => 'presenter');

$update = array(

'$push' => array(

'roles' => 'cool guy',

),

);

$db->people->update($query, $update);

Page 146: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Atomic Operators

$inc

$set

$unset

$push

$pushAll

$addToSet

$pop

$pull

$pullAll

$rename

Page 147: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Advanced Queries

Page 148: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$roles = array('organizer', 'presenter');

$db->people->find(array(

'roles' => array('$all' => $roles),

));

Page 149: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Conditional Operators

$ne

$in

$nin

$mod

$all

$size

$exists

$type

$or

$elemMatch

Page 150: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Cursor Methods

Page 151: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$cursor = $db->people->find();$cursor->sort(array('name' => 1));foreach ($cursor as $person) { // ...

}

Page 152: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

I like you, Sam.

Page 153: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$samRef = MongoDBRef::create('people', $samId);$db->people->update( array('_id' => $kris['_id']), array( '$addToSet' => array( 'likes' => $samRef, ), )

);

Page 154: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$sam = $db->getDBRef($samRef);

Page 155: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$db->people->find(array(

'likes.$id' => $kris['_id'],

));

Page 156: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

TerminologyRDBMSRDBMS MongoDBMongoDB

Database Database

Table Collection

Row Document

Foreign Key Database Reference

Page 157: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

A document is an array.

Page 158: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Arrays are nice.

Page 159: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Objects are better.*

* Whenever objects are better.

Page 160: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The Doctrine MongoDBObject Document Mapper

maps documentsto and from objects.

Page 161: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

We just need to tell it how.

Page 162: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

/** @Document(collection="people") */

class Person {

/** @Id */

public $id;

/** @String */

public $name;

/** @Collection */

public $roles = array();

/** @ReferenceMany */

public $likes = array();

/** @EmbedMany(targetDocument="Address") */

public $addresses = array();

}

Page 163: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

POPO FTW!

Page 164: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$kris = new Person();

$kris->name = 'Kris Wallsmith';

$kris->roles[] = 'presenter';

$kris->likes[] = $sam;

$kris->addresses[] = $homeAddy;

$documentManager->persist($kris);

$documentManager->flush();

Page 165: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Wherefore art thou->save()

???

Page 166: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 167: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 168: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

ActiveRecord is more abstract.

Page 169: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Doctrine calculates theoptimal query for you.optimal query for you.

Page 170: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$kris = $dm->findOne('Person', array(

'name' => 'Kris Wallsmith',

));

$kris->roles[] = 'cool guy';

$dm->flush();

Page 171: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$db->people->update(array(

'_id' => $kris->id,

), array(

'$push' => array(

'roles' => 'cool guy',

),

));

Page 172: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Query API

Page 173: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

$qb = $dm->createQueryBuilder('Person')

->field('name')->notEqual('Kris Wallsmith')

->field('roles')->equals('presenter')

->sort('name', 'asc');

$cursor = $qb->getQuery()->execute();

Page 174: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Lifecycle Callbacks

Page 175: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

/** @Document */

class Foo {

/** @Date */

public $createdAt;

/** @PrePersist */

public function ensureCreatedAt() {

$this->createdAt = new DateTime();

}

}

Page 176: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

That’s MVC!

Page 177: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Configuration principles

Page 178: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Symfony2 supports several configuration file formats out of the box :

YAML, XML, INI or PHP code.

Page 179: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Choosing the best file format

Pros Cons

XML ValidationIDE completion & help Verbose (not that much)

INI ConciseEasy to read and to change Limited syntax

YAML ConciseEasy to read and to change Hard to validate / YAML component

PHP Flexible, more expressive No validation

Page 180: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Uncomment code to activate XML or PHP configuration

Default configuration format

# app/AppKernel.phpclass AppKernel extends Kernel{ # ... public function registerContainerConfiguration(LoaderInterface $loader) { // use YAML for configuration // comment to use another configuration format $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');

// uncomment to use XML for configuration //$loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.xml');

// uncomment to use PHP for configuration //$loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.php'); }}

Page 181: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

YAML configuration sample

# config/config_dev.ymlimports: - { resource: config.yml }

app.config: router: resource: "%kernel.root_dir%/config/routing_dev.yml"

profiler: { only_exceptions: false }

webprofiler.config: toolbar: true intercept_redirects: true

Page 182: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

XML configuration sample

<?xml version="1.0" ?><container xmlns="http://www.symfony-project.org/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:zend="http://www.symfony-project.org/schema/dic/zend" xmlns:app="http://www.symfony-project.org/schema/dic/symfony" xmlns:webprofiler="http://www.symfony-project.org/schema/dic/webprofiler" xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd http://www.symfony-project.org/schema/dic/webprofiler http://www.symfony-project.org/schema/dic/webprofiler/webprofiler-1.0.xsd http://www.symfony-project.org/schema/dic/zend http://www.symfony-project.org/schema/dic/zend/zend-1.0.xsd »> <imports> <import resource="config.xml" /> </imports> <app:config> <app:router resource="%kernel.root_dir%/config/routing_dev.xml" /> <app:profiler only-exceptions="false" /> </app:config> <webprofiler:config toolbar="true" intercept-redirects="true" /> <zend:config> <zend:logger priority="info" path="%kernel.logs_dir%/%kernel.environment%.log" /> </zend:config></container>

Page 183: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

PHP configuration sample

$loader->import('config.php');

$container->loadFromExtension('app', 'config', array( 'router' => array('resource' => '%kernel.root_dir%/config/routing_dev.php'), 'profiler' => array('only-exceptions' => false),));

$container->loadFromExtension('webprofiler', 'config', array( 'toolbar' => true, 'intercept-redirects' => true,));

$container->loadFromExtension('zend', 'config', array( 'logger' => array( 'priority' => 'info', 'path' => '%kernel.logs_dir%/%kernel.environment%.log', ),));

Page 184: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Global configuration can be overloadedaccording to the environment you are on…

Page 185: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Overriding and overloading principles

# config/config_dev.ymlimports: - { resource: config.yml } - { resource: "@FooBarBundle/Resources/config/foo.xml" }

app.config: router: { resource: "%kernel.root_dir%/config/routing_dev.yml" } profiler: { only_exceptions: false }

webprofiler.config: toolbar: true intercept_redirects: true

Page 186: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Importing INI files

# app/config/config.ymlimports: - { resource: dice.config.ini }

parameters: available_colors: [red, green, blue, purple, yellow, black]

# app/config/dice.config.ini[parameters]dice.min = 1dice.max = 6

Page 187: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Forms

Page 188: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

How does it work?

1) The form reads properties of an object,

2) Based on these values, form fields are prepopulated,

3) When the form is submitted, data are bound to the form,

4) Then, the validation business logic is applied on each field ,

5) If validation fails, form is displayed again with submitted values,

6) Otherwise, form is processed.

Page 189: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 190: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 191: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Creating a new formnamespace Acme\DemoBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;use Acme\DemoBundle\Entity\Product;

class ShopController extends Controller{ /** * @Route("/product", name="_new_product") * @Template */ public function indexAction() { $product = new Product(); $product->name = 'Test product'; $product->setPrice('50.00');

$form = $this->createFormBuilder($product) ->add('name', 'text') ->add('price', 'money', array('currency' => 'USD')) ->getForm();

return array('form' => $form->createView()); }}

Page 192: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 193: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 194: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 195: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 196: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Prototyping the form rendering

Symfony provides a dedicated Twig function to automate the rendering of a form in a template.

<form action="#" method="post">

{{ form_widget(form) }}

<button type="submit">Create the product</button></form>

Page 197: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Prototyping the form rendering

Symfony provides a dedicated Twig function to automate the rendering of a form in a template.

<form action="#" method="post">

{{ form_widget(form) }}

<button type="submit">Create the product</button></form>

Page 198: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 199: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Creating a dedicated form class

To make the controller thinner and the form reusable anywhere, the best practice is

move the form creation code to a dedicated form class.

Page 200: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

// src/Acme/DemoBundle/Form/ProductType.phpnamespace Acme\DemoBundle\Form;

use Symfony\Component\Form\AbstractType;use Symfony\Component\Form\FormBuilder;

class ProductType extends AbstractType{ public function buildForm(FormBuilder $builder, array $options) { $builder->add('name'); $builder->add('price', 'money', array( 'currency' => 'USD' )); }}

Creating a custom form

Page 201: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Using a form type from the controller

use Acme\DemoBundle\Entity\Product;use Acme\DemoBundle\Form\ProductType;

// ...

public function indexAction(){ $product = new Product(); $product->name = 'A name'; $product->setPrice(50.00);

$form = $this->createForm(new ProductType(), $product);

// ...}

Page 202: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Experimenting Forms

Page 203: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The contact request form

oBasic form composed of 3 fields (sender, subject, message)

oForm will validate a ContactRequest object

oThe ContactRequest properties are constrainted with validators

Page 204: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

First, create the contact type class in the AcmeTodoBundle bundle.

// src/Acme/TodoBundle/Form/ContactRequestType.phpnamespace Sensio\Bundle\TrainingBundle\Form;

use Symfony\Component\Form\AbstractType;use Symfony\Component\Form\FormBuilder;

class ContactRequestType extends AbstractType{ public function buildForm(FormBuilder $builder, array $options) { $builder->add('sender', 'text'); $builder->add('subject', 'text'); $builder->add('message', 'textarea'); }}

Page 205: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

The contact request domain object

The sender value is mandatory and must be a valid email address

namespace Sensio\TrainingBundle\Form;

use Symfony\Component\Validator\Constraints as Assert;

class ContactRequest{ /** * @Assert\Email() * @Assert\NotBlank() */ public $sender;

/** * @Assert\MaxLength(50) * @Assert\NotBlank() */ public $subject;

/** @Assert\NotBlank() */ public $message;}

The subject value is mandatory and can’t exceed 50 characters

Page 206: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

namespace Sensio\TrainingBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpFoundation\RedirectResponse;use Symfony\Component\HttpFoundation\Request;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;use Sensio\TrainingBundle\Form\ContactRequest;use Sensio\TrainingBundle\Form\ContactRequestType;

class ContactController extends Controller{ /** * @Route("/contact", name="contact") * @Template */ public function indexAction(Request $request) { $contact = new ContactRequest(); $form = $this->createForm(new ContactRequestType(), $contact);

if ($request->getMethod() == 'POST') { $form->bindRequest($request);

if ($form->isValid()) { // ... send an email return $this->redirect($this->generateUrl('contact_success')); } }

return array('form' => $form->createView()); }}

Page 207: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Prototyping the form rendering

Symfony provides a dedicated Twig function to automate the rendering of a form in a template.

<form action="#" method="post">

{{ form_widget(form) }}

<button type="submit">Create the product</button></form>

Page 208: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Implementing the success page

{# @AcmeTodoBundle/Resources/views/Contact/thankYou.html.twig #}

{% extends 'AcmeTodoBundle::layout.html.twig' %}

{% block content %}

<h2>Contact Us</h2> <p>Thanks for your message</p>

{% endblock %}

/** * @Route("/contact/thank-you", name="contact_success") * @Template */public function thankYouAction(){ return array();}

Page 209: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 210: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 211: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

In order to verify application behaviorAs a software developer

I need tests

Page 212: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

In order to verify application behaviorAs a software developer

I need tests

Preferably automated tests

Page 213: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Test-Driven Development...is an iterative design process

● Write a test

Page 214: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Test-Driven Development...is an iterative design process

● Write a test● Ensure the new test fails

Page 215: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Test-Driven Development...is an iterative design process

● Write a test● Ensure the new test fails● Write code to satisfy the test

Page 216: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Test-Driven Development...is an iterative design process

● Write a test● Ensure the new test fails● Write code to satisfy the test● Ensure all tests pass

Page 217: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Test-Driven Development...is an iterative design process

● Write a test● Ensure the new test fails● Write code to satisfy the test● Ensure all tests pass● Refactor

Page 218: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Test-Driven Development...is an iterative design process

● Write a test● Ensure the new test fails● Write code to satisfy the test● Ensure all tests pass● Refactor● Repeat

Page 219: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Dan North Introduces BDD

I had a problem. While using and teaching agile practices like test-driven development (TDD) on projects in different environments, I kept coming across the same confusion and misunderstandings. Programmers wanted to know:● Where to start● What to test and what not to test● How much to test in one go● What to call their tests● How to understand why a test fails

http://dannorth.net/introducing-bdd/

Page 220: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

I started using the word “behavior” in place of “test” in my dealings with TDD and… I now had answers to some of those TDD questions:● What to call your test is easy – it’s a sentence describing the next behavior in which you are interested.● How much to test becomes moot – you can only describe so much behavior in a single sentence.● When a test fails, simply work through the process described above – either you introduced a bug, the

behavior moved, or the test is no longer relevant.

http://dannorth.net/introducing-bdd/

Dan North Introduces BDD

Page 221: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Behavior-Driven Development...builds upon TDD

● Write test cases in a natural language

Page 222: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Behavior-Driven Development...builds upon TDD

● Write test cases in a natural language

•Understood by developers and business folks alike

Page 223: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Behavior-Driven Development...builds upon TDD

● Write test cases in a natural language

•Understood by developers and business folks alike

•Helps relate domain language of requirements to the code

Page 224: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Behavior-Driven Development...builds upon TDD

● Write test cases in a natural language

•Understood by developers and business folks alike

•Helps relate domain language of requirements to the code● Do this with user stories and scenarios

Page 225: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Behavior-Driven Development...builds upon TDD

● Write test cases in a natural language

•Understood by developers and business folks alike

•Helps relate domain language of requirements to the code● Do this with user stories and scenarios

•User stories describe a feature's benefit in context

Page 226: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Behavior-Driven Development...builds upon TDD

● Write test cases in a natural language

•Understood by developers and business folks alike

•Helps relate domain language of requirements to the code● Do this with user stories and scenarios

•User stories describe a feature's benefit in context

•Scenarios are executable acceptance criteria

Page 227: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Behavior-Driven Development...builds upon TDD

● Write test cases in a natural language

• Understood by developers and business folks alike

• Helps relate domain language of requirements to the code● Do this with user stories and scenarios

• User stories describe a feature's benefit in context

• Scenarios are executable acceptance criteria

A story’s behavior is simply its acceptance criteria – if the system fulfills all the acceptance criteria, it’s behaving correctly; if it doesn’t, it isn’t.

http://dannorth.net/introducing-bdd/

Page 228: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

So what does this look like?

Page 229: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 230: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 231: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

This is where Behat and Mink come in.

Page 232: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

This is where Behat and Mink come in.

Acceptance testing (any tests)

Tests a feature by executing its scenarios' steps in a context.

Web acceptance testing (functional tests)

Drivers for Goutte, Sahi and Symfony2's test client.

Page 233: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Initialize Our Bundle With Behat

$ app/console behat --init @AcmeDemoBundle

+d src/Acme/DemoBundle/Features

- place your *.feature files here

+f src/Acme/DemoBundle/Features/Context/FeatureContext.php

- place your feature related code here

● We now have a directory to hold AcmeDemoBundle's features● Behat also creates an empty FeatureContext class, which extends BehatBundle's

BehatContext

• Features describe our behavior, but the context tells Behat how to evaluate our feature as an executable test

Page 234: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Let's Have Behat Analyze Our Feature

$ app/console behat src/Acme/DemoBundle/Features/contact.feature

Feature: Contact form

In order to contact an email address

As a visitor

I need to be able to submit a contact form

Scenario: Successfully submit the contact form # contact.feature:6

Given I am on "/demo/contact"

When I fill in "Email" with "[email protected]"

And I fill in "Message" with "Hello there!"

And I press "Send"

Then I should see "Message sent!"

1 scenario (1 undefined)

5 steps (5 undefined)

Page 235: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Behat Creates the Glue...but the rest is up to you

/**

* @Given /^I am on "([^"]*)"$/

*/

public function iAmOn($argument1)

{

throw new PendingException();

}

/**

* @When /^I fill in "([^"]*)" with "([^"]*)"$/

*/

public function iFillInWith($argument1, $argument2)

{

throw new PendingException();

}

/**

* @Given /^I press "([^"]*)"$/

*/

public function iPress($argument1)

{

throw new PendingException();

}

/**

* @Then /^I should see "([^"]*)"$/

*/

public function iShouldSee($argument1)

{

throw new PendingException();

}

You can implement step definitions for undefined steps with these snippets:

Page 236: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Not so fast. What about Mink?

Page 237: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

MinkContext Defines Steps...for making requests

Pattern DescriptionGiven /^I am on "(?P<page>[^"]+)"$/ Opens specified pageWhen /^I go to "(?P<page>[^"]+)"$/ Opens specified pageWhen /^I reload the page$/ Reloads current pageWhen /^I move backward one page$/ Moves backward one page in historyWhen /^I move forward one page$/ Moves forward one page in historyWhen /^I press "(?P<button>(?:[^"]|\\")*)"$/

Presses button with specified id|name|title|alt|value

When /^I follow "(?P<link>(?:[^"]|\\")*)"$/ Clicks link with specified id|title|alt|text

Page 238: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

MinkContext Defines Steps...for interacting with forms

Pattern DescriptionWhen /^I fill in "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/ Fills in form field with specified id|name|label|value

When /^I fill in "(?P<value>(?:[^"]|\\")*)" for "(?P<field>(?:[^"]|\\")*)"$/ Fills in form field with specified id|name|label|value

When /^I fill in the following:$/ Fills in form fields with provided table

When /^I select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/ Selects option in select field with specified id|name|label|value

When /^I check "(?P<option>(?:[^"]|\\")*)"$/ Checks checkbox with specified id|name|label|value

When /^I uncheck "(?P<option>(?:[^"]|\\")*)"$/ Unchecks checkbox with specified id|name|label|value

When /^I attach the file "(?P<path>[^"]*)" to "(?P<field>(?:[^"]|\\")*)"$/ Attaches file to field with specified id|name|label|value

Page 239: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 240: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

MinkContext Defines Steps...for querying the DOM

Pattern DescriptionThen /^I should see "(?P<text>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/

Checks that element with specified CSS contains specified text

Then /^the "(?P<element>[^"]*)" element should contain "(?P<value>(?:[^"]|\\")*)"$/

Checks that element with specified CSS contains specified HTML

Then /^I should see an? "(?P<element>[^"]*)" element$/ Checks that element with specified CSS exists on page

Then /^I should not see an? "(?P<element>[^"]*)" element$/ Checks that element with specified CSS doesn't exist on page

Then /^the "(?P<field>(?:[^"]|\\")*)" field should contain "(?P<value>(?:[^"]|\\")*)"$/

Checks that form field with specified id|name|label|value has specified value

Then /^the "(?P<field>(?:[^"]|\\")*)" field should not contain "(?P<value>(?:[^"]|\\")*)"$/

Checks that form field with specified id|name|label|value doesn't have specified value

Then /^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox should be checked$/ Checks that checkbox with specified id|name|label|value is checked

Then /^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox should not be checked$/ Checks that checkbox with specified id|name|label|value is unchecked

Page 241: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

MinkContext Defines Steps...for examining responses

Pattern DescriptionThen /^I should be on "(?P<page>[^"]+)"$/ Checks that current page path is equal to specified

Then /^the url should match "(?P<pattern>(?:[^"]|\\")*)"$/ Checks that current page path matches pattern

Then /^the response status code should be (?P<code>\d+)$/ Checks that current page response status is equal to specified

Then /^I should see "(?P<text>(?:[^"]|\\")*)"$/ Checks that page contains specified text

Then /^I should not see "(?P<text>(?:[^"]|\\")*)"$/ Checks that page doesn't contain specified text

Then /^the response should contain "(?P<text>(?:[^"]|\\")*)"$/ Checks that HTML response contains specified string

Then /^the response should not contain "(?P<text>(?:[^"]|\\")*)"$/ Checks that HTML response doesn't contain specified string

Then /^print last response$/ Prints last response to console

Then /^show last response$/ Opens last response content in browser

Page 242: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 243: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 244: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Let's Execute Our Feature With Behat

$ app/console behat @AcmeDemoBundle --env=test

Feature: Contact form

In order to contact an email address

As a visitor

I need to be able to submit a contact form

Scenario: Successfully submit the contact form # contact.feature:6

Given I am on "/demo/contact" # FeatureContext::visit()

When I fill in "Email" with "[email protected]" # FeatureContext::fillField()

Form field with id|name|label|value "Email" not found

And I fill in "Message" with "Hello there!" # FeatureContext::fillField()

And I press "Send" # FeatureContext::pressButton()

Then I should see "Message sent!" # FeatureContext::assertPageContainsText()

1 scenario (1 failed)

5 steps (1 passed, 3 skipped, 1 failed)

Page 245: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 246: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

A Note About Step Results...of which there are seven

● Success: a definition was found and executing it did not throw an Exception●Undefined: a definition couldn't be found; all subsequent steps will be skipped●Pending: the definition threw the special PendingException, which means you have

work to do; skip remaining steps● Failure: a definition throws an Exception; Behat will skip remaining steps and

terminate with exit status 1•Behat can easily use PHPUnit's assertion framework or you can roll your own● Skipped: steps which were never executed●Ambiguous: multiple definitions matched a step●Redundant: multiple definitions share the same pattern

Page 247: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Implement the Contact Form

Page 248: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Implement the Contact Form

Page 249: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Implement the Contact Form

Page 250: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Let's Try That Again

$ app/console behat @AcmeDemoBundle --env=test

Feature: Contact form

In order to contact an email address

As a visitor

I need to be able to submit a contact form

Scenario: Successfully submit the contact form # contact.feature:6

Given I am on "/demo/contact" # FeatureContext::visit()

When I fill in "Email" with "[email protected]" # FeatureContext::fillField()

And I fill in "Message" with "Hello there!" # FeatureContext::fillField()

And I press "Send" # FeatureContext::pressButton()

Then I should see "Message sent!" # FeatureContext::assertPageContainsText()

1 scenario (1 passed)

5 steps (5 passed)

Page 251: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 252: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

What Else Can Mink Do?

● Provide a single API for browser behavior• HTTP authentication, cookies, headers, sessions• Page examination via XPath or CSS selectors• Page manipulation (e.g. complete forms, click, hover, drag-and-drop)● Existing drivers can be used interchangeably• Symfony2 test client – simulated request serving • Goutte – headless, PHP web scraper• Sahi – brower-control toolkit (necessary for JS)• PhantomJS – headless browser-control for Webkit•http://www.ryangrenz.com/2011/05/30/experiments-with-behat-part1-mink-sahi-phantomjs/

Page 253: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Thanks!

http://behat.org/

http://mink.behat.org/

http://github.com/Behat

Page 254: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox
Page 255: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Create a bundle

php app/console generate:bundle --namespace=Acme/TodoBundle

Page 256: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

git clone https://github.com/jmikola/top-shelf-php.git

Page 257: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Questions?

Page 258: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox

Thanks for joining Top Shelf PHP!

http://symfony.com

http://github.com/kriswallsmith/assetic

http://behat.org

Page 259: The format – Talks then Hackingassets.en.oreilly.com/1/event/61/Top Shelf PHP Presentation 1.pdf · The format – Talks then Hacking. Follow along with the sandbox