dive into

151
Dive into http://blog.nerdery.com/2013/06/symfony2-tech-talk/

Upload: marshall-bell

Post on 16-Dec-2015

223 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: Dive into

Dive into

http://blog.nerdery.com/2013/06/symfony2-tech-talk/

Page 2: Dive into

Maxwell VanderveldeWho the hell are you?

Developer at The Nerdery

● Working with

o PHP (Zend, Symfony2, Cake)

o Android, Javascript

o Tools! Git, Jenkins

● Kickstarting Internal Symfony2 Development @ The Nerdery

Page 3: Dive into

Chris JollyWho the hell are you?

CTO at Ontraq Europe

● Working with

o PHP (Symfony2, Drupal, OXID)

o Javascript

o .Net (MVC, WebApi, Forms)

● We do

o Integration, Interfaces & SSO

Page 4: Dive into

What's inside

● Focus on high level birds eye view of framework

● Reinforce low level architecture

● Provide prerequisite knowledge

Code

Architecture / Components

Orientation / Principles

Page 5: Dive into

let's get started!

Page 6: Dive into

What is Symfony2?

"First, Symfony2 is a reusable set of standalone, decoupled, and cohesive PHP components that solve common web development problems."

"... Then, based on these components, Symfony2 is also a full-stack web framework."

Page 7: Dive into
Page 8: Dive into

What is Symfony2?

Is Symfony2 an MVC Framework?

"Symfony2 is never defined as being an MVC framework"

"... I really don't care whether Symfony2 is MVC or not."

"... The separation of concerns is all I care about.”

That’s one way of describing it, but…

In fact it’s very similar to MS .Net MVC + Entity Framework

Page 10: Dive into

Symfony2 Principles

Separate Concerns

● Do one thing,

● Make it excellent.

● Stay out of the way.

"Design programs to be connected to other programs." - Rule 3, Unix Philosophy

Page 11: Dive into

Symfony2 Principles

Break the chain

● Composition, not inheritance

● Event and DI driven

Page 12: Dive into

Symfony2 Principles

Be Explicit, not Implicit.

● Not 'on rails'

● Improves Flexibility

● Improves Readability

Explicit is better than implicit.Simple is better than complex.

Complex is better than complicated.- Zen of Python

Page 13: Dive into

Symfony2 Principles

Follow Current Standards

● Uses PHP namespacing

o Follows PSR-0 Autoloading standard

● Follows HTTP Specification

"Namespaces are one honking great idea -- let's do more of those!" - Zen of Python

Page 14: Dive into

Symfony2 Principles

Don't reinvent the wheel

● Use The right tool for the job

o Uses Doctrine as an ORM

o Uses Composer as Dependency management

o Uses Twig as a View templating engine

● Uses a healthy ecosystem of 3rd-party bundles

Page 15: Dive into

Symfony2 Principles

Decouple your code

● Replace the part, not the machine

● Make code as independent as possible

● Allow for interaction on common interfaces

"The old adage "don't reinvent the wheel" doesn't apply when the wheel comes attached to a locomotive engine."

Page 16: Dive into

Symfony2 Principles

Tooling Agnostic

● Each piece of the framework is replaceable

o ORM

o View templating engine

Distrust all claims for “one true way” - Rule 16, Unix Philosophy

Page 17: Dive into

What is Symfony2?

What framework model is Symfony2?

“Symfony2 is an HTTP Request -> Response framework”

Or…

“the HttpFoundation Component does a great job handling the Request -> Response process.”

Page 18: Dive into

Symfony2's Foundation

Request Response

Page 19: Dive into

Symfony2's Foundation

Request Response

Page 20: Dive into

HttpFoundation Component

● HttpFoundation defines an object-oriented layer for the HTTP specification.

● It protects the programmer from the real world nastiness

● You can use it stand-alone if wanted

● http://symfony.com/doc/current/components/http_foundation/introduction.html

● index.htmlhttps://github.com/symfony/HttpFoundation

Page 21: Dive into

