A PHP Christmas Miracle - 3 Frameworks, 1 app

121
A PHP Christmas Miracle Ryan Weaver @weaverryan A story of deception, wisdom, and finding our common interface Saturday, December 3, 11

description

In this presentation, we walk take a flat PHP4-style application and gently migrate it into our own "framework", that uses components from Symfony2, Lithium, Zend Framework and a library called Pimple. By the end, you'll see how any ugly application can take advantage of the many wonderful tools available to PHP developers.

Transcript of A PHP Christmas Miracle - 3 Frameworks, 1 app

Page 1: A PHP Christmas Miracle - 3 Frameworks, 1 app

A PHP Christmas Miracle

Ryan Weaver@weaverryan

A story of deception, wisdom, and finding our common interface

Saturday, December 3, 11

Page 2: A PHP Christmas Miracle - 3 Frameworks, 1 app

Who is this dude?

• Co-author of the Symfony2 Docs

• Core Symfony2 contributor

• Co-owner of KnpLabs US

• Fiancee of the much more talented @leannapelham

http://www.knplabs.com/enhttp://www.github.com/weaverryan

@weaverryanSaturday, December 3, 11

Page 3: A PHP Christmas Miracle - 3 Frameworks, 1 app

Act 1:

A History of modern PHP

@weaverryanSaturday, December 3, 11

Page 4: A PHP Christmas Miracle - 3 Frameworks, 1 app

First, the facts

Saturday, December 3, 11

Page 5: A PHP Christmas Miracle - 3 Frameworks, 1 app

To put it politely...

Saturday, December 3, 11

Page 6: A PHP Christmas Miracle - 3 Frameworks, 1 app

We have a surplus of PHP frameworks

Saturday, December 3, 11

Page 7: A PHP Christmas Miracle - 3 Frameworks, 1 app

To put it honestly...

Saturday, December 3, 11

Page 8: A PHP Christmas Miracle - 3 Frameworks, 1 app

We have a sh*tload

Saturday, December 3, 11

Page 9: A PHP Christmas Miracle - 3 Frameworks, 1 app

‣ Symfony‣ Zend Framework‣ Lithium‣ Aura (formerly Solar)‣ Code Igniter‣ Yii‣ Cake‣ Fuel‣ Akelos‣ Kohana‣ Flow3‣ ...

Saturday, December 3, 11

Page 10: A PHP Christmas Miracle - 3 Frameworks, 1 app

And we solve common problems

@weaverryanSaturday, December 3, 11

Page 11: A PHP Christmas Miracle - 3 Frameworks, 1 app

‣ HTTP classes (e.g. request, response)‣ Routing‣ Controllers‣ Templates‣ Loggers‣ Database tools‣ Service containers‣ Security‣ Serialization

‣ Forms‣ Events‣ Mailing‣ Validation‣ Pagination‣ Menus‣ Search

Common Problems

@weaverryanSaturday, December 3, 11

Page 12: A PHP Christmas Miracle - 3 Frameworks, 1 app

Lack of sharing means duplicated efforts

Saturday, December 3, 11

Page 13: A PHP Christmas Miracle - 3 Frameworks, 1 app

But, there is some hope...

Saturday, December 3, 11

Page 14: A PHP Christmas Miracle - 3 Frameworks, 1 app

PSR-0

• The PHP community came together, sang Kumbaya and wrote up some class-naming standards

• PSR-0 isn’t a library, it’s just an agreement to name your classes in one of two ways

@weaverryanSaturday, December 3, 11

Page 15: A PHP Christmas Miracle - 3 Frameworks, 1 app

PSR-0 with namespaces

class: Symfony\Component\HttpFoundation\Request

path: vendor/src/Symfony/Component/HttpFoundation/Request.php

Namespace your classes and have the namespaces follow the directory structure

Saturday, December 3, 11

Page 16: A PHP Christmas Miracle - 3 Frameworks, 1 app

PSR-0 with underscores

class: Twig_Extension_Core

path: vendor/twig/lib/Twig/Extension/Core.php

Use underscores in your classes and follow the directory structure

Saturday, December 3, 11

Page 17: A PHP Christmas Miracle - 3 Frameworks, 1 app

But what does this mean?

• An "autoloader" is a tool you can use so that you don't have to worry about “including” classes before you use them

