Complex Sites with Silex

Post on 27-May-2015

734 views 1 download

Tags:

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.

Transcript of Complex Sites with Silex

Complex Sites with Silex

Chris Tankersley

ZendCon 2014

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

3

What is Silex?

4

Microframework

● Built off of the Symfony2 Components

● Micro Service Container● Provides Routing● Provides Extensions

5

Why to Not Use Silex

● You have to piece things together

● Not great for large projects

6

Why use Silex?

● You can use the libraries you want

● Great for small/medium projects

● Prototypers best friend

7

Sites Change over time

8

Silex Allows Us To Adapt

9

Basic Silex App

10

Set up Silex

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

11

Sample Silex App

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

12

Congrats!

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();

14

Service Providers

15

What do they do?

● Allows code reuse● For both services and controllers

16

Service Providers

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

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

Services

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();

18

Adding a Form

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

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();

20

HTTP Method Routing

21

Whoops

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();

23

We've silently introduced a problem into our code

24

Code Quickly Turns to Spaghetti

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

25

Pretend to be a big framework

26

What do we need to do?

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

27

Clean up our file structure

28

Break up that big file

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

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();

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());

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) {/*..});

32

Service Providers

33

For Services

● Implement Silex\ServiceProviderInterface

● Implement boot() and register()

34

For Controllers

● Implement Silex\ControllerProviderInterface

● Implement connect()

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());

36

Controllers as Services

● Ships with Silex● Allows attaching objects to routes

● Favors dependency injection● Framework Agnostic

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) { /* … */ }}

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();

});

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');

40

A Little Planning goes a Long Way

41

Questions?

42

Thanks!

● http://joind.in/talk/view/12080● @dragonmantank● chris@ctankersley.com