Slide 1

Slide 1 text

The Symfony Framework YOUR FREE NEW TOOLKIT

Slide 2

Slide 2 text

> Husband of the much more talented @leannapelham knplabs.com twitter.com/weaverryan Hallo! > Lead contributor to the Symfony documentation
 > KnpLabs US - Symfony consulting, training & kumbaya > Writer for KnpUniversity.com awesome amazing PHP Tutorials!!!

Slide 3

Slide 3 text

Act 1 Dancing on your own? @weaverryan

Slide 4

Slide 4 text

Drupal 7 /** Implements hook_menu() */
 function dinosaur_menu() {
 $items['hello'] = array(
 'title' => 'ROOOOOOAR!',
 'page callback' => 'favorite_dinosaur',
 );
 
 return $items;
 }
 
 function favorite_dinosaur() {
 return 'Triceratops';
 }

Slide 5

Slide 5 text

Symfony, Silex, etc routes & controllers requests & responses service container @weaverryan

Slide 6

Slide 6 text

And now Symfony, Silex, D8 @weaverryan

Slide 7

Slide 7 text

@weaverryan require_once __DIR__.'/vendor/autoload.php';
 
 $app = new Silex\Application();
 
 $app->get('/hello/{name}', function($name) use($app) {
 return 'Hello '.$app->escape($name);
 });
 
 $app->run();


Slide 8

Slide 8 text

require_once __DIR__.'/vendor/autoload.php';
 
 $app = new Silex\Application();
 
 $app->get('/hello/{name}', function($name) use($app) {
 return 'Hello '.$app->escape($name);
 });
 
 $app->run();
 An entire application that says hallo! @weaverryan

Slide 9

Slide 9 text

Configure your web server

Slide 10

Slide 10 text

Or use the built-in PHP web server \o/ php -S localhost:8000 @weaverryan

Slide 11

Slide 11 text

* The built-in PHP web server can be used with Drupal too! @weaverryan

Slide 12

Slide 12 text

Request -> Response Framework Response: Hello Drupal! Routing: Determine a function that can create this page (the controller) Request: GET /hello/Drupal! The Controller: Our code: constructs the page @weaverryan

Slide 13

Slide 13 text

require_once __DIR__.'/vendor/autoload.php';
 
 $app = new Silex\Application();
 
 $app->get('/hello/{name}', function($name) use($app) {
 return 'Hello '.$app->escape($name);
 });
 
 $app->run();
 The route is matched when the URI is /hello/* @weaverryan

Slide 14

Slide 14 text

require_once __DIR__.'/vendor/autoload.php';
 
 $app = new Silex\Application();
 
 $app->get('/hello/{name}', function($name) use($app) {
 return 'Hello '.$app->escape($name);
 });
 
 $app->run();
 If the URI matches the route, Silex executes this function (the controller) @weaverryan

Slide 15

Slide 15 text

require_once __DIR__.'/vendor/autoload.php';
 
 $app = new Silex\Application();
 
 $app->get('/hello/{name}', function($name) use($app) {
 return 'Hello '.$app->escape($name);
 });
 
 $app->run();
 The value of {name} is passed as an argument to the controller @weaverryan

Slide 16

Slide 16 text

require_once __DIR__.'/vendor/autoload.php';
 
 $app = new Silex\Application();
 
 $app->get('/hello/{name}', function($name) use($app) {
 return 'Hello '.$app->escape($name);
 });
 
 $app->run();
 We construct the page and celebrate! @weaverryan (or non-alcoholic beverage of your choice)

Slide 17

Slide 17 text

Request -> Response Framework Response: Hello Drupal! Routing: Determine a function that can create this page (the controller) Request: GET /hello/Drupal! The Controller: Our code: constructs the page @weaverryan

Slide 18

Slide 18 text

Act 2 Hello Symfony @weaverryan

Slide 19

Slide 19 text

@weaverryan downloads the installer

Slide 20

Slide 20 text

@weaverryan my_dir_name

Slide 21

Slide 21 text

Symfony Project Structure configuration, templates PHP Classes 3rd Party Code @weaverryan

Slide 22

Slide 22 text

@weaverryan

Slide 23

Slide 23 text

@weaverryan

Slide 24

Slide 24 text

Hi, I’m the Symfony PacMan ghost! Look, things are working, you just don’t have any pages yet. Get to it! @weaverryan

Slide 25

Slide 25 text

Install ! Build a page! " @weaverryan

Slide 26

Slide 26 text

hello_world:
 path: /hello/{name}
 defaults:
 _controller: AppBundle\…sayHelloAction
 AppBundle\Controller\PoliteController::sayHelloAction @weaverryan

Slide 27

Slide 27 text

namespace AppBundle\Controller;
 
 use Symfony\Component\HttpFoundation\Response;
 
 class PoliteController
 {
 public function sayHelloAction($name)
 {
 return new Response('Hello '.$name);
 }
 }
 @weaverryan

Slide 28

Slide 28 text

@weaverryan

Slide 29

Slide 29 text

Request -> Response Framework The Controller: Our code: constructs the page Response: Hello Drupal! Routing: Determine a function that can create this page (the controller) Request: GET /hello/Drupal! @weaverryan

Slide 30

Slide 30 text

Debugging? @weaverryan

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

@weaverryan

Slide 33

Slide 33 text

@weaverryan

Slide 34

Slide 34 text

@weaverryan

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

Can we do even less work? @weaverryan

Slide 38

Slide 38 text

// ...
 
 class PoliteController
 {
 /**
 * @Route("/hello/{name}", name="hello_world")
 */
 public function sayHelloAction($name)
 {
 return new Response('Hello '.$name);
 }
 }
 @weaverryan