• Use anyone’s autoloader

• We're all still duplicating each other's work, but at least everyone’s autoloader does the same thing

@weaverryanSaturday, December 3, 11

Page 18: A PHP Christmas Miracle - 3 Frameworks, 1 app

What else can we agree on?

Saturday, December 3, 11

Page 19: A PHP Christmas Miracle - 3 Frameworks, 1 app

So far, not much

Saturday, December 3, 11

Page 20: A PHP Christmas Miracle - 3 Frameworks, 1 app

But we’ll see how all the libraries can still work

together

Saturday, December 3, 11

Page 21: A PHP Christmas Miracle - 3 Frameworks, 1 app

And we can always hope for a Christmas miracle

Saturday, December 3, 11

Page 22: A PHP Christmas Miracle - 3 Frameworks, 1 app

Act 2:

Starting with a Horrible App

@weaverryanSaturday, December 3, 11

Page 23: A PHP Christmas Miracle - 3 Frameworks, 1 app

How many of you use a framework on a regular

basis?

Saturday, December 3, 11

Page 24: A PHP Christmas Miracle - 3 Frameworks, 1 app

How many of you have been told that it's a bad idea to not

use a framework?

Saturday, December 3, 11

Page 25: A PHP Christmas Miracle - 3 Frameworks, 1 app

Was I the one who told you that?

Saturday, December 3, 11

Page 26: A PHP Christmas Miracle - 3 Frameworks, 1 app

Today we’re going to break the rules...

Saturday, December 3, 11

Page 27: A PHP Christmas Miracle - 3 Frameworks, 1 app

... build a framework from “scratch” ...

Saturday, December 3, 11

Page 28: A PHP Christmas Miracle - 3 Frameworks, 1 app

... and see why that’s no longer necessarily a bad

thing.

Saturday, December 3, 11

Page 29: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Refactor a crappy flat PHP application into a framework that makes sense

• Use as many libraries from as many quarreling PHP tribes as possible‣ Symfony‣ Zend Framework‣ Lithium‣ ... only lack of time prevents more...

Today’s 2 goals:

@weaverryanSaturday, December 3, 11

Page 30: A PHP Christmas Miracle - 3 Frameworks, 1 app

Our starting point

• Our app is a single file that fuels two pages

http://bit.ly/php-xmas

• Following along with the code of our app at:

Saturday, December 3, 11

Page 31: A PHP Christmas Miracle - 3 Frameworks, 1 app

Saturday, December 3, 11

Page 32: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Shucks, we even have a database connection

Saturday, December 3, 11

Page 33: A PHP Christmas Miracle - 3 Frameworks, 1 app

Open our Database connection

try { $dbPath = __DIR__.'/data/database.sqlite'; $dbh = new PDO('sqlite:'.$dbPath);} catch(PDOException $e) { die('Panic! '.$e->getMessage());}

// index.php

Saturday, December 3, 11

Page 34: A PHP Christmas Miracle - 3 Frameworks, 1 app

Try to get a clean URI

$uri = $_SERVER['REQUEST_URI'];if ($pos = strpos($uri, '?')) { $uri = substr($uri, 0, $pos);}

// index.php

Saturday, December 3, 11

Page 35: A PHP Christmas Miracle - 3 Frameworks, 1 app

Render the homepage

if ($uri == '/' || $uri == '') { echo '<h1>Welcome to PHP Santa</h1>'; echo '<a href="/letters">Readletters</a>'; if (isset($_GET['name'])) { echo sprintf( '<p>Oh, and hello %s!</p>', $_GET['name'] ); }}

// index.php

Saturday, December 3, 11

Page 36: A PHP Christmas Miracle - 3 Frameworks, 1 app

Print out some lettersif ($uri == '/letters') {

$sql = 'SELECT * FROM php_santa_letters'; echo '<h1>Read the letters to PHP Santa</h1>'; echo '<ul>'; foreach ($dbh->query($sql) as $row) { echo sprintf( '<li>%s - dated %s</li>', $row['content'], $row['received_at'] ); } echo '</ul>';}

// index.php

Saturday, December 3, 11

Page 37: A PHP Christmas Miracle - 3 Frameworks, 1 app

Got it?

Saturday, December 3, 11

Page 38: A PHP Christmas Miracle - 3 Frameworks, 1 app