HttpFoundation\Request Object

● Container for a standard HTTP request

● Created from PHP globals

Page 22: Dive into

HttpFoundation\Response Object

● Holds all the information that needs to be sent back to the client from a given request.

o Content, Status code, HTTP headers

Page 23: Dive into

HttpFoundation Demo

Let’s go OO…

Page 24: Dive into

Symfony2's Foundation

Request Response

Page 25: Dive into

HttpKernel Component

● First object created. The core of the web framework

● Takes in a Request, outputs a Response

● Binds the components together and controls the flow

Page 26: Dive into

Symfony2's Foundation

Request Response

HttpKernel

Page 27: Dive into

EventDispatcher

● Symfony's internals are event driven

● Controlled by the EventDispatcher Component

Page 28: Dive into

Symfony2's Foundation

Request Response

HttpKernelEventDispatche

r

Page 29: Dive into

EventDispatcher

● Implements the Observer pattern

o Listeners are added to an event

o Dispatcher is notified to dispatch the event

o Each Listener is notified / called

Page 30: Dive into

Symfony2's Foundation

Request Response

HttpKernelEventDispatche

r

Listeners

Page 31: Dive into

EventDispatcher

What does it mean to be event driven?

Event A

Event B

Event C

Listener

Listener

Listener

Listener

Listener

Page 32: Dive into

The kernel.request event

● HttpKernel first calls the kernel.request event

● Listeners of the object are called

o These listeners may return a Response

Page 33: Dive into

DependencyInjection

● Allows you to standardize and centralize the way objects are constructed in your application.

● Connects / wires objects together

o Defined in a yaml/xml config

Page 34: Dive into

Symfony2's Foundation

Request Response

HttpKernelEventDispatche

r

Listeners

DependencyInjection

Page 35: Dive into

Routing

● Given a Request

o Defined in Yaml or Annotations

o Determines route based on URI and Request Type

o Returns a controller to execute

Page 36: Dive into

Symfony2's Foundation

Request Response

HttpKernelEventDispatche

r

Listeners

DependencyInjection

Routing

Page 37: Dive into

The kernel.controller event

● HttpKernel calls the kernel.controller event BEFORE calling the controller

● Listeners of the object are called

o These listeners may return a Response

Page 38: Dive into

Symfony2's Foundation

Request Response

HttpKernelEventDispatche

r

Controller

Listeners

DependencyInjection

Routing

Page 39: Dive into

Controller

● Take a request, may return a response

● Nothing Special

o can be any PHP callable

Page 40: Dive into

The kernel.view event

● What if the controller doesn't return a response?

● After the controller is called the kernel.view event is dispatched

o These listeners may return a Response

Page 41: Dive into

Symfony2's Foundation

Request Response

HttpKernelEventDispatche

r

Controller

Listeners

DependencyInjection

Routing

Page 42: Dive into

The kernel.exception event

● Called on uncaught exception

● Called on unhandled request

● the kernel.exception event is dispatched

o Application's last chance to return a Response

Page 43: Dive into

EventDispatcher

● You can make your own listeners

● Can dispatch your own events

Page 44: Dive into

Using Composer

What is Dependency Management?

● Your project needs things (Doctrine, Symfony, Twig)

o Those things need things

● Composer installs all the things!

Page 45: Dive into

Using Composer

Composer is not a package manager!

● Familiar with PEAR/PEAR2/PECL?

o These install libraries globally

o Runs into conflicts if you need two different versions

● Composer installs on per-project

Page 46: Dive into

Using Composer

● Composer installs dependencies in /vendors/

● Provides an autoloader for classes

● Will "lock" each dependency down to a version

o Each subsequent insall will use the same version

Page 47: Dive into

Using Composer

● Composer allows libraries to be excluded from Source Control

o Keeps project lean

o Abstracts wiring of dependencies

o Easy to manage installs & updates:

composer.phar install

composer.phar update

Page 48: Dive into

Using Composer

How does it work?

● Composer is a php executable (.phar file)

