Download pdf - Complex Sites with Silex

Transcript
Page 1: Complex Sites with Silex

Complex Sites with Silex

Chris Tankersley

ZendCon 2014

Page 2: Complex Sites with Silex

2

Who Am I?

● A PHP Developer for 10 Years● Lots of projects no one uses, and a few some do

● https://github.com/dragonmantank

Page 3: Complex Sites with Silex

3

What is Silex?

Page 4: Complex Sites with Silex

4

Microframework

● Built off of the Symfony2 Components

● Micro Service Container● Provides Routing● Provides Extensions

Page 5: Complex Sites with Silex

5

Why to Not Use Silex

● You have to piece things together

● Not great for large projects

Page 6: Complex Sites with Silex

6

Why use Silex?

● You can use the libraries you want

● Great for small/medium projects

● Prototypers best friend

Page 7: Complex Sites with Silex

7

Sites Change over time

Page 8: Complex Sites with Silex

8

Silex Allows Us To Adapt

Page 9: Complex Sites with Silex

9

Basic Silex App

Page 10: Complex Sites with Silex

10

Set up Silex

composer require “silex/silex”:”~1.2”

Page 11: Complex Sites with Silex

11

Sample Silex App

<?phprequire_once __DIR__ . '/../vendor/autoload.php';$app = new Silex\Application();$app->get('/', function() use ($app) { return 'Hello World';});$app->run();

Page 12: Complex Sites with Silex

12

Congrats!

Page 13: Complex Sites with Silex

13

And you add more pages

