Symfony2

Powerful and flexible web application framework in state of the art PHP




SunshinePHP, Feb 7th 2013 © David Buchmann, Liip AG

About David Buchmann

Twitter: @dbu

David is a senior developper at Liip SA, specializing in Symfony2. He happens to also be a certified Scrum Master and sometimes enjoys doing the scrum master or product owner role for a project.

Liip is doing custom web development with PHP in Switzerland.

Symfony2

Bundles

Reusable code pieces with Symfony2 integration

Outline

Fr 13:30-14:30
Jordi Boggiano

Composer: Dependency management reloaded

Setting up a project

$ curl -s https://getcomposer.org/installer | php
$ php composer.phar create-project symfony/framework-standard-edition my-project 2.1.x-dev
            

Edit composer.json extra section:

"extra": {
    "symfony-app-dir": "app",
    "symfony-web-dir": "web",
    "symfony-assets-install": "symlink"
}
            

Configure your web server to point to web subfolder of my-project

Directory Layout

Create your first bundle

$ php app/console generate:bundle --namespace=Sunshine/HelloBundle --format=yml
# simply accept all defaults, they are fine
            

This creates code and adds our bundle to the Kernel

// app/AppKernel.php
public function registerBundles()
{
    $bundles = array(
        // ...
        new Sunshine\HelloBundle\SunshineHelloBundle(),
    );
    // ...

    return $bundles;
}
            

And also links the routing file in app/config/routing.yml

Bundle Directory Layout

The MVC of Symfony




Control

Routing: Map request to controller

# src/Sunshine/HelloBundle/Resources/config/routing.yml
sunshine_hello_homepage:
    pattern:  /sunshine/{name}
    defaults: { _controller: SunshineHelloBundle:Hello:index }
            

Symfony will:

Controller

namespace Sunshine\HelloBundle\Controller;

use Symfony\Component\HttpFoundation\Response;

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



View

Fr 11:30-12:30
Javier Equiluz

Twig templating


<!DOCTYPE html>
<html>
  <head>
    <title>Welcome to SunshinePHP!</title>
  </head>
  <body>
    <h1>Hello: {{ name }}</h1>
  </body>
</html>
            

Use template in Controller

namespace Acme\HelloBundle\Controller;

use Symfony\Component\HttpFoundation\Response;

class HelloController
{
  public function indexAction($name)
  {
    return $this->render(
        'SunshineHelloBundle:Hello:index.html.twig',
        array('name' => $name)
    );
  }
}
            



Model

Domain object

<?php
namespace Sunshine\HelloBundle\Entity;

class Page
{
  private $mainText;
  public function __construct($text)
  {
    $this->mainText = $text;
  }
  public function getMainText()
  {
    return $this->mainText;
  }
  public function setMainText($text)
  {
    $this->mainText = $text;
  }
}
            

Use it

Controller

$page = new \Sunshine\HelloBundle\Entity\Page('test');
return $this->render(
    'SunshineHelloBundle:Default:index.html.twig',
    array('name' => $name, 'page' => $page)
);
            

Template

<p>{{ page.mainText }}</p>
            

Doctrine ORM

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Page
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(name="main_text", type="string")
     */
    private $mainText;
    ...
            

Set up database

Console commands to manage database

$ app/console doctrine:schema:update --dump-sql
CREATE TABLE Page (id INTEGER NOT NULL, main_text VARCHAR(255) NOT NULL, PRIMARY KEY(id))

$ app/console doctrine:schema:update --force
Updating database schema...
Database schema updated successfully! "1" queries were executed

$ app/console doctrine:schema:drop --dump-sql
DROP TABLE Page
# --force would actually drop it
            

Insert Doctrine Objects

Controller

public function createAction()
{
    $page = new Page('SunshinePHP in sunny florida');

    $em = $this->getDoctrine()->getManager();
    $em->persist($page);
    $em->flush();

    return new Response('Created page id '.$page->getId());
}
            

Route

sunshine_hello_create:
    pattern:  /sunshine-create
    defaults: { _controller: SunshineHelloBundle:Default:create }
            

Read Doctrine Objects

Controller

use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
public function showAction($id)
{
    $em = $this->getDoctrine()->getManager();
    $repository = $em->getRepository('SunshineHelloBundle:Page')
    $page = $repository->find($id);
    if (! $page) {
        throw new NotFoundHttpException("no page $id");
    }
    // render as before
}
            

Route

sunshine_hello_show:
    pattern:  /sunshine-show/{id}
    defaults: { _controller: SunshineHelloBundle:Default:show }
            

Doctrine shell commands

Sa 13:30-14:30
Bernhard Schussek

Symfony2 form component

Form Controller

public function createAction(Request $request)
{
    $page = new Page('');

    $form = $this->createFormBuilder($page)
            ->add('mainText', 'textarea')
            ->getForm();

    return $this->render(
        'SunshineHelloBundle:Default:form.html.twig',
        array('form' => $form->createView()));
}
            

Template

<form action="{{ path('sunshine_hello_create') }}"
      method="post" {{ form_enctype(form) }}>
    {{ form_widget(form) }}
    <input type="submit" />
</form>
            

Handle Form Submit

// create form, then
if ($request->isMethod('POST')) {
    $form->bind($request);

    if ($form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($page);
        $em->flush();

        $showUrl = $this->generateUrl(
            'sunshine_hello_show',
            array('id' => $page->getId())
        );

        return $this->redirect($showUrl);
    }
}
            



Use an existing bundle

Use Bundles in your projects

Integrate KnpMarkdownBundle

php composer.phar require "knplabs/knp-markdown-bundle:1.2.*@dev"
            

Add to app/AppKernel.php

$bundles = array(
    // ...
    new Knp\Bundle\MarkdownBundle\KnpMarkdownBundle(),
);
            

Use it in template

{{ page.mainText|markdown }}
            



Working with Symfony2

Configuration and Environments

Using git

Configure filesystem permissions

If you can do chmod +a:

$ rm -rf app/cache/*
$ rm -rf app/logs/*
$ sudo chmod +a "www-data allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs
$ sudo chmod +a "`whoami` allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs
            

Otherwise set up ACL and:

$ sudo setfacl -R -m u:www-data:rwx -m u:`whoami`:rwx app/cache app/logs
$ sudo setfacl -dR -m u:www-data:rwx -m u:`whoami`:rwx app/cache app/logs
            
Sa 10:15-11:15
Hugo Hamon

Lots of interesting components

Dependeny Injection

Dependeny Injection

class MyClass
{
    public function do()
    {
        global $variable;
        echo $variable;
    }
}
            

NO!

Dependeny Injection

class MyClass
{
    public function do()
    {
        echo Registry::instance()->get('variable');
    }
}
            

Meh. A bit better but not good.

Dependeny Injection

class MyClass
{
    private $variable;
    public function __construct($variable)
    {
        $this->variable = $variable;
    }
    public function do()
    {
        echo $this->variable;
    }
}
            

This is dependency injection!

Dependeny Injection

Symfony2 Dependeny Injection

Thank you!



Questions / Input / Feedback ?



joind.in/7997 | @dbu

Related talks

Friday

Saturday