o Can be included on an individual project basis

o Can be installed on the system

● Dependencies are defined in a json file

Page 49: Dive into

Using Composer

{ "require": { "symfony/symfony": "2.1.*", "doctrine/orm": ">=2.2.3,<2.5-dev", },}

$ curl -sS https://getcomposer.org/installer | php --install-dir=bin

$ composer require symfony/http-foundation

Page 50: Dive into

The Bundle System

Symfony2 project code is broken into "bundles"

Page 51: Dive into

The Bundle System

● What is a bundle?

ForumBundle

AdminBundle

BlogBundle

WebBundle}

● Structured set of files that implement a single feature of your application.

● Every project is a bundle in Symfony2

Page 52: Dive into

The Bundle System

● Bundles should be self contained

● Bundles can extend other bundles

Page 53: Dive into

Symfony Configuration

● Configuration kept in yaml files

o Prod, Dev, & Test environments.

Page 54: Dive into

Symfony Configuration

● Routing and others can be defined with annotationnamespace Acme\HelloBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;

class HelloController { /** * @Route("/hello/{name}") * @Method("GET") */ public function indexAction($name) { ... }}

Page 55: Dive into

Symfony Parameters

● Environment specific configurations?

o (Passwords, keys, etc.)

o Kept in a parameters.yml file

o Can be kept excluded from Version Control

o Replaces placeholders in configuration files

Page 56: Dive into

Symfony Parameters

imports:

- { resource: parameters.yml }

database:

driver: MySQL

password: %db_password%

username: %db_username%Parameter placeholders

config.yml

Page 57: Dive into

Symfony Parameters

parameters:

db_username: "admin"

db_password: "sadjiou34iu3$as"

Placeholder values

parameters.yml

Page 58: Dive into

The Symfony2 View

● Layouts are created using Twig Templating engine

o May also use php, or another template engine

Page 59: Dive into

The Symfony2 View

● Why use Twig?

o Isn't PHP a templating language?

● View helpers are object oriented

o Creates a lot of noise in the view

● Twig aims to clean the noise up

● It’s a lot like Smarty

Page 60: Dive into

Templates are broken into a block structure

The Symfony2 View

layout.twig myView.twig

Header

Body Body

Header

Page 61: Dive into

● Partial views can be included easily

● Twig outputs can be "filtered"

● Output Autoescaped by default

The Symfony2 View

Page 62: Dive into

How do filters work?

The Symfony2 View

*Hello Damn World*

Markdown Filter

<b>Hello Damn World</b>

Expletive Filter

<b>Hello D*mn World</b>

Initial output

final output

Page 63: Dive into

Javascript and CSS asset compilation!

● Can combine multiple CSS, JS into single output files

● Can Filter output!

The Symfony2 View

Page 64: Dive into

Templating is slow!

● Templates cached in production!

The Symfony2 View

Page 65: Dive into

Using Doctrine

● Symfony's default database ORM

● Follows strict standards for data entity management

Page 66: Dive into

Using Doctrine

● Data models are Entity objects

o Plain objects

● Data structure defined as annotations on Entities

Page 67: Dive into

Using Doctrine

● Entities are accessed through Doctrine Repositories

o May be customized for custom queries

Page 68: Dive into

Using Doctrine

Entity

EntityRepository

CustomRepository

Database

Page 69: Dive into

Using Doctrine

● Queries are optimized

o Allows for cached Queries

● Associations are lazy loaded

o Reduces overhead

Page 70: Dive into

Application Security

Page 71: Dive into

Security Component

Authentication

Authorization● Identify a user

o Formo Http Autho Custom?

● Resource accesso URLo Entityo Action/Method

Page 72: Dive into

Security Component

Firewalls

● Does a user need to be authenticated?

● Based on URLs

Page 73: Dive into

Security Component

Anonymous User

Firew

all

/foo

Page 74: Dive into

Security Component

Anonymous User

Firew

all

/foo

/foo

Anonymous users are allowed!

Page 75: Dive into

Security Component

