Symfony2 components to the rescue of your PHP projects
-
Upload
xavier-lacot -
Category
Technology
-
view
111 -
download
2
description
Transcript of Symfony2 components to the rescue of your PHP projects
Xavier Lacot – June 2012
Symfony2 components to the rescue of your PHP projects
2Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Hello
My name is Xavier Lacot
■ Web and Mobile at http://jolicode.com
■ Formerly PHP technical leader at Clever Age
■ Open Source convinced and contributor
■ In PHP, mainly Symfony
■ In javascript, etc.
■ Président of AFUP – the French PHP Users Association (afup.org)
■ Forum PHP
■ PHP Tour
■ http://twitter.com/xavierlacot
3Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Summary
1. PHP in 2012, a living ecosystem
2. 2005's PHP is now just pain
3. Migration strategies
■ The slow path
■ Switch progressively
4. Symfony components for your pleasure
■ Your prefered migration toolkit
■ Case Study
4Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Before we start
How many of you use a framework on a regular basis?
How many of you must deal with no-framework applications?
PHP in 2012, a living ecosystem
6Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
A few things about PHP
■ A pragmatic language built for the Web
■ PHP5 since 2005
■ One of the most used languages on the Web
PHP – solves problems since 1995
7Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
The language improves
■ PHP 5.3 introduced new concepts :
■ Usage of namespaces
■ Lambda and closures
■ Phar archives
■ “goto” WTF ???
namespace JoliCode\Conferences;use General\Talk\Session;
class SymfonyLive extends Session{ public function runPresentation() { // do something nice... }}
8Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Namespaces manipulation
■ Pro
■ No more collisions
■ Less ambiguity
■ Ahah, short class names. No more long classnames
■ Cons
■ Don't forget the use statement
use One\Full\Classname as Something;
$object = new Something;
9Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
And it still evolves
■ PHP 5.4
■ Some deprecated features removed
■ Performance improvements
■ Instance Method Calls
■ Closures inside objects
■ Traits, aka. assisted copy/paste
■ Arrays manipulation
$post = (new Post)->setTitle('Hello poneys')->save();
function fruits() { return ['apple', 'banana', 'orange'];}
echo fruits()[0]; // Outputs: apple
10Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
The ecosystem improves
■ Last years = bunch of new things
■ New (versions of) frameworks
■ New tools
■ Dependancies resolution
■ Code analysis
■ Continuous integration
■ Structuration of the projects
■ Standards
■ Discussions
■ More and more conferences
11Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
New frameworks
12Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
New frameworks
13Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
ClassLoader and PSR-0
■ PSR-0 :
■ A standardization agreement
■ Scope: classes naming and organization
■ Idea : match the path of the file containg a class to this full class name
class: Symfony\Component\HttpFoundation\Requestpath: vendor/src/Symfony/Component/HttpFoundation/Request.php
class: Twig_Extension_Corepath: vendor/twig/lib/Twig/Extension/Core.php
14Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
ClassLoader and PSR-0
class: Symfony\Component\HttpFoundation\Requestpath: vendor/src/Symfony/Component/HttpFoundation/Request.php
class: Twig_Extension_Corepath: vendor/twig/lib/Twig/Extension/Core.php
PEAR naming style
Namespaced classes styleautoloading path prefix
15Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Composer
■ A packages management tool
■ Launched in 2012
■ Composer : a tool for managing dependancies
■ Packagist.org : a repository of packages
■ See the talk of Jordi Boggiano and Nils Adermann
16Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Dependancies resolution using Composer
■ And more:
■ Post install commands
■ Configuration variables
■ etc.
{ "name": "joli/demo-project", "description": "A simple demo project", "require": { "php": ">=5.3.3", "symfony/symfony": "2.1.*", "seld/jsonlint": "1.0.0" }}
composer.json
$ php composer.phar installInstalling dependencies from lock file - Updating twig/twig (dev-master)
17Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Packagist
■ The packages repository behind packagist
■ A great resource for finding high quality contributions
■ Definitively forget about PEAR or distro packages
■ Fear that packagist might break? Build your own repository with satis - https://github.com/composer/satis
18Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
19Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
PHP gets is a professional language
■ PHP is not anymore an amateur language
■ Continuous integration (hi Jenkins, Sismo and Travis)
■ Unit tests (hi PHPUnit, SimpleTest, Atoum)
■ Code quality analysis and metrics
■ Code improvement tools (Hi PHP-CS-Fixer)
■ etc.
■ PHP developers have grew up since 2002
■ The language is more mature
■ The community too
20Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
21Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Cheers GitHub
22Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
GitHub
■ Social coding
■ Gathers many Open Source contributions
■ Watch, fork, comment, request pulls
■ Fun and nice
■ 2,500,000 projects,
~ 150,000 PHP projects
■ A great market for the developer!
PHP switched from SVN to Git
23Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
24Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Summary
1. PHP in 2012, a living ecosystem
2. 2005's PHP is now just pain
3. Migration strategies
■ The slow path
■ Switch progressively
4. Symfony components for your pleasure
■ Your prefered migration toolkit
■ Case study
2005's PHP is now just pain
26Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Oh yes we did it...
<html> <body> <?php include("includes/menu.inc.php"); $file = (isset($_GET['pages'])) ? "pages/".$_GET['page'].".php" : "pages/404.php";
if ( !file_exists($file) ) { @include("pages/404.php"); } else { $allowed = realpath('./pages');
if ( !@ereg($allowed."*", realpath($file)) ) { @include("pages/404.php"); } else { @include($file); } } ?> </body></html>
somewhere in 2002...
27Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Oh yes we did it...
<html> <body> <?php include("includes/menu.inc.php"); $file = (isset($_GET['pages'])) ? "pages/".$_GET['page'].".php" : "pages/404.php";
if ( !file_exists($file) ) { @include("pages/404.php"); } else { $allowed = realpath('./pages');
if ( !@ereg($allowed."*", realpath($file)) ) { @include("pages/404.php"); } else { @include($file); } } ?> </body></html>
somewhere in 2002...
■ HTML and PHP mix
28Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Oh yes we did it...
<html> <body> <?php include("includes/menu.inc.php"); $file = (isset($_GET['pages'])) ? "pages/".$_GET['page'].".php" : "pages/404.php";
if ( !file_exists($file) ) { @include("pages/404.php"); } else { $allowed = realpath('./pages');
if ( !@ereg($allowed."*", realpath($file)) ) { @include("pages/404.php"); } else { @include($file); } } ?> </body></html>
somewhere in 2002...
■ HTML and PHP mix
■ Direct access to superglobals
29Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Oh yes we did it...
<html> <body> <?php include("includes/menu.inc.php"); $file = (isset($_GET['pages'])) ? "pages/".$_GET['page'].".php" : "pages/404.php";
if ( !file_exists($file) ) { @include("pages/404.php"); } else { $allowed = realpath('./pages');
if ( !@ereg($allowed."*", realpath($file)) ) { @include("pages/404.php"); } else { @include($file); } } ?> </body></html>
somewhere in 2002...
■ HTML and PHP mix
■ Direct access to superglobals
■ Use of the @ operator
30Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Oh yes we did it...
<html> <body> <?php include("includes/menu.inc.php"); $file = (isset($_GET['pages'])) ? "pages/".$_GET['page'].".php" : "pages/404.php";
if ( !file_exists($file) ) { @include("pages/404.php"); } else { $allowed = realpath('./pages');
if ( !@ereg($allowed."*", realpath($file)) ) { @include("pages/404.php"); } else { @include($file); } } ?> </body></html>
somewhere in 2002...
■ HTML and PHP mix
■ Direct access to superglobals
■ Use of the @ operator
■ Urls tied to code structure
31Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Oh yes we did it...
<html> <body> <?php include("includes/menu.inc.php"); $file = (isset($_GET['pages'])) ? "pages/".$_GET['page'].".php" : "pages/404.php";
if ( !file_exists($file) ) { @include("pages/404.php"); } else { $allowed = realpath('./pages');
if ( !@ereg($allowed."*", realpath($file)) ) { @include("pages/404.php"); } else { @include($file); } } ?> </body></html>
somewhere in 2002...
■ HTML and PHP mix
■ Direct access to superglobals
■ Use of the @ operator
■ Urls tied to code structure
■ Duplicate code
32Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
33Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Not bad at all
■ That was 10 years ago!
■ No PHP5 at that time
■ That was still flexible
■ Just missed some concepts
34Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
The shit of today was great yesterday
So how did we improve things?
35Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
2004 → 2007
■ First professional PHP frameworks
■ Zend Framework
■ Code Igniter
■ Seagull PHP
■ Cake PHP
■ symfony 1
■ Jelix
■ Pluf
■ Yii
■ etc.
36Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
symfony 1
■ End 2005 : first public version (release 0.4)
■ Developers say “hurra”
ORM
Ajax
Plugins
Console
Conventions
Debug toolbar
Documentation
Functionnal and Unit tests
Internationalisation
Community
Helpers
Routing
Cache
MVC
37Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Still not sufficient
■ Several limits:
■ Very monolithic
■ Not very flexible
■ Almost no components - use it all or don't use it
■ Some things were a pain to achieve
■ Extensive use of Singleton
■ Hard (impossible) to write complete test suites
■ Developers only
■ Performances... !
■ Lots of bad contribs
■ Low average community level
38Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Migration strategies
40Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Summary
1. PHP in 2012, a living ecosystem
2. 2005's PHP is now just pain
3. Migration strategies
■ The slow path
■ Switch progressively
4. Symfony components for your pleasure
■ Your prefered migration toolkit
■ Case study
41Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Pre-conditions
■ You work since more than 5 years on your project
■ A bunch of functionnalities
■ The app is in production
■ Lots of users and data
■ A competent team
■ But
■ New developments are slow
■ Infrastructure problems
■ Hard to improve things
■ You want to trash it all, and code like in 2012
42Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Your reality
Pre-conditions
43Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Your expectations
Pre-conditions
44Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Strategy #1 – big bang
■ Most natural approach : rewrite everything
■ Pro:
■ A new solid and modern framework
■ Leave away from the old crappy codebase
■ Feel more happy
■ Cons:
■ Stop the company's business
■ Spend 1y+ re-developing everything
■ Have client cry
■ Complex migration scripts
■ Very risky
45Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
■ Don't do that
■ Too risky
■ Lot of pressure
■ Might lead to a disaster
■ Your boss won't be happy
■ Prefer a gradual approach
Strategy #1 – big bang
46Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Strategy #2 – Be progressive
■ Being progressive :
■ Re-write step by step
■ Control the way you build things
■ Use Framework parts, not the complete framework
■ Choose which parts to use
■ Gradually raise the level of your team
■ Less risky
■ And your boss will love you
47Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Step #1
Switch to PHP 5.3 or PHP 5.4
NOW.
thanks w3techs.com*
*
Historical codebase
PHP x.x
Historical codebase
PHP 5.3
48Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Step #1
■ Debian users :
■ Update your distribution version (eventually)
■ Update your packages (5 seconds)
■ Mac Users :
■ Please trash wamp and go grab http://php-osx.liip.ch/ (kudos Liip)
■ Windows users
Doh!
49Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Step #2
■ Create a solid foundation for your future new developments
■ Put new things in your project
■ Symfony components are up! Start with:
■ ClassLoader
■ DependencyInjection
■ HTTPFoundation
Historical codebase
Historical codebase
ClassLoader
DIC
HTTPFoundation
50Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Step #2 – install the components
■ Use composer
{ "autoload": { "psr-0": {} }, "name": "xavierlacot/blog", "description": "My old blog on steroids", "require": { "php": ">=5.3.3", "symfony/class-loader": "2.1.*", "symfony/dependency-injection": "2.1.*", "symfony/http-foundation": "2.1.*" }}
$ php composer.phar installInstalling dependencies from lock file - Updating symfony/class-loader (dev-master)
51Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Step #2 – install the components
■ What did we install while doing this?
■ ClassLoader allows to load classes automagically, when required, if they follow a naming convention defined by PSR-0;
■ DependancyInjection provides a set of tools for building object and classes in a standardized way, and reduce the BC breaks;
■ HTTPFoundation is the basic toolkit when working with HTTP requests (all web pages, for example).
■ We'll see all three later un the presentation
52Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Step #2 – install the components
■ Composer is great
■ It comes with an autoloader
■ Using the classes is simple :
■ And we're ready to start using the component classes!
<?phprequire 'vendor/autoload.php';
index.php
53Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Step #3 – start using the components
■ HTTPFoundation is the easiest component to start with – the one you can immediately use without breaking things
use Symfony\Component\HttpFoundation\Request;$request = Request::createFromGlobals();
CreateFromGlobals() analyses the superglobals and populates the Request object
index.php
54Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Step #3 – use HTTPFoundation
Time to change your historical code...
becomes
$pagename = (isset($_GET['page'])) ? $_GET['page'] : "404"; $file = sprintf('pages/%s.php', $pagename);
$pagename = $request->query->get('page', '404'); $file = sprintf('pages/%s.php', $pagename);
55Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Step #4
■ There's no step #4
■ The rest of the process is very similar
■ Integrate the component
■ Use it
■ Refactor your code
■ Simplify
■ Iterate – don't break everything at once. Use components gradually
Symfony components for your pleasure
57Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Summary
1. PHP in 2012, a living ecosystem
2. 2005's PHP is now just pain
3. Migration strategies
■ The slow path
■ Switch progressively
4. Symfony components for your pleasure
■ Your prefered migration toolkit
■ Case study
58Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
So what are the Symfony Components ?
■ Symfony components are :
■ A set of independent libraries
■ You can use them separately
■ High quality code components, tested and documented
■ Symfony components are not :
■ A bootstrap
■ They do not provide end user fonctionnalities
■ They are the bricks of your new platform, but you will have to glue them together
59Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Symfony components
■ The complete list is available at http://symfony.com/components
■ Symfony2 is built with the Symfony components
■ You will often use the symfony standard distribution, which contains all the components plus some bundles
■ Components do not depend on any third party library
■ All kind of stuff:
■ HTTP management
■ Cache
■ Files finder
■ Routing management
■ Internationalization process
■ Templating
■ Forms management
■ etc.
60Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Symfony components
■ Here is the list of what you can get :
■ BrowserKit
■ ClassLoader
■ Config
■ Console
■ CssSelector
■ DependencyInjection
■ DomCrawler
■ EventDispatcher
■ Finder
■ Form
■ HttpFoundation
■ HttpKernel
■ Locale
■ Process
■ Routing
■ Security
■ Serializer
■ Templating
■ Translation
■ Validator
■ Yaml
61Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Your prefered migration toolkit
■ I won't detail all the components
■ Here are (AMHA) the most useful (and straightforward) when migrating an old application:
■ ClassLoader
■ Console
■ DependencyInjection
■ Finder
■ HttpFoundation
■ Routing
■ Templating
■ Validator
■ If you want to use more, consider using Symfony2 at some point
62Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
ClassLoader
■ loads classes automatically if they follow PSR-0;
■ Migration process:
1. have your classes organization follow PSR-0 (renaming stuff)
2. Configure the ClassLoader
<?php
class prefixedLdapConnector{ public function __construct() { // stuff }}
ldap.php<?phpnamespace Prefix/Ldap/Client;
class Client{ public function __construct() { // stuff }}
src/Ldap/Client.php
63Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
ClassLoader
■ loads classes automatically if they follow PSR-0;
■ Migration process:
1. have your classes organization follow PSR-0 (renaming stuff)
2. Configure the ClassLoader
<?php
class prefixedLdapConnector{ public function __construct() { // stuff }}
ldap.php<?phpnamespace Prefix/Ldap;
class Client{ public function __construct() { // stuff }}
src/Prefix/Ldap/Client.php
64Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
ClassLoader
■ Composer's autoloader is taking care of vendors installed by composer
■ We must declare “our” classes:
■ Possible to declare several namespaces at once: registerNamespaces(array(...))
use Symfony\Component\ClassLoader\UniversalClassLoader;
$loader = new UniversalClassLoader();$loader->registerNamespace('Prefix', __DIR__.'/src/');$loader->register();
index.php
65Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Console
■ Your best friend for writing:
■ Command line tasks
■ Cron jobs
■ Repetitive asynchron tasks
■ Pros:
■ Input / Output management
■ Colorization
■ Well written
■ Extensible
66Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Console
■ Add the Console component to composer.json
■ Update the dependencies :
"require": { "php": ">=5.3.3", "symfony/class-loader": "2.1.*", "symfony/console": "2.1.*", "symfony/dependency-injection": "2.1.*", "symfony/http-foundation": "2.1.*"}
$ php composer.phar updateUpdating dependencies - Installing symfony/console (dev-master)
Writing lock fileGenerating autoload files
67Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Console■ Write a new command:
<?phpnamespace Prefix\Command;
class TwitterCommand extends Command{ protected function configure() { $this ->setName('joli:twitter') ->setDescription('Gets updates from twitter') ; }
protected function execute(InputInterface $input, OutputInterface $output) { $puller = $this->getContainer()->get('joli.twitter.puller'); $output->writeln("Contacting Twitter..."); $data = $puller->pull();
// do stuff with $data
$output->writeln(sprintf('Tweets fetched. %s new tweets', count($tweets))); }}
Hint: I did remove some “use” statements
src/Prefix/Command/TwitterCommand.php
68Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Console
■ Then create the executable file itself:
■ Fix this file's permissions:
#!/usr/bin/env php<?phprequire 'autoload.php';
use Prefix\Command\TwitterCommand;use Symfony\Component\Console\Application;
$application = new Application();$application->add(new TwitterCommand);$application->run();
console.php
$ chmod 755 console.php
69Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Console
■ And finally run the command:
$ ./console joli:twitterContacting Twitter...Tweets successfuly fetched. 0 new tweets
$ ./console Console Tool
Usage: [options] command [arguments]
Options: --help -h Display this help message. --quiet -q Do not output any message. --verbose -v Increase verbosity of messages. --version -V Display this application version. --ansi Force ANSI output. --no-ansi Disable ANSI output. --no-interaction -n Do not ask any interactive question.
Available commands: help Displays help for a command list Lists commandsjoli joli:twitter Gets updates from twitter
70Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Dependency Injection
■ “Dependency Injection” is a rather cryptic name
■ No drugs here, promise
■ Here is an “old school” function prototype:
■ It is bad, because:
■ The prototype will change when you will have new requirements
■ The order of the parameters is a hard constraint
■ Maybe one day you'll store menu items in a NoSQL database, and not in a relational one anymore
function makeMenu($sqlConnection, $menu, $nbItems = null, $level = 0, $startingWith = null)
Copyright me a long long long time ago*
*
71Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
72Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Your existing app
■ Your existing app does a lot of things
■ Sending emails
■ Parsing data
■ Writing logs
■ Storing data in databases
73Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Dependency Injection
■ The Dependency Injection component provides a dependency injection container
■ Imagine a large array of resources widely used in the whole application
■ This “DIC” has some capacities:
■ Resources are instantiated only when required;
■ It is extensible;
■ Each item of this DIC is called a “service”
■ The SQL connection is a service
■ Passing the DIC to a class automatically gives access to a large collection of services...!
74Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Dependency Injection
DICDIC
Initialization Execution
bootstrapCreate services $container->get('mailer')
Instantiate a non-existing
service
Call the service
75Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Implement your own services
■ In the migration plan:
■ convert the “service” functionnalities into real Symfony2 services,
■ Create binding to the existing calls
■ use them like before
■ In the future, put all your services in the container.
■ And use them from there
76Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
DIC migration
■ Imagine we have a “Mailer” class:
■ A mail is sent in our code with:
<?phpnamespace Prefix\Mailer;
class Mailer{ $prefix = '';
public function send($to, $subject, $body) { // etc. }}
function saveUser($name, $email){ // stuff here $mailer = new Mailer; $mailer->send($user->getEmail(), 'Welcome '.$user->getName(), 'A test'); }
77Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
DIC migration
■ Create the service container:
■ Pass it to our users management class
■ Use it:
use Symfony\Component\DependencyInjection\ContainerBuilder;
$container = new ContainerBuilder();$container->register('mailer', 'Mailer');
function saveUser($name, $email){ // stuff here $mailer = $this->container->get('mailer'); $mailer->send($user->getEmail(), 'Welcome '.$user->getName(), 'A test');
}
78Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
DIC migration
■ Benefits:
■ The Mailer object is now only created in one place
■ Its configuration is centralized
■ It is easy to override in the user management class
79Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
HttpFoundation
■ We have already used a little the HTTP Foundation component
■ One core concept of Symfony2 is the coverage of the framework
■ It handles Requests
■ And returns Responses
ApplicationUser
Request
Response
HTTP
80Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
HttpFoundation
■ HttpFoundation provides concepts for Request and Responses
■ Every input from the user, or output to the user should pass through this component
■ Request:
■ $request→request represents $_POST
■ $request→query represents $_GET
■ $request→cookies represents $_COOKIE
■ etc.
use Symfony\Component\HttpFoundation\Request;$request = Request::createFromGlobals();
81Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
HttpFoundation
■ Response:
■ Represents the stuff returned to the user through HTTP
■ It implements HTTP 1.1, the response is customizable:
use Symfony\Component\HttpFoundation\Response;$response = new Response();
$response->setContent('This will be the response content');$response->headers->set('Content-Type', 'text/html');$response->setStatusCode(200);
// send the Response$response->prepare($request);$response->send();
82Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Migration plan for using HttpFoundation
■ HTTPFoundation will help:
■ Making your application more secure
■ Enforce a normalization of the way the output is sent ot the user
■ Migration plan:
■ Start with systematically using the Request ibject in place of the superglobals
■ Use Response objects whenever possible
■ ob_* may help you
■ Use a templating system to move view content in separate files
83Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Routing Component – what we did before...
■ Didn't you find nasty the way we manage urls in our old app?
$file = (isset($_GET['pages'])) ? "pages/".$_GET['page'].".php" : "pages/404.php";
if ( !file_exists($file) ) { @include("pages/404.php"); } else { $allowed = realpath('./pages');
if ( !@ereg($allowed."*", realpath($file)) ) { @include("pages/404.php"); } else { @include($file); } }
84Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
■ Yes, it is far from perfect:
■ Urls enforce code organization
■ This system may cause security problems
■ What if the “$allowed” check doesn't work?
■ It is not extensible
■ The url ↔ action matching is hardcoded, which means no possible alternative
■ Bad for SEO
■ http://example.org/index.php?page=news&id=3657
■ The Symfony2 Routing component helps handling urls in an abstract way
Routing Component – what we did before...
85Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Routing Component
■ Routing is a mechanism which allows to manage the address map of an application
■ Very useful:
■ Better SEO
■ Better security
■ Help reorganize the application internally
■ Do not expose the technology you use
86Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Routing
■ There are two types of routing
■ “Descending” routing: maps an URI to an action the application must complete:
■ /blog must display the list of posts
■ /blog/2010/05/12/un-message.html must display the right post
■ /contact must display the contact form
■ “ascending” routing helps generate nice, SEO compliant URLs
/blog
Descending routingUser
87Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Routing component – migration plan
■ The migration plan for using this component will strongly depend on the way you developed your application.
■ Usually:
■ Add the component to composer.json, update
■ In the front controller, use the routing to match certain urls and handle the request in a clean way
■ This way, it won't affect other URLs
■ Once installed, always use the Router when exposing new URLs
88Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
In our example...
■ First, declare the routes
■ Then, match the requests to find the page to load
// declare the routes$routes = new RouteCollection();$routes->add( 'blog_show', new Route( '/blog/{year}/{month}/{slug}', array('pagename' => 'display_blog') ));
$context = new RequestContext();$context->fromRequest($request);$matcher = new UrlMatcher($routes, $context);
try{ $route = $matcher->match($request->getRequestUri()); // do things}catch (ResourceNotFoundException $e){ // handle exception }
Hint: I did remove some “use” statements
$route now contains the matched route parameters
89Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Generating URLs with the Routing Component
■ $router::generate() allows to generate a URL with parameters:
■ Of course, add the Routing as a service to the container!
$generator = new UrlGenerator($routes, $context);$url = $generator->generate('blog_show', array( 'slug' => 'hello-les-poneys', 'year' => '2011', 'month' => '11'));$response->setContent('Please go <a href="'.$url.'">here</a>');$response->send();
90Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Questions ?Contact
Xavier [email protected] 51 48 59 73
http://jolicode.comTwitter : @JoliCode
91Symfony2 components to the rescue of your PHP projectsJoliCode | Xavier Lacot | Symfony Live 2012
Credits
■ Photos – thanks to the photographers:
■ http://www.flickr.com/photos/artbandito/67829362/
■ http://capsizedatsea.tumblr.com/post/9559345143
■ http://memegenerator.net