Great, let’s clean this mess up

Saturday, December 3, 11

Page 39: A PHP Christmas Miracle - 3 Frameworks, 1 app

Act 3:

Symfony's HTTP Foundation

@weaverryanSaturday, December 3, 11

Page 40: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Our code for trying to get a clean URL is a bit archaic and probably error prone

• We're echoing content from our controllers, maybe we can evolve

Problems

@weaverryanSaturday, December 3, 11

Page 41: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Symfony’s HttpFoundation Component

• Gives us (among other things) a solid Request and Response class

Solution

@weaverryanSaturday, December 3, 11

Page 42: A PHP Christmas Miracle - 3 Frameworks, 1 app

Bring in HttpFoundation

mkdir -p vendors/Symfony/Component

git submodule add \ git://github.com/symfony/HttpFoundation.git \ vendors/Symfony/Component/HttpFoundation/

git submodule add \ git://github.com/symfony/ClassLoader.git \ vendors/Symfony/Component/ClassLoader

Saturday, December 3, 11

Page 43: A PHP Christmas Miracle - 3 Frameworks, 1 app

Current Status

@weaverryanSaturday, December 3, 11

Page 44: A PHP Christmas Miracle - 3 Frameworks, 1 app

• No matter what framework or libraries you use, you’ll need an autoloader

• We’ll use Symfony’s “ClassLoader”

• Each PSR-0 autoloader is very similar

Autoloading

@weaverryanSaturday, December 3, 11

Page 45: A PHP Christmas Miracle - 3 Frameworks, 1 app

Create a bootstrap file<?php// bootstrap.php

require __DIR__.'/vendors/Symfony/Component/ClassLoader/UniversalClassLoader.php';use Symfony\Component\ClassLoader\UniversalClassLoader;

// setup the autoloader$loader = new UniversalClassLoader();$loader->registerNamespace( 'Symfony', __DIR__.'/vendors');$loader->register();

Saturday, December 3, 11

Page 46: A PHP Christmas Miracle - 3 Frameworks, 1 app

... and include it

<?php// index.phprequire 'bootstrap.php';

// ...

Saturday, December 3, 11

Page 47: A PHP Christmas Miracle - 3 Frameworks, 1 app

So how does this help?

Saturday, December 3, 11

Page 48: A PHP Christmas Miracle - 3 Frameworks, 1 app

$uri = $_SERVER['REQUEST_URI'];if ($pos = strpos($uri, '?')) { $uri = substr($uri, 0, $pos);}

use Symfony\Component\HttpFoundation\Request;$request = Request::createFromGlobals();

// the clean URI - a lot of logic behind it!!!$uri = $request->getPathInfo();

... becomes ...

Saturday, December 3, 11

Page 49: A PHP Christmas Miracle - 3 Frameworks, 1 app

if (isset($_GET['name'])) { echo sprintf( '<p>Oh, and hello %s!</p>', $_GET['name'] );}

if ($name = $request->query->get('name')) { echo sprintf(

'<p>Oh, and hello %s!</p>',$name

);}

... becomes ...

Saturday, December 3, 11

Page 50: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Normalizes server variables across systems

• Shortcut methods to common things like getClientIp(), getHost(), getContent(), etc

• Nice object-oriented interface

The “Request” object

@weaverryanSaturday, December 3, 11

Page 51: A PHP Christmas Miracle - 3 Frameworks, 1 app

• We also have a Response object

• Instead of echoing out content, we populate this fluid object

The “Response” object

@weaverryanSaturday, December 3, 11

Page 52: A PHP Christmas Miracle - 3 Frameworks, 1 app

header("HTTP/1.1 404 Not Found");echo '<h1>404 Page not Found</h1>';echo '<p>This is most certainly *not* an xmas miracle</p>';

$content = '<h1>404 Page not Found</h1>';$content .= '<p>This is most certainly *not* an xmas miracle</p>';

$response = new Response($content);$response->setStatusCode(404);$response->send();

... becomes ...

Saturday, December 3, 11

Page 53: A PHP Christmas Miracle - 3 Frameworks, 1 app

Act 4:

Routing

@weaverryanSaturday, December 3, 11

Page 54: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Our app is a giant gross “if” statementProblems