Anonymous User

Firew

all

/foo

/foo

/login

No Anonymous users, try logging in!

Page 76: Dive into

Security Component

Access Controls

● Can a user access a resource?

● Based on user

● Permissions distributed as "roles"

Page 77: Dive into

Security Component

Anonymous User

Firew

all

/foo

/foo

/login

Acce

ss Con

trol

No Required Roles

/foo

Page 78: Dive into

Security Component

Anonymous User

Firew

all

/foo

/foo

Acce

ss Con

trol User needs Admin Role!

/foo

/loginTry logging in!

Page 79: Dive into

Security Component

User "Ryan"

Firew

all

/foo

/foo

Acce

ss Con

trol

/foo

User is logged in and has Admin role

Page 80: Dive into

Security Component

User "Ryan"

Firew

all

/foo

/foo

Acce

ss Con

trol

User is missing Admin Role!

/foo

403

Already logged in

Page 81: Dive into

Symfony Forms

Forms are a trouble point for most frameworks

● Separation of Concerns

● Decouple from view

● Decouple from entities

● Validation

Page 82: Dive into

Symfony Forms

● Form Builder

o Add fields by name, type, etc.

● Form types

● Bind to gather data

Page 83: Dive into

Symfony Forms

Validation

● Forms don't validate

● Check entity state after form populates it.

Page 84: Dive into

Symfony Forms

How does Symfony2 organize forms?

● Each form is broken into many forms

● Forms are structured in a tree

Page 85: Dive into

Symfony Forms

Page 86: Dive into

Symfony Forms

Page 87: Dive into

Symfony FormsForm

[New Employee]

Text[Name]

Number[salary]

BirthDate[birth date]

int[Year]

int[Month]

int[Day]

Page 88: Dive into

Symfony Forms

How do decorators work?

● Leverage template block structure

● Broken into "widgets"

o Each widget gets a view block / partial

Page 89: Dive into

Symfony Forms

● Benefits

o View logic detached from Form!

o Same form, different views

Page 90: Dive into

Symfony Forms

What about the Data?

Got a complex form?

Want some more control over form data types?

Page 91: Dive into

Symfony Forms

Form data is stored in three formats

o Model

o Normalized

o View

Page 92: Dive into

Symfony Forms

Wait... what?

Model Normalized View

● Tied to Entity● Must associate

with property

● Tied to input type● Reliable for logic

● Tied to view● Stringly typed

Page 93: Dive into

Symfony Forms

● Why all the formats?

o Decouples View from Model

o Decouples Domain logic from View & Model

Page 94: Dive into

Symfony Forms

Form Transformers

Page 95: Dive into

Symfony Forms

Form Transformers

● Used to convert one format to another

● Bijective transformation

Page 96: Dive into

Symfony Forms

setData($data);

Model Normalized ViewTransform Transform

Page 97: Dive into

Symfony Forms

bind($data);

Model Normalized View

Reverse Transform

Reverse Transform

Page 98: Dive into

Symfony Console

Symfony Console

● Provides Useful commands

o Cache options

o Code Generation

o Asset Symlinking

o Custom Commands

Page 99: Dive into

Symfony Console

Custom Commands

● Service oriented

o Get Database or anything the DI can provide

● Run your own command line

● Cron Tasks, Setup, Etc.

Page 100: Dive into

Symfony Demo

The Framework in action…

Page 101: Dive into

Questions / Details