Slide 39

Slide 39 text

Act 3 Services and the “container” @weaverryan

Slide 40

Slide 40 text

Services == Useful Objects @weaverryan

Slide 41

Slide 41 text

The container == the object that contains all the services @weaverryan

Slide 42

Slide 42 text

In Silex, Symfony & Drupal 8 there is a “container”. If you have it, you can use any service (useful object) @weaverryan

Slide 43

Slide 43 text

In Symfony and Drupal 8 The container is pre-loaded with many useful services (objects)

Slide 44

Slide 44 text

That’s 224 built-in services @weaverryan

Slide 45

Slide 45 text

@weaverryan

Slide 46

Slide 46 text

How do I get access to the container inside a controller? @weaverryan

Slide 47

Slide 47 text

/**
 * @Route("/hello/{name}", name="hello_world")
 */
 public function sayHelloAction($name)
 {
 $html = $this->container->get('templating')->render(
 'polite/sayHello.html.twig',
 ['myName' => $name]
 );
 
 return new Response($html);
 }
 @weaverryan

Slide 48

Slide 48 text

{% extends 'base.html.twig' %}
 
 {% block body %}
 Hello {{ myName }}!
 {% endblock %}
 @weaverryan

Slide 49

Slide 49 text

Request -> Response Framework The Controller: Our code: constructs the page Response: Hello Drupal! Container (with services) Routing: Determine a function that can create this page (the controller) Request: GET /hello/Drupal! @weaverryan

Slide 50

Slide 50 text

What else does Symfony do? @weaverryan

Slide 51

Slide 51 text

Doctrine ORM $em = $this->container ->get('doctrine.orm.entity_manager'); 
 $post = $em->getRepository('AppBundle:Post')
 ->findOneBySlug($slug);
 
 // ...
 
 $em->persist($post);
 $em->flush();
 @weaverryan

Slide 52

Slide 52 text

or just use the DBAL or PDO $conn = $this->container ->get('database_connection'); 
 $sql = 'SELECT id, name FROM post';
 $posts = $conn->fetchAll($sql); @weaverryan

Slide 53

Slide 53 text

Forms $form = $this->container->get('form.factory') ->createBuilder()
 ->add('email', 'email')
 ->add('username', 'text')
 ->add('gender', 'choice', [
 'choices' => ['f' => 'Female', 'm' => 'Male']
 ])
 ->getForm();
 
 $form->handleRequest($request);
 if ($form->isValid()) {
 $data = $form->getData();
 // do some stuff
 }
 
 $html = $this->container->get('templating')->render(
 'user/register.html.twig',
 ['form' => $form->createView()]
 );
 
 return new Response($html);

Slide 54

Slide 54 text