if ($uri == '/' || $uri == '') { // ...} elseif ($uri == '/letters') { // ...} else { // ...}

• Grabbing a piece from the URL like /blog/my-blog-post will take some work

@weaverryanSaturday, December 3, 11

Page 55: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Lithium’s Routing library

• Routing matches URIs (e.g. /foo) and returns information we attached to that URI pattern

• All the nasty regex matching is out-of-sight

Solution

@weaverryanSaturday, December 3, 11

Page 56: A PHP Christmas Miracle - 3 Frameworks, 1 app

3 Steps to Bringing in an external tool

Saturday, December 3, 11

Page 57: A PHP Christmas Miracle - 3 Frameworks, 1 app

git submodule add git://github.com/UnionOfRAD/lithium.git vendors/lithium

#1 Download the library

Saturday, December 3, 11

Page 58: A PHP Christmas Miracle - 3 Frameworks, 1 app

// bootstrap.php// ...

$loader = new UniversalClassLoader();$loader->registerNamespace('Symfony', __DIR__.'/vendors');$loader->registerNamespace('lithium', __DIR__.'/vendors');

$loader->register();

#2 Configure the autoloader

Saturday, December 3, 11

Page 59: A PHP Christmas Miracle - 3 Frameworks, 1 app

use lithium\net\http\Router;$router = new Router();// ...

#3 Celebrate!

Saturday, December 3, 11

Page 60: A PHP Christmas Miracle - 3 Frameworks, 1 app

@weaverryan

Current Status

Saturday, December 3, 11

Page 61: A PHP Christmas Miracle - 3 Frameworks, 1 app

So how do we use the router?

Saturday, December 3, 11

Page 62: A PHP Christmas Miracle - 3 Frameworks, 1 app

Full disclosure: “use” statements I’m hiding from the

next page

use Symfony\Component\HttpFoundation\Request;use lithium\net\http\Router;use lithium\action\Request as Li3Request;

Saturday, December 3, 11

Page 63: A PHP Christmas Miracle - 3 Frameworks, 1 app

$request = Request::createFromGlobals();$li3Request = new Li3Request();// get the URL from Symfony's request, give it to lithium$li3Request->url = $request->getPathInfo();

a) Map URI to “controller”

// create a router, build the routes, and then execute it$router = new Router();$router->connect('/letters', array('controller' => 'letters'));$router->connect('/', array('controller' => 'homepage'));$router->parse($li3Request);

if (isset($li3Request->params['controller'])) { $controller = $li3Request->params['controller'];} else { $controller = 'error404';}

Saturday, December 3, 11

Page 64: A PHP Christmas Miracle - 3 Frameworks, 1 app

// execute the controller, send the request, get the response$response = call_user_func_array($controller, array($request));if (!$response instanceof Response) { throw new Exception(sprintf( 'WTF! Your controller "%s" didn\'t return a response!!', $controller ));}

$response->send();

b) Execute the controller*

* each controller is a flat function Saturday, December 3, 11

Page 65: A PHP Christmas Miracle - 3 Frameworks, 1 app

function homepage(Request $request) { $content = '<h1>Welcome to PHP Santa</h1>'; $content .= '<a href="/letters">Read the letters</a>'; if ($name = $request->query->get('name')) { $content .= sprintf( '<p>Oh, and hello %s!</p>', $name ); }

return new Response($content);}

The Controllers

Saturday, December 3, 11

Page 66: A PHP Christmas Miracle - 3 Frameworks, 1 app

function letters(Request $request){ global $dbh;

$sql = 'SELECT * FROM php_santa_letters'; $content = '<h1>Read the letters to PHP Santa</h1>'; $content .= '<ul>'; foreach ($dbh->query($sql) as $row) { $content .= sprintf( '<li>%s - dated %s</li>', $row['content'], $row['received_at'] ); } $content .= '</ul>';

return new Response($content);}

The Controllers$kitten--

Saturday, December 3, 11

Page 67: A PHP Christmas Miracle - 3 Frameworks, 1 app

function error404(Request $request){ $content = '<h1>404 Page not Found</h1>'; $content .= 'This is most certainly *not* an xmas miracle';

$response = new Response($content); $response->setStatusCode(404);

return $response;}

The Controllers

Saturday, December 3, 11

Page 68: A PHP Christmas Miracle - 3 Frameworks, 1 app