(Psst... There's more slides)

Page 102: Dive into

The Symfony2 Controller

use Symfony\Component\HttpFoundation\Response;

function helloAction(){ return new Response('Hello world!');}

● As a basic callable

Page 103: Dive into

The Symfony2 Controller

namespace Acme\HelloBundle\Controller;use Symfony\Component\HttpFoundation\Response;

class HelloController{ public function indexAction() { return new Response('Hello World!'); }}

● As a class method

Page 104: Dive into

The Symfony2 Controller

namespace Acme\HelloBundle\Controller;use Symfony\Component\HttpFoundation\Response;

use Symfony\Component\HttpFoundation\Request;

class HelloController{ public function indexAction(Request $request) {

if ($request->isXmlHttpRequest()) { ... } }}

● Getting the Request object

Page 105: Dive into

The Symfony2 Controller

namespace Acme\HelloBundle\Controller;use Symfony\Component\HttpFoundation\Response;

class HelloController{ public function indexAction($name) { return new Response('Hello ' . $name . '!'); }}

● Parameters can be passed in from router

Page 106: Dive into

The Symfony2 Router

● Routes defined as a Yaml config

● app/config/routing.yml

hello_world: path: /hello/{name} defaults:{ _controller: AcmeHelloBundle:Hello:index }

Page 107: Dive into

The Symfony2 Router

● Routes can be defined with annotations

namespace Acme\HelloBundle\Controller;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class HelloController { /** * @Route("/hello/{name}") */ public function indexAction($name) { ... }}

Page 108: Dive into

The Symfony2 Router

● Routes follow HTTP GET/POST/PUT/DELETE specnamespace Acme\HelloBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;

class HelloController { /** * @Route("/hello/{name}") * @Method("GET") */ public function indexAction($name) { ... }}

Page 109: Dive into

The Symfony2 View

Twig basics

● {{ ... }} Prints a variable or the result of an expression

● {% ... %} Controls the logic of the template;

Page 110: Dive into

The Symfony2 View

Properties, methods are accessed through dot notation{% for post in blogPosts %}<li> <ul> <a href="{{post.getLink()}}">{{post.title}}</a> </ul>

</li>{% endfor %}

Page 111: Dive into

The Symfony2 View

Twig views are extendable

● Parent template

● Broken into Blocks

● Blocks are extended or overridden by views

Page 112: Dive into

The Symfony2 View

A Base Template

<html> <head> <title> {% block title %}Example.com{% endblock %} </title> </head> <body> {% block body %}{% endblock %} </body></html>

Page 113: Dive into

The Symfony2 View

Blocks can be extended, or overridden

{% extends "::base.html.twig" %}

{% block title %}

Welcome! {{ parent() }}

{% endblock %}

{% block body %}

Hello World!

{% endblock %}

Page 114: Dive into

DependencyInjection

What is dependency injection?

● Inject needed objects into classes

o Constructor, setters, properties

● Used to decouple classes

● Use Common interfaces instead of concretes

Page 115: Dive into

DependencyInjection

The problem:public class User { private $session; public function __construct() { $this->session = new Session('SESSION_ID'); } ....}

Page 116: Dive into

DependencyInjection

Dependency Injection solutionpublic class User { private $session; public function __construct(SessionInterface $session) { $this->session = $session; } ....}

Page 117: Dive into

DependencyInjection

Configuring Servicesparameters: api.class: Acme\HelloBundle\Api curl.class: Acme\HelloBundle\Wrapper\Curlservices: api: class: "%api.class%" arguments: [@curl, "%api.key%"] curl: class: "%curl.class%" arguments: []

Page 118: Dive into

Doctrine Entities/** * @ORM\Table(name="widget") */class Widget{ /** * @var string $body * @ORM\Column(name="body", type="text", nullable=true) */ private $body; public function getBody() { ... } public function setBody($body) { ... }}

Table name

Page 119: Dive into

Doctrine Entities/** * @ORM\Table(name="widget") */class Widget{ /** * @var string $body * @ORM\Column(name="body", type="text", nullable=true) */ private $body; public function getBody() { ... } public function setBody($body) { ... }}

Column name

Page 120: Dive into

Doctrine Entities/** * @ORM\Table(name="widget") */class Widget{ /** * @var string $body * @ORM\Column(name="body", type="text", nullable=true) */ private $body;

public function getBody() { ... } public function setBody($body) { ... }}

Column type / attributes

Page 121: Dive into

Using Doctrine

● Data is accessed through the EntityManager

o Each table is a "Repository"

Page 122: Dive into

Doctrine Entitiesclass AcmeClass{ public function doSomething() { $repo = $this->doctrine->getRepository('AcmeBundle:Widgets'); $widget = $repo->findById(5); }}

Page 123: Dive into

Doctrine Entitiesclass AcmeClass{ public function doSomething() { $repo = $this->doctrine->getRepository('AcmeBundle:Widgets'); $widget = $repo->findById(5); }} Bundle

name

Page 124: Dive into

Doctrine Entitiesclass AcmeClass{ public function doSomething() { $repo = $this->doctrine->getRepository('AcmeBundle:Widgets'); $widget = $repo->findById(5); }} Entity name

Page 125: Dive into

Using Doctrine

● Repositories can be explicitly defined for an entity

o (Similar to Zend's Db_Table object)

Page 126: Dive into

Doctrine Entities/** * @ORM\Table(name="widget") */class Widget{ /** * @var string $body * @ORM\Column(name="body", type="text", nullable=true) */ private $body; public function getBody() { ... } public function setBody($body) { ... }}

Page 127: Dive into

Doctrine Entities/** * @ORM\Table(name="widget") * @ORM\Entity( * repositoryClass="Acme\HelloBundle\Repository\WidgetRepository" * ) */class Widget{ /** * @var string $body * @ORM\Column(name="body", type="text", nullable=true) */ private $body; public function getBody() { ... } public function setBody($body) { ... }}

Repository

Page 128: Dive into

Doctrine Repositoriesuse Doctrine\ORM\EntityRepository;

class WidgetRepository extends EntityRepository{ public function findWidgetsByName($string) { ... }}

Page 129: Dive into

Using Doctrine

Doctrine provides two ways to access data

● Query Builder

● DQL (Doctrine Query Language)

Page 130: Dive into

Using DQL

● DQL is structured like SQL

● Aimed at Entities, not at tables

Page 131: Dive into

Using DQLclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $query = $this->entityManager->createQuery( "SELECT w FROM AcmeBlogBundle:Widgets w JOIN w.tag t WHERE t.title = :tag ORDER BY w.created DESC" ); $query->setParameter('tag', $tag); $results = $query->getResults();

return $results; }}

