42
Complex Sites with Silex Chris Tankersley ZendCon 2014

Complex Sites with Silex

Embed Size (px)

DESCRIPTION

Everyone knows that Silex is a great microframework for APIs and small sites, but what do you do when you want to build a large site, or your little tiny site has grown up? Silex has many different ways to let you build larger, complex websites that might still be too small for Symfony, but have outgrown the single page app it once was. We’ll look at what Silex offers us, and different ways we can structure our site.

Citation preview

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]