1. Request cleans the URI2. Router matches the URI to a route, returns a “controller” string3. We execute the controller function4. The controller creates a Response object5. We send the Response headers and content

The Big Picture

@weaverryanSaturday, December 3, 11

Page 69: A PHP Christmas Miracle - 3 Frameworks, 1 app

Your 20 line framework

Saturday, December 3, 11

Page 70: A PHP Christmas Miracle - 3 Frameworks, 1 app

Act 5:

Pimple!

@weaverryanSaturday, December 3, 11

Page 71: A PHP Christmas Miracle - 3 Frameworks, 1 app

• We’ve got lots of random, disorganized objects floating around

Problems

• And we can’t easily access them from within our controllers

@weaverryan

function letters(Request $request){ global $dbh;

// .... }

Saturday, December 3, 11

Page 72: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Pimple! - a Dependency Injection Container

• Dependency Injection Container:

the scariest word we could think of todescribe an array of objects on steroids

Solution

@weaverryanSaturday, December 3, 11

Page 73: A PHP Christmas Miracle - 3 Frameworks, 1 app

Remember: 3 Steps to bringing in an external tool

Saturday, December 3, 11

Page 74: A PHP Christmas Miracle - 3 Frameworks, 1 app

git submodule add git://github.com/fabpot/Pimple.git vendors/Pimple

#1 Download the library

Saturday, December 3, 11

Page 75: A PHP Christmas Miracle - 3 Frameworks, 1 app

// bootstrap.php// ...

require __DIR__.'/vendors/Pimple/lib/Pimple.php';

#2 Configure the autoloader

actually, it’s only one file - so just require it!

Saturday, December 3, 11

Page 76: A PHP Christmas Miracle - 3 Frameworks, 1 app

$c = new Pimple();

#3 Celebrate!

Saturday, December 3, 11

Page 77: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Use Pimple to create and store your objects in a central place

• If you have the Pimple container object, then you have access to every other object in your application

Pimple Creates Objects

@weaverryanSaturday, December 3, 11

Page 78: A PHP Christmas Miracle - 3 Frameworks, 1 app

$c = new Pimple();

$c['connection'] = $c->share(function() { $dsn = 'sqlite:'.__DIR__.'/data/database.sqlite'; return new PDO($dsn);});

Centralize the db connection

Saturday, December 3, 11

Page 79: A PHP Christmas Miracle - 3 Frameworks, 1 app

Centralize the db connection

$c1 = $c['connection'];$c2 = $c['connection'];

// they are the same - only one object is created!$c1 === $c2

Saturday, December 3, 11

Page 80: A PHP Christmas Miracle - 3 Frameworks, 1 app

Centralize the db connection

$c1 = $c['connection'];$c2 = $c['connection'];

// they are the same - only one object is created!$c1 === $c2

Saturday, December 3, 11

Page 81: A PHP Christmas Miracle - 3 Frameworks, 1 app

• So far, we’re using a “global” keyword to access our database connection

• But if we pass around our Pimple container, we always have access to anything we need - including the database connection

Access to what we need

@weaverryanSaturday, December 3, 11

Page 82: A PHP Christmas Miracle - 3 Frameworks, 1 app

Pass the container to the controller

$c = new Pimple();

// ...

$response = call_user_func_array( $controller, array($request, $c));

Saturday, December 3, 11

Page 83: A PHP Christmas Miracle - 3 Frameworks, 1 app

function letters(Request $request, Pimple $c){ $dbh = $c['connection'];

$sql = 'SELECT * FROM php_santa_letters'; $content = '<h1>Read the letters to PHP Santa</h1>'; $content .= '<ul>'; foreach ($dbh->query($sql) as $row) { // ... } // ...}

$kitten++

Saturday, December 3, 11

Page 84: A PHP Christmas Miracle - 3 Frameworks, 1 app

What else?

How about configuration?

Saturday, December 3, 11

Page 85: A PHP Christmas Miracle - 3 Frameworks, 1 app

$c = new Pimple();

// configuration$c['connection_string'] = 'sqlite:'.__DIR__ .'/data/database.sqlite';

$c['connection'] = $c->share(function(Pimple $c) { return new PDO($c['connection_string']);});

Saturday, December 3, 11

Page 86: A PHP Christmas Miracle - 3 Frameworks, 1 app

Further?

What about dependencies?

Saturday, December 3, 11

Page 87: A PHP Christmas Miracle - 3 Frameworks, 1 app

$c['request'] = $c->share(function() { return Request::createFromGlobals();});

$c['li3_request'] = $c->share(function($c) { $li3Request = new Li3Request(); $li3Request->url = $c['request']->getPathInfo();

return $li3Request;});

// ...$li3Request = $c['li3_request'];

Saturday, December 3, 11

Page 88: A PHP Christmas Miracle - 3 Frameworks, 1 app

With everything in the container, our “framework”

just got skinny

Saturday, December 3, 11

Page 89: A PHP Christmas Miracle - 3 Frameworks, 1 app

$c = new Pimple();// create objects in Pimple

// execute our routing, merge attributes to request$result = $c['router']->parse($c['li3_request']);$c['request']->attributes ->add($c['li3_request']->params);

// get controller and execute!$controller = $c['request']->attributes ->get('controller', 'error404');$response = call_user_func_array( $controller, array($c['request'], $c));

$response->send();Saturday, December 3, 11

Page 90: A PHP Christmas Miracle - 3 Frameworks, 1 app

Logging with ZF2

@weaverryanSaturday, December 3, 11

Page 91: A PHP Christmas Miracle - 3 Frameworks, 1 app

• I don’t have enough frameworks in my framework

Problems

• Oh yeah, and we need logging...

@weaverryanSaturday, December 3, 11

Page 92: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Zend Framework2

• ZF2 has a ton of components, including a logger

Solution

@weaverryanSaturday, December 3, 11

Page 93: A PHP Christmas Miracle - 3 Frameworks, 1 app

3 Steps to bringing in an external tool

Saturday, December 3, 11

Page 94: A PHP Christmas Miracle - 3 Frameworks, 1 app

git submodule add git://github.com/zendframework/zf2.git vendors/zf2

#1 Download the library

Saturday, December 3, 11

Page 95: A PHP Christmas Miracle - 3 Frameworks, 1 app

// bootstrap.php// ...

$loader = new UniversalClassLoader();$loader->registerNamespace('Symfony', __DIR__.'/vendors');$loader->registerNamespace('lithium', __DIR__.'/vendors');$loader->registerNamespace( 'Zend', __DIR__.'/vendors/zf2/library');

$loader->register();

#2 Configure the autoloader

Saturday, December 3, 11

Page 96: A PHP Christmas Miracle - 3 Frameworks, 1 app

use Zend\Log\Logger;use Zend\Log\Writer\Stream;

$logger = Logger($pimple['logger_writer']);

#3 Celebrate!

Yes we did just bring in a 100k+ lines of code for a simple logger :)

Saturday, December 3, 11

Page 97: A PHP Christmas Miracle - 3 Frameworks, 1 app

Current Status

@weaverryanSaturday, December 3, 11

Page 98: A PHP Christmas Miracle - 3 Frameworks, 1 app

use Zend\Log\Logger;use Zend\Log\Writer\Stream;

$c['log_path'] = __DIR__.'/data/web.log';$c['logger_writer'] = $c->share(function($pimple) { return new Stream($pimple['log_path']);});

$c['logger'] = $c->share(function($pimple) { return new Logger($pimple['logger_writer']);});

Create the Logger in our Fancy Container

Saturday, December 3, 11

Page 99: A PHP Christmas Miracle - 3 Frameworks, 1 app

function error404(Request $request, Pimple $c){ $c['logger']->log( 'Crap, 404 for '.$request->getPathInfo(), Logger::ERR ); $content = '<h1>404 Page not Found</h1>'; // ...}

And use it anywhere

Saturday, December 3, 11

Page 100: A PHP Christmas Miracle - 3 Frameworks, 1 app

Getting kinda easy, right?

Saturday, December 3, 11

Page 101: A PHP Christmas Miracle - 3 Frameworks, 1 app

What other libraries can you think to integrate?

Saturday, December 3, 11

Page 102: A PHP Christmas Miracle - 3 Frameworks, 1 app

Getting Organized

@weaverryanSaturday, December 3, 11

Page 103: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Our application has 4 major parts:1) autoloading setup2) Creation of container3) Definition of routes4) Definition of controllers5) The code that executes everything