Page 132: Dive into

Using DQLclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $query = $this->entityManager->createQuery( "SELECT w FROM AcmeBlogBundle:Widgets w JOIN w.tag t WHERE t.title = :tag ORDER BY w.created DESC" ); $query->setParameter('tag', $tag); $results = $query->getResults();

return $results; }}

Entity Manager

Page 133: Dive into

Using DQLclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $query = $this->entityManager->createQuery( "SELECT w FROM AcmeBlogBundle:Widgets w JOIN w.tag t WHERE t.title = :tag ORDER BY w.created DESC" ); $query->setParameter('tag', $tag); $results = $query->getResults();

return $results; }}

Bundle Name

Page 134: Dive into

Using DQLclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $query = $this->entityManager->createQuery( "SELECT w FROM AcmeBlogBundle:Widgets w JOIN w.tag t WHERE t.title = :tag ORDER BY w.created DESC" ); $query->setParameter('tag', $tag); $results = $query->getResults();

return $results; }}

Entity Class

Page 135: Dive into

Using DQLclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $query = $this->entityManager->createQuery( "SELECT w FROM AcmeBlogBundle:Widgets w JOIN w.tag t WHERE t.title = :tag ORDER BY w.created DESC" ); $query->setParameter('tag', $tag); $results = $query->getResults();

return $results; }}

Placeholder

Page 136: Dive into

Using DQLclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $query = $this->entityManager->createQuery( "SELECT w FROM AcmeBlogBundle:Widgets w JOIN w.tag t WHERE t.title = :tag ORDER BY w.created DESC" ); $query->setParameter('tag', $tag); $results = $query->getResults();

return $results; }}

Placeholder Value

Page 137: Dive into

