Date post: | 18-Oct-2014 |
Category: |
Technology |
View: | 13,390 times |
Download: | 2 times |
The Wonderful World of the Symfony Components
by your friend:
Ryan Weaver@weaverryan
Friday, September 28, 12
Who is this dude?
• That “Docs” guy
• KnpLabs US - Symfony consulting, training, Kumbaya
• Writer for KnpUniversity.comscreencasts
• Husband of the much more talented @leannapelham
knplabs.comgithub.com/weaverryan@weaverryan
Friday, September 28, 12
Intro
Life before components(The Desert of the Real)
Friday, September 28, 12
Symfony consists of 23 individual components
Friday, September 28, 12
Components are available via Composer
Friday, September 28, 12
Snooze...
Friday, September 28, 12
Who Cares?
Friday, September 28, 12
We Suck at Sharingand that sucks for you
@weaverryan
1
Friday, September 28, 12
Including External Libraries is Depressing
Friday, September 28, 12
The Big Bummer :(
@weaverryan
• How do I autoload their files?
• Does their library depend on anything else?
• How do I even store their files in my project?
Friday, September 28, 12
Include a Zend Framework 1 component in symfony1
Friday, September 28, 12
Friday, September 28, 12
manually download the library and commit it
into your project
Friday, September 28, 12
if you don’t want the WHOLE library, carefully delete everything except the dependent components
Friday, September 28, 12
autoloading is completely custom ... blah gross!
Friday, September 28, 12
Components are the key to mastering your framework
@weaverryan
2
Friday, September 28, 12
If PHP is big, we’ll thriveIf PHP is small, we’ll die
@weaverryan
3
Friday, September 28, 12
Communities
@weaverryan
PHP is Huge! Right?
http://www.flickr.com/photos/kitty-kat/
Friday, September 28, 12
@weaverryan
PHP > Ruby
Friday, September 28, 12
Fragmentation
@weaverryan
But fragmentation makes us tiny, isolated, and misguided trend-setters
http://www.flickr.com/photos/slpunk99/7329609744
Friday, September 28, 12
PHP frameworks < Rails
@weaverryanFriday, September 28, 12
I don’t want a damned CakePHP Plugin!
@weaverryan
CakePHP
CodeIgniter
Friday, September 28, 12
Fragmentation
@weaverryan
• More information we have to know
• Difficult to hire
• Disjointed forums, StackOverflow
• Interoperability? What’s that?
Friday, September 28, 12
Components are shareable across all of PHP
Friday, September 28, 12
Act 1
Making Sharing Sexy
Friday, September 28, 12
PHP Framework Interoperability Group
http://www.php-fig.org/
Friday, September 28, 12
The United Nations of PHP
Friday, September 28, 12
(A)
The Problem of Autoloading
Friday, September 28, 12
My Autoloader doesn’t like your PHPs
@weaverryan
• The symfony1 autoloader doesn’t know where ZF1 classes live. The Zf1 autoloader doesn’t know where symfony1 classes live
• Each library has its own autoloader that you must discover, configure and use
Friday, September 28, 12
like a town where every store has its own currency
Friday, September 28, 12
From The Mountain:PSR-0 Class Naming Conventions
@weaverryan
“Thou shalt name your classes by
following a predictable pattern”
Friday, September 28, 12
class:sfRequest
path:lib/vendor/symfony/???idk
Friday, September 28, 12
class:Symfony\Component\HttpFoundation\Request
path:vendor/symfony/src/Symfony/Component/HttpFoundation/Request.php
Friday, September 28, 12
use Symfony\Component\ClassLoader\UniversalClassLoader;
$loader = new UniversalClassLoader();$loader->registerNamespaces(array( 'Zend' => __DIR__.'/path/to/zf'));
$loader->register();
Friday, September 28, 12
(B)
Managing Vendors in your project
Friday, September 28, 12
Composer
Friday, September 28, 12
{ "require": { "zendframework/ldap": "2.0.x-dev" }}
1) Composer.json
Friday, September 28, 12
$ curl -s https://getcomposer.org/installer | php
$ php composer.phar install
2) Composer.phar
Friday, September 28, 12
require 'vendor/autoload.php';
use Zend\Ldap\Ldap;
$options = array(...);$ldap = new Ldap($options);
3) Use It
Friday, September 28, 12
Friday, September 28, 12
Act 2
Your friendly, neighborhood Symfony Components
Friday, September 28, 12
The Symfony Components• HttpFoundation• HttpKernel• Event Dispatcher• Routing• CSSSelector• DomCrawler• BrowserKit• Config• Yaml• DependencyInjection• Security
@weaverryan
• OptionsResolver• Console• Filesystem• Finder• Locale• Process• Serializer• Templating• Form• Translation• Validator
Friday, September 28, 12
The Symfony Components• HttpFoundation• HttpKernel• Event Dispatcher• Routing• CSSSelector• DomCrawler• BrowserKit• Config• Yaml• DependencyInjection• Security
@weaverryan
• OptionsResolver• Console• Filesystem• Finder• Locale• Process• Serializer• Templating• Form• Translation• Validator
The “Framework” Components
Friday, September 28, 12
Level 1
HttpFoundationsymfony/http-foundation
Friday, September 28, 12
@weaverryan
{ "require": { "symfony/http-foundation": "2.1.x-dev" }}
php composer.phar install
<?php// your app
require 'vendor/autoload.php';
1
2
3
Fun to Install!
Friday, September 28, 12
@weaverryan
Request/foo
Response<h1>Hi!</h1>
?
?
?
? ?
?
MysteryPHP Code
Friday, September 28, 12
The Request
Friday, September 28, 12
GET /foo?p=v1 HTTP/1.1Host: knplabs.comAccept: text/htmlUser-Agent: Mozilla/5.0
// /foo?p=v1$uri = $_SERVER['REQUEST_URI'];$p = isset($_GET['p']) ? $_GET['p'] : '';$host = $_SERVER['HTTP_HOST'];$accept = $_SERVER['HTTP_ACCEPT'];$ua = $_SERVER['HTTP_USER_AGENT'];
Friday, September 28, 12
use Symfony\Component\HttpFoundation\Request;$request = Request::createFromGlobals();
$uri = $request->getPathInfo(); /foo$p = $request->query->get('p');$host = $request->getHost();$accept = $request->headers->get('Accept');
GET /foo?p=v1 HTTP/1.1Host: knplabs.comAccept: text/htmlUser-Agent: Mozilla/5.0
Friday, September 28, 12
The Response
Friday, September 28, 12
HTTP/1.1 200 OKDate: Tue, 04 Jun 2011 21:05:05 GMTContent-Type: text/htmlSet-Cookie:foo=fooval; path=/; httponly
<h1>Foo!</h1>
header('Content-Type', 'text/html');setcookie('foo', 'fooval');echo '<h1>Foo!</h1>';
Friday, September 28, 12
HTTP/1.1 200 OKDate: Tue, 04 Jun 2011 21:05:05 GMTContent-Type: text/htmlSet-Cookie:foo=fooval; path=/; httponly
<h1>Foo!</h1>
use Symfony\Component\HttpFoundation\Response;use Symfony\Component\HttpFoundation\Cookie;
$response = new Response('<h1>Foo!</h1>');$cookie = new Cookie('foo', 'fooval');$response->headers->setCookie($cookie);
$response->send();Friday, September 28, 12
A Mini Framework
Friday, September 28, 12
// not dependable!$uri = $_SERVER['REQUEST_URI'];
ob_start();if ($uri == '/') { echo 'Homepage! \o/';} else { echo 'sad missing page :/';}
header('X-TOKEN: Foo');
ob_end_flush();Friday, September 28, 12
$req = Request::createFromGlobals();
if ($req->getPathInfo() == '/') { $res = new Response('Homepage! \o/');} else { $res = new Response('sad missing page :/');}
$res->headers->set('X-SECRET', 'Foo');
$res->send();
Symfony3
Friday, September 28, 12
Get some learning about HttpFoundation
@weaverryan
• Docs: http://bit.ly/sf2-http-foundation• Code: http://bit.ly/sf2-http-foundation-code• API: http://bit.ly/sf2-http-foundation-api
Friday, September 28, 12
Level 2
HttpKernelsymfony/http-kernel
Friday, September 28, 12
@weaverryan
FrameworkRequest
Determine the controller
?
? ?
Execute it
Flush the ResponseResponse
Friday, September 28, 12
Framework:
A pattern for converting a request into a response
Friday, September 28, 12
@weaverryan
FrameworkRequest
Determine the controller
?
? ?
Execute it
Flush the ResponseResponse
Friday, September 28, 12
@weaverryan
HttpKernelRequest
Determine the controller
?
? ?
Execute it
Flush the ResponseResponse
Friday, September 28, 12
$kernel = new HttpKernel(...);$request = Request::createFromGlobals();$response = $kernel->handle($request);$response->send();
There be magic inside!
Friday, September 28, 12
These lines execute your Symfony application
(hint, see - web/app.php)
Friday, September 28, 12
... and Drupal 8 too ...
Friday, September 28, 12
Yea, this is abstract
Stay Tuned...
Friday, September 28, 12
Level 3
EventDispatchersymfony/event-dispatcher
Friday, September 28, 12
@weaverryan
Event Dispatcher
A classic “observer pattern”
Listener
Listener
Tell me when Lizgets to work
Tell me when Lizgets to work
Friday, September 28, 12
@weaverryan
Event Dispatcher
• Event Dispatcher: a classic “observer pattern”
Listener
Listener
Yo! I’m at work!
Friday, September 28, 12
@weaverryan
Event Dispatcher
• Event Dispatcher: a classic “observer pattern”
Listener
Listener
Liz is atwork!
Liz is atwork!
Friday, September 28, 12
Event Dispatcher
• Event Dispatcher: a classic “observer pattern”
Listener
Listener
She’s the best around!
I’m totally going to go talk
with her!!
Friday, September 28, 12
Level 4
Routingsymfony/routing
Friday, September 28, 12
@weaverryan
RouterUrl
Match againsta route
Return infoabout the routeRoute
Route
Friday, September 28, 12
$loader = new ClosureLoader();$router = new Router($loader, function() { $collection = new RouteCollection();
$route = new Route('/blog/{slug}'); $collection->add('blog', $route);
return $collection;});$results = $router->match('/blog/sflive');
array( 'slug' => 'sflive', '_route' => 'blog',)
Friday, September 28, 12
$loader = new ClosureLoader();$router = new Router($loader, function() { $collection = new RouteCollection();
$route = new Route('/blog/{slug}', array( '_controller' => 'SomeBundle:Blog:show' )); $collection->add('blog', $route);
return $collection;});$results = $router->match('/blog/sflive');
array( '_controller' => 'SomeBundle:Blog:show', 'slug' => 'sflive', '_route' => 'blog')
Friday, September 28, 12
Input: Request Information
Output: An array of info
Friday, September 28, 12
Level 5
A “Framework”
Friday, September 28, 12
$kernel = new HttpKernel(...);$request = Request::createFromGlobals();$response = $kernel->handle($request);$response->send();
Friday, September 28, 12
@weaverryan
HttpKernel::handle()
HttpFoundation
+
EventDispatcher
+
Routing (optional)
=
Framework
Friday, September 28, 12
@weaverryan
HttpKernel::handle()
Request
+
Determine Controller
+
Controller Returns a Response
=
Response
Friday, September 28, 12
Homework:Hack your Framework
... or do Karaoke later... your call
Friday, September 28, 12
@weaverryan
HttpKernel::handleRaw()private function handleRaw(Request $request, $type = self::MASTER_REQUEST){ // request $event = new GetResponseEvent($this, $request, $type); $this->dispatcher->dispatch(KernelEvents::REQUEST, $event);
if ($event->hasResponse()) { return $this->filterResponse($event->getResponse(), $request, $type); }
// load controller if (false === $controller = $this->resolver->getController($request)) { throw new NotFoundHttpException('Unable to find the controller); }
$event = new FilterControllerEvent($this, $controller, $request, $type); $this->dispatcher->dispatch(KernelEvents::CONTROLLER, $event); $controller = $event->getController();
// ... returns a response}
The kewlest code I know about... seriously
Friday, September 28, 12
@weaverryan
• Symfony\Component\HttpKernel\HttpKernel::handle()http://bit.ly/sf2-http-kernel-code
• Symfony Framework Important Classes
Symfony\Component\HttpKernel\EventListener\RouterListener- Executes the routing
Symfomy\Bundle\FrameworkBundle\Controller\ControllerResolver- Parses _controller and instantiates the controller object
step/var_dump()die; the core
Friday, September 28, 12
Timeline of events in the Symfony Framework
kernel.request
kernel.controller
kernel.response
Friday, September 28, 12
Profile events in the Symfony Framework
Friday, September 28, 12
The Symfony Components• HttpFoundation• HttpKernel• Event Dispatcher• Routing• CSSSelector• DomCrawler• BrowserKit• Config• Yaml• DependencyInjection• Security
@weaverryan
• OptionsResolver• Console• Filesystem• Finder• Locale• Process• Serializer• Templating• Form• Translation• Validator
AwesomeTools
Friday, September 28, 12
Process
symfony/process
Now with more Windows Love!
Friday, September 28, 12
@weaverryan
{ "require": { "symfony/process": "2.1.x-dev" }}
Find Symfony’s Process on Packagist.org
php composer.phar install
1
2
3
<?php// your app
require 'vendor/autoload.php';
Friday, September 28, 12
<?php// dinner.php
for ($i = 1; $i <= 3; $i++) { sleep(1); echo sprintf("Cooking... %s\n", $i);}
echo "DING! \n";
External Script to Cook Dinner
Friday, September 28, 12
Run the script synchronously
Friday, September 28, 12
// app.phprequire 'vendor/autoload.php';
use Symfony\Component\Process\Process;
$process = new Process('php dinner.php');// if dinner takes longer than 5 seconds// to cook, freak out!$process->setTimeout(5);
$process->run(function($type, $buffer) { echo $buffer;});
// executed after the command finishesif (!$process->isSuccessful()) { throw new \Exception('Process misbehaved')}
Friday, September 28, 12
Friday, September 28, 12
Run the script asynchronously
Friday, September 28, 12
$process = new Process('php dinner.php');$process->start();
// do more work hereecho "WORKING!!! \n";
while ($process->isRunning()) { // wait for the process to finish};echo $process->getOutput();
Friday, September 28, 12
Interacting via Stdin
Friday, September 28, 12
$process = new Process('php dinner.php');$process->setStdin('turkey');
“turkey” is read from Stdin
Friday, September 28, 12
$process = new Process('php dinner.php');$process->run(function($type, $buffer) { if ($type == 'err') { // perhaps do some logging? echo $buffer; }});
Handling things that blow up!
if (!$process->isSuccessful()) { echo sprintf( "Process failed! Exit code %s, '%s'\n", $process->getExitCode(), $process->getExitCodeText() );}
Friday, September 28, 12
Find out more about Process
@weaverryan
• Docs: http://bit.ly/sf2-process• Code: http://bit.ly/sf2-process-code• API: http://bit.ly/sf2-process-api
Friday, September 28, 12
SPORK!@kriswallsmith
$manager = new Spork\ProcessManager();$manager->fork(function() { // do something in another process! return 'Hello from '.getmypid();})->then(function(Spork\Fork $fork) { // do something in the parent process afterwards echo "{$fork->getPid()} says '{$fork->getResult()}'";});
Fork yourself some more PHP
https://github.com/kriswallsmith/spork
Friday, September 28, 12
Finder
symfony/finder
Friday, September 28, 12
From the Fablog
http://fabien.potencier.org/article/44/php-iterators-and-streams-are-awesome
use Symfony\Components\Finder\Finder; $s3 = new \Zend_Service_Amazon_S3($key, $secret);$s3->registerStreamWrapper("s3"); $finder = new Finder();$finder->name('photos*') ->size('< 100K') ->date('since 1 hour ago');foreach ($finder->in('s3://bucket-name') as $file) { // do something print $file->getFilename()."\n";}
Friday, September 28, 12
Find(er) out more about Finder
@weaverryan
• Docs: http://bit.ly/sf2-finder• Code: http://bit.ly/sf2-finder-code• API: http://bit.ly/sf2-finder-api
Friday, September 28, 12
Filesystem
symfony/filesystem
New in 2.1!
Friday, September 28, 12
@weaverryan
{ "require": { "symfony/filesystem": "2.1.x-dev" }}
Find Symfony’s Filesystem on Packagist.org
php composer.phar update symfony/filesystem
1
2
3
<?php// your app
require 'vendor/autoload.php';
Friday, September 28, 12
// ...
use Symfony\Component\Filesystem\Filesystem;
$filesystem = new Filesystem();$filesystem->copy( 'cowboy.jpg', 's3://my-bucket/cowboy.jpg');$filesystem->copy( 's3://my-bucket/rodeo.mov', 'rodeo.mov');$filesystem->mirror( 'thumbnails', 's3://my-bucket/thumbnails');
Friday, September 28, 12
// ...
use Symfony\Component\Filesystem\Filesystem;use Symfony\Component\Finder\Finder;
$finder = new Finder();$finder->name('*.jpg') ->date('since 1 hour ago'); ->in('thumbs');$filesystem = new Filesystem();$filesystem->chmod($finder, 0777);
Friday, September 28, 12
// ...
use Symfony\Component\Filesystem\Filesystem;
$filesystem = new Filesystem();$filesystem->touch('foo.txt');$filesystem->chmod('foo.txt', 0777);$filesystem->symlink('/some/dir', '/symlink/target')
Friday, September 28, 12
Find out more about Filesystem
@weaverryan
• Docs: http://bit.ly/sf2-filesystem• Code: http://bit.ly/sf2-filesystem-code• API: http://bit.ly/sf2-filesystem-api
Friday, September 28, 12
Console
symfony/console
Friday, September 28, 12
Friday, September 28, 12
<?php// command.php
$loader = require 'vendor/autoload.php';$loader->add('App', __DIR__);
use Symfony\Component\Console\Application;use App\Command\EchoCommand;
$app = new Application();$app->add(new EchoCommand());$app->run();
Friday, September 28, 12
namespace App\Command;
use Symfony\Component\Console\Command\Command;use Symfony\Component\Console\Input\InputInterface;use Symfony\Component\Console\Output\OutputInterface;
class EchoCommand extends Command{ protected function configure() { $this->setName('echo')->addArgument('msg'); }
public function execute( InputInterface $input, OutputInterface $output) { $output->writeln('Yo '.$input->getArgument('msg')); }}
Friday, September 28, 12
Output with pretty colors
Friday, September 28, 12
Find out more about Command
@weaverryan
• Docs http://bit.ly/sf2-console• Code http://bit.ly/sf2-console-code
• API http://api.symfony.com/master/namespaces.html-> and search for “Console”
Friday, September 28, 12
If you download Composer in the next 5 minutes, we’ll
throw in a special gift!
Friday, September 28, 12
CssSelector + DomCrawler
symfony/css-selectorsymfony/dom-crawler
Friday, September 28, 12
require 'vendor/autoload.php';use Symfony\Component\DomCrawler\Crawler;
$html = <<<'HTML'<!DOCTYPE html><html> <body> <p class="message">Hello World!</p> <p>Hello Crawler!</p> </body></html>HTML;
$crawler = new Crawler($html);
$crawler->filter('p')->eq(0)->attr('class');$crawler->filter('p')->eq(1)->text();
Friday, September 28, 12
Goutte!
Friday, September 28, 12
Config
symfony/config
Friday, September 28, 12
Config
@weaverryan
• Load configuration from many formats (YAML, PHP files, XML)
• Config Validation
• Caching for parsed config
Friday, September 28, 12
Validator
symfony/validator
Friday, September 28, 12
Shh... a little setup
Friday, September 28, 12
require 'vendor/autoload.php';
use Symfony\Component\Validator\Validator;use Symfony\Component\Validator\Mapping\ClassMetadataFactory;use Symfony\Component\Validator\ConstraintValidatorFactory;
// a little setup$metadata = new ClassMetadataFactory();$constraintFactory = new ConstraintValidatorFactory();$validator = new Validator($metadata, $constraintFactory);
Friday, September 28, 12
use Symfony\Component\Validator\Constraints\Email;
$value = 'ryan[AT]knplabs.com';$email = new Email();$email->message = 'Invalid! You entered {{ value }}';$errors = $validator->validateValue($value, $email);
if (count($errors) > 0) { echo strtr( $errors[0]->getMessageTemplate(), $errors[0]->getMessageParameters() );}
Friday, September 28, 12
34 Core Validators and counting• String length• Regular expressions• Ip addresses• Dates• Collections• File size, mime-type, etc
... and the brand new Luhn validatorfor credit card numbers thanks to@merk ----------------------------------->
@weaverryan
See the “Reference”section of the docs
Friday, September 28, 12
But wait there’s more!
Friday, September 28, 12
More Components
• DependencyInjection• Security• OptionsResolver• Locale• Serializer• Templating• Form• Translation
@weaverryanFriday, September 28, 12
Many components are easy
Friday, September 28, 12
Some are still wtf-hard
Friday, September 28, 12
(cough) Security (cough)
Friday, September 28, 12
DocumentationDocumentationDocumentation
Friday, September 28, 12
The Security Component
https://github.com/symfony/symfony-docs/pull/1604
WIP by @matthiasnoback
Friday, September 28, 12
Act 3
Kicking ass in the new PHP eco-system
Friday, September 28, 12
The PHP Ecosphere
• Symfony• Zend Framework• EZ Components• Drupal• ...• Individuals
@weaverryan
Symfony is only one part of the picture
What other stuff exists?
Friday, September 28, 12
How do we find good libraries?
Friday, September 28, 12
Friday, September 28, 12
Friday, September 28, 12
Some Favorites
Friday, September 28, 12
Minkbehat/mink
http://mink.behat.org/
By @everzet, written onFabien’s childhood computer
Friday, September 28, 12
Command a browser, find elements, click them, and fill out forms
$driver = new \Behat\Mink\Driver\SahiDriver('firefox');$session->visit('http://my_project.dev/some_page.php');
$page = $session->getPage();
$anchor = $page->find('css', '.something');$anchor->click();
// get the content of the new pageecho $page->getContent();
Friday, September 28, 12
Monologmonolog/monolog
https://github.com/Seldaek/monolog
Your Friend Jordi
Friday, September 28, 12
A Logger, where bells and whistles come standard
use Monolog\Logger;use Monolog\Handler\StreamHandler;use Monolog\Handler\FirePHPHandler;
// Create the logger$logger = new Logger('my_logger');$logger->pushHandler(new StreamHandler( __DIR__.'/my_app.log'));$logger->pushHandler(new FirePHPHandler());
$logger->addInfo('My logger is now ready');
Friday, September 28, 12
Zend Framework 2
They have some stuff
Friday, September 28, 12
Yay Find More!
Friday, September 28, 12
Epilogue
4 Reasons to getsilly-excited about
the Future
Friday, September 28, 12
1) Look for Participation & Consolidation
Friday, September 28, 12
Shared Building-blocks
• Drupal• phpBB• Midgard• Zikula• ez Publish 5• ...
@weaverryanFriday, September 28, 12
Less Library Duplication?
• Zend/Form• Zend/Serializer• Zend/Http• Zend/EventManager• Zend/Log• Zend/Navigation• ...
@weaverryan
• Symfony/Form• Symfony/Serializer• Symfony/HttpFoundation• Symfony/EventDispatcher• Monlog• KnpMenu• ...
Friday, September 28, 12
2) More high quality, community-grown libraries
Friday, September 28, 12
Solving 1 specific problem is a low barrier to entry
Friday, September 28, 12
Find them, fork them.
Friday, September 28, 12
Write their docs :)
Friday, September 28, 12
Programmers that write docs get hugs
Friday, September 28, 12
3) Easier upgrades
Friday, September 28, 12
4) Grow your Community
Friday, September 28, 12
Solutions exist outside of your framework
Friday, September 28, 12
Fabien will not come to your house and tell you about them
Friday, September 28, 12
Cast your vote by using the best libraries and improving
them
Friday, September 28, 12
and realize the power of the entire PHP community
Friday, September 28, 12
Thanks...
Ryan Weaver@weaverryan
Friday, September 28, 12
... and we love you!
Ryan Weaver@weaverryan
Ryan Weaver@weaverryan
https://joind.in/7218
Friday, September 28, 12