Forms {{ form_start(form) }}
 {{ form_row(form.email) }}
 {{ form_row(form.username) }}
 {{ form_row(form.gender) }}
 
 Do it!
 {{ form_end(form) }} @weaverryan

Slide 55

Slide 55 text

or just do it yourself $email = $request->request->get('email');
 $username = $request->request->get('username');
 $gender = $request->request->get('gender'); @weaverryan

Slide 56

Slide 56 text

… and infinitely more with community bundles @weaverryan

Slide 57

Slide 57 text

Act 4 Creating your own Services @weaverryan

Slide 58

Slide 58 text

Now we want to select a random greeting each time @weaverryan

Slide 59

Slide 59 text

Put this logic in our controller? How about a flat function somewhere? @weaverryan

Slide 60

Slide 60 text

namespace AppBundle\Greet;
 
 class RandomGreeter
 {
 private static $greetings = [
 'Hello %s',
 'Hola %s!',
 'git blame. Ah, I knew it was %s!'
 ];
 
 public function randomlyGreet($name)
 {
 $key = array_rand(self::$greetings);
 $greeting = self::$greetings[$key];
 
 return sprintf($greeting, $name);
 }
 }

Slide 61

Slide 61 text

public function sayHelloAction($name)
 {
 $greeter = new RandomGreeter();
 $greeting = $greeter->randomlyGreet($name);
 
 $html = $this->container->get('templating')->render(
 'polite/sayHello.html.twig',
 ['theGreeting' => $greeting]
 );
 
 return new Response($html);
 } @weaverryan

Slide 62

Slide 62 text

Could we log which greeting was chosen? @weaverryan

Slide 63

Slide 63 text

@weaverryan

Slide 64

Slide 64 text

public function sayHelloAction($name)
 {
 $greeter = new RandomGreeter();
 $greeting = $greeter->randomlyGreet($name);
 
 $this->container->get('logger')
 ->info('Created greeting: '.$greeting);
 
 // ...
 }
 @weaverryan

Slide 65

Slide 65 text

Could we log from inside RandomGreeter? @weaverryan

Slide 66

Slide 66 text

class RandomGreeter
 {
 public function randomlyGreet($name)
 {
 $key = array_rand(self::$greetings);
 $greeting = self::$greetings[$key];
 
 $this->container->get('logger')
 ->info('Created greeting: '.$greeting);
 
 return sprintf($greeting, $name);
 }
 } There’s no container property! That’s magic only the controller has

Slide 67

Slide 67 text

omg DEPENDENCY INJECTION @weaverryan

Slide 68

Slide 68 text

class RandomGreeter
 {
 private $logger;
 
 public function __construct($logger)
 {
 $this->logger = $logger;
 }
 
 // ...
 }
 @weaverryan

Slide 69

Slide 69 text

class RandomGreeter
 {
 private $logger;
 
 public function __construct(LoggerInterface $logger)
 {
 $this->logger = $logger;
 }
 
 // ...
 }
 @weaverryan If you’re feeling fancy and/or awesome

Slide 70

Slide 70 text

class RandomGreeter
 {
 private $logger;
 
 // ...
 
 public function randomlyGreet($name)
 {
 $key = array_rand(self::$greetings);
 $greeting = self::$greetings[$key];
 
 $this->logger ->info('Created greeting: '.$greeting);
 
 return sprintf($greeting, $name);
 }
 }


Slide 71

Slide 71 text

public function sayHelloAction($name)
 {
 $greeter = new RandomGreeter( $this->container->get('logger') );
 $greeting = $greeter->randomlyGreet($name);
 
 // ...
 } @weaverryan

Slide 72

Slide 72 text

Act 5 Teach Symfony how to instantiate your services @weaverryan

Slide 73

Slide 73 text

services:
 my_random_greeter:
 class: AppBundle\Greet\RandomGreeter
 arguments:
 - "@logger"
 @weaverryan

Slide 74

Slide 74 text

services:
 my_random_greeter:
 class: AppBundle\Greet\RandomGreeter
 arguments:
 - "@logger"


Slide 75

Slide 75 text