Using DQLclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $query = $this->entityManager->createQuery( "SELECT w FROM AcmeBlogBundle:Widgets w JOIN w.tag t WHERE t.title = :tag ORDER BY w.created DESC" ); $query->setParameter('tag', $tag); $results = $query->getResults();

return $results; }}

Result Collection

Page 138: Dive into

Using QueryBuilderclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $qb = $this->entityManager->createQueryBuilder(); $qb->select('w') ->from('AcmeBlogBundle:Widgets', 'w') ->innerJoin('w.tags', 't') ->where('t.title = :tag') ->setParameter('tag', $tag) ->orderBy('w.created'); $results = $qb->getQuery()->getResults();

return $results; }}

Bundle name

Page 139: Dive into

Using QueryBuilderclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $qb = $this->entityManager->createQueryBuilder(); $qb->select('w') ->from('AcmeBlogBundle:Widgets', 'w') ->innerJoin('w.tags', 't') ->where('t.title = :tag') ->setParameter('tag', $tag) ->orderBy('w.created'); $results = $qb->getQuery()->getResults();

return $results; }}

Entity name

Page 140: Dive into

Using QueryBuilderclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $qb = $this->entityManager->createQueryBuilder(); $qb->select('w') ->from('AcmeBlogBundle:Widgets', 'w') ->innerJoin('w.tags', 't') ->where('t.title = :tag') ->setParameter('tag', $tag) ->orderBy('w.created'); $results = $qb->getQuery()->getResults();

return $results; }}

Placeholder

Page 141: Dive into

Using QueryBuilderclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $qb = $this->entityManager->createQueryBuilder(); $qb->select('w') ->from('AcmeBlogBundle:Widgets', 'w') ->innerJoin('w.tags', 't') ->where('t.title = :tag') ->setParameter('tag', $tag) ->orderBy('w.created'); $results = $qb->getQuery()->getResults();

return $results; }}

Placeholder Value

Page 142: Dive into

Using QueryBuilderclass AcmeService { private $entityManager; public fucntion __construct(EntityManager $em) {...} public getWidgetsByTag($tag) { $qb = $this->entityManager->createQueryBuilder(); $qb->select('w') ->from('AcmeBlogBundle:Widgets', 'w') ->innerJoin('w.tags', 't') ->where('t.title = :tag') ->setParameter('tag', $tag) ->orderBy('w.created'); $results = $qb->getQuery()->getResults();

return $results; }}

Result Collection

Page 143: Dive into

Security Component

security: firewalls: secured_area: pattern: ^/ anonymous: ~ form_login: login_path: login check_path: login_check

Page 144: Dive into

Security Component

security: firewalls: secured_area: pattern: ^/ anonymous: ~ form_login: login_path: login check_path: login_check

Secure everything

Page 145: Dive into

Security Component

security: firewalls: secured_area: pattern: ^/foo anonymous: ~ form_login: login_path: login check_path: login_check

Secure things in:

/foo

Page 146: Dive into

Security Component

security: firewalls: secured_area: pattern: ^/foo anonymous: ~ form_login: login_path: login check_path: login_check

Allow anonymous

Page 147: Dive into

Security Component

security: firewalls: secured_area: pattern: ^/foo anonymous: ~ form_login: login_path: login check_path: login_check

login route

Page 148: Dive into

Security Component

security: firewalls: secured_area: pattern: ^/foo anonymous: ~ form_login: login_path: login check_path: login_check

login check route

Page 149: Dive into

Security Component

Oops! I accidentally the whole security, what should I do?

● Define Routes for login_path and check_path

● Make sure the login page isn't behind a secured firewall or access control

● Make sure check path is behind a firewall

● Multiple firewalls do not share security contexts!

Page 150: Dive into

Credits● Symfony Documentation

o Symfony.com/doc

● Fabien Potenciero What is symfonyo http://fabien.potencier.org/article/49/what-is-symfony2

● Symfony Live Presentationso Bernhard Schussek (Symfony Berlin / forms)

Page 151: Dive into

Credits

● Nerdery Symfony2 Fork

o github.com/TheNerdery/symfony-standard