• For our business, only #3 and #4 are important

• ... but it’s all jammed together

Problems

@weaverryanSaturday, December 3, 11

Page 104: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Some definitions

“Application” - the code that makes you money

“Framework” - under-the-hood code that impresses your geek friends

• To be productive, let’s “hide” the framework

Solution

@weaverryanSaturday, December 3, 11

Page 105: A PHP Christmas Miracle - 3 Frameworks, 1 app

• Our app basically has 2 files

‣ bootstrap.php: holds autoloading‣ index.php: holds

- container setup- definition of routes- definition of controllers- the code that executes it all

Starting point

@weaverryanSaturday, December 3, 11

Page 106: A PHP Christmas Miracle - 3 Frameworks, 1 app

‣ bootstrap.php: holds- autoloading- container setup- the code that executes it all

(as a function called _run_application())‣ controllers.php: holds controllers‣ routes.php: holds routes

‣ index.php: pulls it all together

Ending point

@weaverryanSaturday, December 3, 11

Page 107: A PHP Christmas Miracle - 3 Frameworks, 1 app

<?php

// index.php$c = require 'bootstrap.php';require 'routing.php';require 'controllers.php';

$response = _run_application($c);$response->send();

Nothing to see here...

Saturday, December 3, 11

Page 108: A PHP Christmas Miracle - 3 Frameworks, 1 app