public function sayHelloAction($name)
 {
 /* $greeter = new RandomGreeter(
 $this->container->get('logger')
 ); */
 
 $greeter = $this->container ->get('my_random_greeter');
 $greeting = $greeter->randomlyGreet($name);
 
 // ...
 }
 @weaverryan

Slide 76

Slide 76 text

Act 6 Events (extra credit) @weaverryan

Slide 77

Slide 77 text

Just like Drupal “hooks”, Silex has events @weaverryan

Slide 78

Slide 78 text

“Hi! When event XXXXX happens, execute this function. kthxbai” YOU CAN TELL SILEX @weaverryan

Slide 79

Slide 79 text

EVENTS kernel.view kernel.response Request -> Response Framework The Controller: Our code: constructs the page Container (with services) EVENT kernel.controller Response: Hello Drupal! Routing: Determine a function that can create this page (the controller) Request: GET /hello/Drupal! EVENT kernel.request @weaverryan

Slide 80

Slide 80 text

What if we didn’t return a Response from the controller?

Slide 81

Slide 81 text

public function sayHelloAction($name)
 {
 $greeter = $this->container ->get('my_random_greeter');
 $greeting = $greeter->randomlyGreet($name);
 
 return [
 'template' => 'polite/sayHello.html.twig',
 'variables' => ['theGreeting' => $greeting]
 ];
 } @weaverryan

Slide 82

Slide 82 text

@weaverryan I’m so angry right now!!!!!

Slide 83

Slide 83 text

class RenderArrayViewSubscriber implements EventSubscriberInterface
 {
 private $templating;
 
 public function __construct(EngineInterface $templating)
 {
 $this->templating = $templating;
 }
 
 public function onView()
 {
 // call me if the controller does not
 // return a Response
 }
 
 public static function getSubscribedEvents()
 {
 return ['kernel.view' => 'onView'];
 }
 }


Slide 84

Slide 84 text

services:
 # ...
 
 listener.render_array_view_listener:
 class: AppBundle\EventListener\RenderArrayViewSubscriber
 arguments:
 - "@templating"
 tags:
 - { name: kernel.event_subscriber }
 @weaverryan

Slide 85

Slide 85 text

public function onView(GetResponseForControllerResultEvent $event)
 {
 $controllerResult = $event->getControllerResult();
 
 if (!is_array($controllerResult)) {
 return;
 }
 if (!isset($controllerResult['template'])) {
 return;
 }
 
 $template = $controllerResult['template'];
 $variables = $controllerResult['variables'];
 $html = $this->templating->render($template, $variables);
 
 $response = new Response($html);
 $event->setResponse($response);
 }

Slide 86

Slide 86 text

Act 7 Build something amazing @weaverryan

Slide 87

Slide 87 text

It’d be nice to learn by looking at a real, fully- feature application @weaverryan “

Slide 88

Slide 88 text

@weaverryan

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

@weaverryan Use + the Symfony plugin http://bit.ly/phpstorm-symfony

Slide 91

Slide 91 text

http://symfony.com/doc

Slide 92

Slide 92 text

@weaverryan KnpUniversity.com Screencasts

Slide 93

Slide 93 text

@weaverryan require_once __DIR__.'/vendor/autoload.php';
 
 $app = new Silex\Application();
 
 $app->get('/hello/{name}', function($name) use($app) {
 return 'Hello '.$app->escape($name);
 });
 
 $app->run();
 Use Silex!

Slide 94

Slide 94 text

Use D8 @weaverryan

Slide 95

Slide 95 text

Act 8 , & @weaverryan

Slide 96

Slide 96 text

PRINCIPAL THEMES • Request/Response • Routing/Controller • PHP Namespaces/Autoloading • Services/Container 
 • Events/Listeners 
 • Profiler All are the same in Silex, Drupal & Symfony @weaverryan

Slide 97

Slide 97 text

You can use Silex to learn Drupal! @weaverryan

Slide 98

Slide 98 text

You can use Silex to learn Symfony! @weaverryan

Slide 99

Slide 99 text

You can use Symfony to learn Drupal! @weaverryan

Slide 100

Slide 100 text

https://www.flickr.com/photos/zzpza/32697842 Finally, We have more tools to solve problems

Slide 101

Slide 101 text

Ryan Weaver @weaverryan THANK YOU!