Development Manager @ PITECH+PLUS
Symfony Certified Developer
lenard.palko@gmail.com
@lenardpalko
+1,000
code contributors
+300,000
Symfony developers
+1,000,000
Monthly downloads
www.symfony.com
https://www.flickr.com/photos/wonderlane/3909074244/
$ sudo curl -LsS http://symfony.com/installer -o /usr/local/bin/symfony
$ sudo chmod a+x /usr/local/bin/symfony
$ symfony new my_project 2.6.0
$ composer create-project symfony/framework-standard-edition my_project_name "2.6.*"
https://www.flickr.com/photos/ogimogi/2253657555
Symfony Components are a set of decoupled and reusable PHP libraries. They are becoming the standard foundation on which the best PHP applications are built on. You can use any of these components in your own applications independently from the Symfony Framework.
www.symfony.com
The Symfony Components provide the low-level building blocks that you need to build a web product so that YOU can focus on what matters most for Drupal.
The ClassLoader component provides tools to autoload your classes and cache their locations for performance.
www.symfony.com
manually include all files that contain the classes
vs
just using a class
PHP Framework Interop Group
results in PSR
PHP Standard Recommendation
PSR-0 -> Autoloading Standard
PSR-1 -> Basic Coding Standard
PSR-2 -> Coding Style Guide
PSR-3 ->Logger Interface
PSR-4 -> Improved Autoloading
user-code : hey @php, I want to create a new Vendor\Package\Class object
php : oups ... I don't have it, @autoloader, could you load it
autoloader : I know that class files are in 'src' folder
autoloader : so I'll try to include src/Vendor/Package/Class.php
autoloader : ok ... found it ... you can use it now
use Vendor\Package\Class;
$class = new Class();
src/
Vendor/
Package/
Class.php
require __DIR__.'/lib/ClassLoader/Psr4ClassLoader.php';
$loader = new Psr4ClassLoader();
$loader->addPrefix('Vendor\\Package\\', 'src');
$loader->register(); // register the autoloader
curl -sS https://getcomposer.org/installer | php
{
"name": "drupal/core",
"description": "Drupal is an open source ...",
"type": "drupal-core",
"license": "GPL-2.0+",
"require": {
"php": ">=5.4.5",
"sdboyer/gliph": "0.1.*",
"symfony/class-loader": "2.6.*",
"symfony/css-selector": "2.6.*",
"symfony/dependency-injection": "2.6.*",
"symfony/event-dispatcher": "2.6.*",
"symfony/http-foundation": "2.6.*",
...
"autoload": {
"psr-4": {
"Drupal\\Core\\": "lib/Drupal/Core",
"Drupal\\Component\\": "lib/Drupal/Component",
"Drupal\\Driver\\": "../drivers/lib/Drupal/Driver"
},
...
}
if you have a composer.json
$ composer install
then after
composer.lock
The DependencyInjection component allows you to standardize and centralize the way objects are constructed in your application.
www.symfony.com
implementation of a powerful design pattern "Dependency Injection"
code follows "I" principle from SOLID
hmmm ... what does "I" stand for ?
decoupling dependencies
Example
You have an application in which the user can edit some configuration values.
And you want to save them "somewhere".
Example
class ConfigSaver
{
protected $storage;
public function __construct()
{
$this->storage = new FileStorage();
}
public function set($name, $value)
{
$this->storage->save($name, $value);
}
}
$configSaver = new ConfigSaver();
???
Example
class ConfigSaver
{
protected $storage;
public function __construct(StorageInterface $storage)
{
$this->storage = $storage;
}
public function set($name, $value)
{
$this->storage->save($name, $value);
}
}
$storage = new FileStorage(); // or DbStorage() or SessionStorage() or mock
$configSaver = new ConfigSaver($storage);
Basically, you are using Dependency Injection pattern when your object receives it's dependencies
constructor (contructor injection)
method (setter injection)
field (property injection)
controller : hey @container, could you give me the config saver service
container : oups ... I don't have it, let me build it
container : it has a storage dependency, let me check the configuration
container : it is a FileStorage, let me build that too
container : it's ready you can use the service now
controller : thanks
Dependency Injection Container
can inject services and parameters
based on configuration files that can be written in YML, XML, PHP
The service container can be "compiled" (dumped) to plain PHP
Modify already registered services
services:
cache_factory:
class: Drupal\Core\Cache\CacheFactory
arguments: ['@settings']
calls:
- [setContainer, ['@service_container']]
cache_contexts:
class: Drupal\Core\Cache\CacheContexts
arguments: ['@service_container', '%cache_contexts%' ]
...
exception.default:
class: Drupal\Core\EventSubscriber\DefaultExceptionSubscriber
tags:
- { name: event_subscriber }
arguments: ['@config.factory', '@bare_html_page_renderer']
core.services.yml
www.symfony.com
The HttpFoundation component defines an object-oriented layer for the HTTP specification.
Request
Server
Response
user
browser
simple OO representation of HTTP request message
holds information about the client request
wraps existing global PHP parameters in "bags"
$input = $_POST['input'];
$method = $_SERVER['REQUEST_METHOD'];
$cookie = $_COOKIE['cookie'];
use Symfony\Component\HttpFoundation\Request;
$request = Request::createFromGlobals();
$input = $request->get('input');
$method = $request->getMethod();
$cookie = $request->cookies->get('cookie');
$request->isSecure();
$request->getClientIp();
simple OO representation of HTTP response message
holds the information to be sent back
status, headers, content
header("HTTP/1.0 404 Not Found");
header("Cache-Control: max-age=600");
setcookie('cookie', 'value');
echo 'Lorem ipsum...';
use Symfony\Component\HttpFoundation\Response;
$response = new Response('Not Found!', 404);
$response->setMaxAge(600);
$response->setContent('Lorem ipsum...');
use Symfony\Component\HttpFoundation\Cookie;
$response->headers->setCookie(new Cookie('cookie', 'value'));
RequestStack
Session
UploadedFile
The EventDispatcher component provides tools that allow your application components to communicate with each other by dispatching events and listening to them.
www.symfony.com
mediator pattern
http://sourcemaking.com/files/v2/content/patterns/Mediator_example-2x.png
decoupled system
event based communication
listeners are independent
removing listener doesn't affect the system
Two types of consumers :
listeners
subscribers
// dispatching an event
$this->dispatcher->dispatch(BlockEvents::ADMINISTRATIVE_CONTEXT, new BlockContextEvent();
// setting up a subscriber implements EventSubscriberInterface
public static function getSubscribedEvents() {
$events[BlockEvents::ACTIVE_CONTEXT][] = 'onBlockActiveContext';
$events[BlockEvents::ADMINISTRATIVE_CONTEXT][] = 'onBlockAdministrativeContext';
return $events;
}
www.symfony.com
The Routing component maps a HTTP request to a set of configuration variables.
Kernel
Routing
kernel.request
Request
_controller
listens on kernel.request
matches route config
sets _controller on request
SymfonyCMF routing
+ enhancers
block.admin_demo:
path: '/admin/structure/block/demo/{theme}'
defaults:
_controller: '\Drupal\block\Controller\BlockController::demo'
_title_callback: 'theme_handler:getName'
requirements:
_access_theme: 'TRUE'
_permission: 'administer blocks'
options:
_admin_route: FALSE
The HttpKernel component provides a structured process for converting a Request into a Response by making use of the EventDispatcher.
www.symfony.com
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
$response = $kernel
->handle($request);
http://www.vanseodesign.com/blog/wp-content/uploads/2011/01/validate.jpg
Generic class validation component
add validation to any PHP object
configuration based
translatable error messages
$object = new Object();
$errors = $validator->validate($object);
Acme\OneBundle\Onjectr:
properties:
email:
- Email: ~
validation.yml
The Serializer component is meant to be used to turn objects into a specific format (XML, JSON, YAML, ...) and the other way around.
www.symfony.com
www.symfony.com
www.symfony.com
The Yaml component loads and dumps YAML files.
use Symfony\Component\Yaml\Parser;
$yaml = new Parser();
$value = $yaml->parse(file_get_contents('/path/to/file.yml'));
fast
easy to use
Configuration Management Initiative
$routes = new RouteCollection();
$routes->add('hello', new Route('/hello', array('_controller' =>
function (Request $request) {
return new Response(sprintf("Hello %s", $request->get('name')));
}
)));
$request = Request::createFromGlobals();
$matcher = new UrlMatcher($routes, new RequestContext());
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new RouterListener($matcher));
$resolver = new ControllerResolver();
$kernel = new HttpKernel($dispatcher, $resolver);
$kernel->handle($request)->send();
https://speakerdeck.com/fabpot/symfony2-meets-drupal-8
http://symfony.com/components
https://speakerdeck.com/fabpot/symfony2-meets-drupal-8
https://cipix.nl/understanding-drupal-8-part-1-general-structure-framework
http://www.sitepoint.com/drupal-8-hooks-symfony-event-dispatcher
http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1