// bootstrap.phpfunction _run_application(Pimple $c){ $c['router']->parse($c['li3_request']); $c['request']->attributes ->add($c['li3_request']->params);

$controller = $c['request']->attributes ->get('controller', 'error404');

return call_user_func_array( $controller, array($c['request'], $c) );}

“Framework” hidden away...

Saturday, December 3, 11

Page 109: A PHP Christmas Miracle - 3 Frameworks, 1 app

// routing.php$c['router']->connect( '/letters', array('controller' => 'letters'));

$c['router']->connect( '/{:name}', array( 'controller' => 'homepage', 'name' => null ));

Routes have a home

Saturday, December 3, 11

Page 110: A PHP Christmas Miracle - 3 Frameworks, 1 app

// controllers.phpuse Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\Response;

function homepage(Request $request) { // ...}

function letters(Request $request, $c){ // ...}

function error404(Request $request){ // ...}

Controllers have a home

Saturday, December 3, 11

Page 111: A PHP Christmas Miracle - 3 Frameworks, 1 app

To make $$$, work in routes.php and controllers.php

Saturday, December 3, 11

Page 112: A PHP Christmas Miracle - 3 Frameworks, 1 app

Final Thoughts

@weaverryanSaturday, December 3, 11

Page 113: A PHP Christmas Miracle - 3 Frameworks, 1 app

It doesn’t matter if you use a framework...

Saturday, December 3, 11

Page 114: A PHP Christmas Miracle - 3 Frameworks, 1 app

... inherited a legacy spaghetti system...

Saturday, December 3, 11

Page 115: A PHP Christmas Miracle - 3 Frameworks, 1 app

... or practice “not-invented-here” development

Saturday, December 3, 11

Page 116: A PHP Christmas Miracle - 3 Frameworks, 1 app

...an innumerable number of tools are available...

Saturday, December 3, 11

Page 117: A PHP Christmas Miracle - 3 Frameworks, 1 app

... so you can stop writing your framework ...

Saturday, December 3, 11

Page 118: A PHP Christmas Miracle - 3 Frameworks, 1 app

... and start writing your application

Saturday, December 3, 11

Page 119: A PHP Christmas Miracle - 3 Frameworks, 1 app

What’s available? Search GitHub

Saturday, December 3, 11

Page 120: A PHP Christmas Miracle - 3 Frameworks, 1 app

Thanks!Questions?

Ryan Weaver@weaverryan

Saturday, December 3, 11

Page 121: A PHP Christmas Miracle - 3 Frameworks, 1 app

• http://bit.ly/php-xmas• http://github.com/symfony• https://github.com/UnionOfRAD/lithium• https://github.com/zendframework/zf2• http://pimple.sensiolabs.org/

References

@weaverryan

And if we had more time...• http://twig.sensiolabs.org/• https://github.com/knplabs/KnpMenu• https://github.com/Seldaek/monolog• https://github.com/avalanche123/Imagine

Saturday, December 3, 11