<?phprequire_once __DIR__ . '/../vendor/autoload.php';$app = new Silex\Application();$app->get('/', function() use ($app) {/*...*/});$app->get('/about, function() use ($app) {/*...*/});$app->get('/contact', function() use ($app) {/*...*/});$app->get('/services', function() use ($app) {/*...*/});$app->run();

Page 14: Complex Sites with Silex

14

Service Providers

Page 15: Complex Sites with Silex

15

What do they do?

● Allows code reuse● For both services and controllers

Page 16: Complex Sites with Silex

16

Service Providers

● Twig● URL Generator● Session● Validator● Form● HTTP Cache● HTTP Fragments● Security

● Remember Me● Switftmailer● Monolog● Translation● Serializer● Doctrine● Controllers as

Services

Page 17: Complex Sites with Silex

17

And you add templating

<?phprequire_once __DIR__ . '/../vendor/autoload.php';$app = new Silex\Application();$app->register(new Silex\Provider\TwigServiceProvider(), array( 'twig.path' => __DIR__.'/../views',));$app->get('/', function() use ($app) { return $app['twig']->render('homepage.html.twig');});$app->get('/about, function() use ($app) {/*...*/});$app->get('/contact', function() use ($app) {/*...*/});$app->get('/services', function() use ($app) {/*...*/});$app->run();

Page 18: Complex Sites with Silex

18

Adding a Form

● We need to generate the form● We need to accept the form● We need to e-mail the form

Page 19: Complex Sites with Silex

19

Now we add a form<?phprequire_once __DIR__ . '/../vendor/autoload.php';use Symfony\Component\HttpFoundation\Request;$app = new Silex\Application();$app->register(new Silex\Provider\TwigServiceProvider(), array( 'twig.path' => __DIR__.'/views',));$app->register(new Silex\Provider\FormServiceProvider());$app->register(new Silex\Provider\TranslationServiceProvider());$app->get('/', function() use ($app) {/*...*/});$app->get('/about, function() use ($app) {/*...*/});$app->get('/contact', function(Request $request) use ($app) { $form = $app['form.factory']->createBuilder('form') ->add('name') ->add('email') ->getForm() ; $form->handleRequest($request); if($form->isValid()) { $data = $form->getData(); // Mail it } return $app['twig']->render('contact.html.twig', array('form' => $form->createView()));});$app->get('/services', function() use ($app) {/*..});$app->run();

Page 20: Complex Sites with Silex

20

HTTP Method Routing

Page 21: Complex Sites with Silex

21

Whoops

Page 22: Complex Sites with Silex

22

Allow Both Methods<?phprequire_once __DIR__ . '/../vendor/autoload.php';use Symfony\Component\HttpFoundation\Request;$app = new Silex\Application();$app->register(new Silex\Provider\TwigServiceProvider(), array( 'twig.path' => __DIR__.'/views',));$app->register(new Silex\Provider\FormServiceProvider());$app->register(new Silex\Provider\TranslationServiceProvider());$app->get('/', function() use ($app) {/*...*/});$app->get('/about, function() use ($app) {/*...*/});$app->match('/contact', function(Request $request) use ($app) { $form = $app['form.factory']->createBuilder('form') ->add('name') ->add('email') ->getForm() ; $form->handleRequest($request); if($form->isValid()) { $data = $form->getData(); // Mail it } return $app['twig']->render('contact.html.twig', array('form' => $form->createView()));})->method('GET|POST');$app->get('/services', function() use ($app) {/*..});$app->run();

Page 23: Complex Sites with Silex

23

We've silently introduced a problem into our code

Page 24: Complex Sites with Silex

24

Code Quickly Turns to Spaghetti

http://commons.wikimedia.org/wiki/File:Spaghetti-prepared.jpg

Page 25: Complex Sites with Silex

25

Pretend to be a big framework

Page 26: Complex Sites with Silex

26

What do we need to do?

● Consistent File Layout● Separate out functionality● Make things more testable

Page 27: Complex Sites with Silex

27

Clean up our file structure

Page 28: Complex Sites with Silex

28

Break up that big file

● File for bootstrapping the app● File for routes● File for running the app

Page 29: Complex Sites with Silex

29

web/index.php

require_once __DIR__ . '/../vendor/autoload.php';

$app = new Silex\Application();

require_once __DIR__ . '/../app/bootstrap.php';require_once __DIR__ . '/../app/routes.php';

$app->run();

Page 30: Complex Sites with Silex

30

app/bootstrap.php

$config = include_once 'config/config.php';$app['config'] = $config;

$app->register(new Silex\Provider\TwigServiceProvider(), array( 'twig.path' => $app['config']['template_path'],));

$app->register(new Silex\Provider\FormServiceProvider());

$app->register(new Silex\Provider\TranslationServiceProvider());

Page 31: Complex Sites with Silex

31

app/routes.php

$app->get('/', function() use ($app) {/*...*/});$app->get('/about, function() use ($app) {/*...*/});$app->match('/contact', function(Request $request) use ($app) { $form = $app['form.factory']->createBuilder('form') ->add('name') ->add('email') ->getForm() ; $form->handleRequest($request); if($form->isValid()) { $data = $form->getData(); // Mail it } return $app['twig']->render('contact.html.twig', array('form' => $form->createView()));})->method('GET|POST');$app->get('/services', function() use ($app) {/*..});

Page 32: Complex Sites with Silex

32

Service Providers

Page 33: Complex Sites with Silex

33

For Services

● Implement Silex\ServiceProviderInterface

● Implement boot() and register()

Page 34: Complex Sites with Silex

34

For Controllers

● Implement Silex\ControllerProviderInterface

● Implement connect()

Page 35: Complex Sites with Silex

35

Sample Controller

use Silex\Application;use Silex\ControllerProviderInterface;

class BlogController implements ControllerProviderInterface { public function connect(Application $app) { $controllers = $app['controllers_factory']; $controllers->get('/', array($this, 'index')); $controllers->get('/inline', function() use ($app) { /* Logic Here */ }); }

protected function index(Application $app) { /* Logic Here */ }}

$app->mount('/blog', new BlogController());

Page 36: Complex Sites with Silex

36

Controllers as Services

● Ships with Silex● Allows attaching objects to routes

● Favors dependency injection● Framework Agnostic

Page 37: Complex Sites with Silex

37

Create our Object// src/MyApp/Controller/IndexController.phpnamespace MyApp\Controller;

use Silex\Application;use Symfony\Component\HttpFoundation\Request;

class IndexController{ public function indexAction(Application $app) { return $app['twig']->render('Index/index.html.twig'); }

public function aboutAction(Application $app) { /* … */ }

public function servicesAction(Application $app) { /* … */ }

public function contactAction(Application $app) { /* … */ }}

Page 38: Complex Sites with Silex

38

Register Controllers as Services

$config = include_once 'config/config.php';$app['config'] = $config;

$app->register(new Silex\Provider\TwigServiceProvider(), array( 'twig.path' => $app['config']['template_path'],));

$app->register(new Silex\Provider\FormServiceProvider());

$app->register(new Silex\Provider\TranslationServiceProvider());

$app['controller.index'] = $app->share(function() use ($app) {return new MyApp\Controller\IndexController();

});

Page 39: Complex Sites with Silex

39

Register our routes

$app->get('/', 'controller.index:indexAction')->bind('homepage');$app->get('/about', 'controller.index:aboutAction')->bind('about');$app->get('/services', 'controller.index:servicesAction')->bind('services');$app->match('/contact', 'controller.index:contactAction')->bind('contact')->method('GET|POST');

Page 40: Complex Sites with Silex

40

A Little Planning goes a Long Way

Page 41: Complex Sites with Silex

41

Questions?

Page 42: Complex Sites with Silex

42

Thanks!

● http://joind.in/talk/view/12080● @dragonmantank● [email protected]