SlideShare a Scribd company logo
1 of 46
Symfony2 your way
by Rafał Wrzeszcz, 2014
rafal.wrzeszcz@wrzasq.pl
http://wrzasq.pl/
http://chilldev.pl/
https://github.com/rafalwrzeszcz
https://linkedin.com/in/rafalwrzeszcz
Symfony2 – ways to customize
● Dependency Injection Container
● Code
● Bundles
● External tools
Dependency Injection
(yet without “Container”)
class DataSource {
protected $adapter;
protected $prefix;
public function __construct(
DataAdapter $adapter,
$prefix
) {
$this->adapter = $adapter;
$this->prefix = $prefix;
}
}
class DataAdapter {
protected $sources;
public function __construct(
array $sources
) {
$this->sources = $sources;
}
}
$conn = new DataAdapter(
['srv1', 'srv2']
);$db = new DataSource(
$conn,
'prod.'
);
Putting dependencies into Container
class MyExtension extends Extension
{
public function load(
array $configs,
ContainerBuilder $container
) {
$loader = new XmlFileLoader(
$container,
new FileLocator(__DIR__ .
'/../Resources/config')
);
$loader->load('services.xml');
}
}
<parameter key="my.prefix">prod.</parameter>
<parameter key="my.sources" type="collection">
<parameter>srv1</parameter>
<parameter>srv2</parameter>
</parameter>
<service id="my.dataadapter" class="DataAdapter">
<argument>%my.sources%</argument>
</service>
<service id="my.datasource" class="DataSource">
<argument type="service"
id="my.dataadapter"/>
<argument>%my.prefix%</argument>
</service>
$db = $di->get(
'my.datasource'
);
Semantic configuration
my:
prefix: "prod."
sources:
- "srv1"
- "srv2"
class Configuration
implements ConfigurationInterface
{
public function getConfigTreeBuilder() {
$treeBuilder = new TreeBuilder();
$treeBuilder->root('my')
->children()
->scalarNode('prefix')->end()
->arrayNode('sources')
->prototype('scalar')->end()
->end()
->end();
return $treeBuilder;
}
}
//MyExtension::load()
$config = $this->processConfiguration(
new Configuration(),
$configs);
$container->setParameter(
'my.prefix', $config['prefix']);
$container->setParameter(
'my.sources', $config['sources']);
Alles zusammen
my:
prefix: "prod."
sources:
- "srv1"
- "srv2"
$db = $di->get(
'my.datasource'
);
Services
definitions
Configuration
schema
DI
extension
Overriding services and parameters
services:
form.resolved_type_factory:
class: "MyBundleApplicationBundleFormProfiledTypeFactory"
arguments:
- "@profiler"
parameters:
web_profiler.debug_toolbar.position: "top"
Less invasive way - %*.class%
parameters:
form.resolved_type_factory.class: "MyBundleApplicationBundleFormProfiledTypeFactory"
Adding .class parameter
<service id="my.dataadapter" class="DataAdapter">
<argument>%my.sources%</argument>
</service>
<service id="my.datasource" class="DataSource">
<argument type="service"
id="my.dataadapter"/>
<argument>%my.prefix%</argument>
</service>
<parameter key="my.dataadapter.class">DataAdapter</parameter>
<parameter key="my.datasource.class">DataSource</parameter>
<service id="my.dataadapter" class="%my.dataadapter.class%">
<argument>%my.sources%</argument>
</service>
<service id="my.datasource" class="%my.datasource.class%">
<argument type="service" id="my.dataadapter"/>
<argument>%my.prefix%</argument>
</service>
DIC compiler
Loading all extensions
Merging them
DIC compiler
Dumping compiled DIC
into cache
Creating own compiler phase
class MyPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if ($container->hasDefinition('form.resolved_type_factory')) {
$definition = $container->getDefinition('form.resolved_type_factory');
$definition->setClass('MyBundleApplicationBundleFormProfiledTypeFactory');
$definition->addMethodCall(
'setProfiler',
[new Reference('profiler')]
);
}
}
}
Registering compiler pass
class MyBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(
new MyCompilerPass(),
PassConfig::TYPE_OPTIMIZE
);
}
}
Adding tags to services
<parameter key="my.dataadapter.class">DataAdapter</parameter>
<parameter key="my.datasource.class">DataSource</parameter>
<service id="my.dataadapter" class="%my.dataadapter.class%">
<argument>%my.sources%</argument>
<tag name="my.datasource" alias="data" prefix="%my.prefix_data%"/>
<tag name="my.datasource" alias="meta" prefix="%my.prefix_meta%"/>
</service>
Own tags handler
class MyPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$class = $container->getParameter('my.datasource.class');
foreach ($container->findTaggedServiceIds('my.datasource') as $id => $tags) {
foreach ($tags as $tag) {
$definition = $container->register($tag['alias'], $class);
$definition->setArguments([
new Reference($id),
$tag['prefix']
]);
}
}
}
}
Most important pre-defined tags
● twig.extension/templating.helper – registering templating helpers,
● security.voter – custom security access logic,
● monolog.logger – marking specific channels for the logger,
● kernel.event_listener/kernel.event_subscriber – subscribing to
events,
● data_collector – web profiler data collector.
More on http://symfony.com/doc/current/reference/dic_tags.html.
Symfony2 – ways to customize
● Dependency Injection Container
● Code
● Bundles
● External tools
Events
● move your non-core features to event handlers,
● keep core logic thin and simple,
● provide before and after events.
Custom event object
class MyLibFormEvent extends Event
{
const FORM_SUBMITTED = 'my_lib.form.event.submitted';
const FORM_HANDLED = 'my_lib.form.event.handled';
// properties
public function __construct(/* custom event params */)
{
// assign properties
}
// getters and setters
}
Dispatching the event
$eventDispatcher = $di->get('event_dispatcher');
$eventDispatcher->dispatch(
MyLibFormEvent::FORM_SUBMITTED,
new MyLibFormEvent(/* custom data */)
);
// process form
$eventDispatcher->dispatch(
MyLibFormEvent::FORM_HANDLED,
new MyLibFormEvent(/* custom data */)
);
Subscribing to events
$di->get('event_dispatcher')->addListener(
MyLibFormEvent::FORM_SUBMITTED,
function (MyLibFormEvent $event)
{
// handle the event
}
);
Symfony kernel events
● kernel.requestnew request is being dispatched,
● kernel.responseresponse is generated by request handler (like controller),
● kernel.finish_requestfired after request is handled – regardless of operation
status,
● kernel.terminateresponse is already sent – we can perform some heavy tasks that
won’t afect page load,
● kernel.exceptionunhandled exception occured during request handling.
DI tag event_listener
<service id="my.lib.response_listener" class="%my.lib.response_listener.class%">
<tag name="kernel.event_listener" event="kernel.response" method="onKernelResponse"/>
</service>
JMSAopBundle
"jms/aop-bundle": "1.0.1"
Writing own aspects
<service id="my.lib.security.pointcut" class="%my.lib.security.pointcut.class%">
<tag name="jms_aop.pointcut" interceptor="my.lib.security.interceptor"/>
</service>
<service id="my.lib.security.interceptor" class="%my.lib.security.interceptor.class%"/>
Pointcut
class MySecurityPointcut implements PointcutInterface
{
public function matchesClass(ReflectionClass $class)
{
return $class->implementsInterface('MyDataAdapterInterface');
}
public function matchesMethod(ReflectionMethod $method)
{
return $method->getName() == 'read';
}
}
Interceptor
class MySecurityInterceptor implements MethodInterceptorInterface
{
public function intercept(MethodInvocation $invocation)
{
if (/* security checks */) {
// you can modify $invocation->arguments array
$result = $invocation->proceed();
// you can post-process results
return $result;
} else {
throw new SecurityException('Unauthorized access attempt.');
}
}
}
Symfony2 – ways to customize
● Dependency Injection Container
● Code
● Bundles
● External tools
Bundles inheritance
class MySecurityBundle extends Bundle
{
public function getParent()
{
return 'SonataUserBundle';
}
}
Overriding controllers
class AdminSecurityController
extends SonataUserBundleControllerAdminSecurityController
{
public function loginAction()
{
// own login handling logic
}
}
Overriding routing
_admin_security:
# cascade checks:
# MySecurityBundle/Resources/config/routing/admin_security.xml
# SonataUserBundle/Resources/config/routing/admin_security.xml
resource: "@SonataUserBundle/Resources/config/routing/admin_security.xml"
prefix: "/admin"
Overriding templates
public function loginAction()
{
// action logic
return $this->templating->renderResponse(
'SonataUserBundle:Admin:Security/login.html.php',
$params
);
}
Overriding versus extending
{# MySecurityBundle/Resources/views/Admin/Security/login.html.twig #}
{% extends '::layout.html.twig' %}
{% block sidebar %}
<h3>Table of Contents</h3>
{# ... #}
{{ parent() }}
{% endblock %}
Application templates
● app/Resources/MySecurityBundle/views/Admin/Security/login.html.php
application resource,
● src/MySecurityBundle/Resources/views/Admin/Security/login.html.php
inheriting bundle,
● src/SonataUserBundle/Resources/views/Admin/Security/login.html.php
source template.
Symfony2 – ways to customize
● Dependency Injection Container
● Code
● Bundles
● External tools
Composer
https://getcomposer.org/
wget -O - https://getcomposer.org/installer
| php -- --install-dir=/usr/local/bin
Scripts
incenteev/composer-parameter-handler:
ScriptHandler::buildParameters
sensio/distribution-bundle:
ScriptHandler::buildBootstrap
ScriptHandler::clearCache
ScriptHandler::installAssets
ScriptHandler::installRequirementsFile
ScriptHandler::removeSymfonyStandardFiles
Autoloading overriding
{
"autoload": {
"classmap": ["src/Symfony/"]
}
}
React
(react/http)
$app = function ($request, $response) {
$response->writeHead(200, ['Content-Type' => 'text/plain']);
$response->end("Hello Worldn");
};
$loop = ReactEventLoopFactory::create();
$socket = new ReactSocketServer($loop);
$http = new ReactHttpServer($socket, $loop);
$http->on('request', $app);
$socket->listen(1337);
$loop->run();
PHP ProcessManager
(marcj/php-pm)
http://marcjschmidt.de/blog/2014/02/08/php-high-performance.html
./bin/ppm start ~/my/path/to/symfony/ --bridge=httpkernel
Varnish
templating:
esi: true
ESI example
<body>
<?php echo $this['actions']->render(
$this['actions']->controller('MySecurityBundle:Panel:sidebar'),
['strategy' => 'esi']
); ?>
<h1>My blog</h1>
<?php /* page content */ ?>
</body>
QA tools – CLI
● php -l
● phpcs (squizlabs/php_codesniffer)
● phpcpd (sebastian/phpcpd)
● phpmd (phpmd/phpmd)
● phpunit (phpunit/phpunit)
● phpdoc (phpdocumentor/phpdocumentor)
QA tools – in the cloud
● CIfor open source – Travis (https://travis-ci.org/),
● Version Eyedependencies tracking
(https://www.versioneye.com/),
● Coverallscode coverage tracking (https://coveralls.io/).
Scrutinizer
https://scrutinizer-ci.com/
SensioLabs Insights
https://insight.sensiolabs.com/
Thank you!

More Related Content

What's hot

How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonKris Wallsmith
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
droidQuery: The Android port of jQuery
droidQuery: The Android port of jQuerydroidQuery: The Android port of jQuery
droidQuery: The Android port of jQueryPhDBrown
 
Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Vladyslav Riabchenko
 
Javascript and jQuery intro
Javascript and jQuery introJavascript and jQuery intro
Javascript and jQuery introwaw325
 
Love and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayLove and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayKris Wallsmith
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Writing Sensible Code
Writing Sensible CodeWriting Sensible Code
Writing Sensible CodeAnis Ahmad
 
Drupal Field API. Practical usage
Drupal Field API. Practical usageDrupal Field API. Practical usage
Drupal Field API. Practical usagePavel Makhrinsky
 
06 jQuery #burningkeyboards
06 jQuery  #burningkeyboards06 jQuery  #burningkeyboards
06 jQuery #burningkeyboardsDenis Ristic
 
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014Matthias Noback
 
05 JavaScript #burningkeyboards
05 JavaScript #burningkeyboards05 JavaScript #burningkeyboards
05 JavaScript #burningkeyboardsDenis Ristic
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkG Woo
 
A resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangleA resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangleAkihito Koriyama
 

What's hot (20)

How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Your Entity, Your Code
Your Entity, Your CodeYour Entity, Your Code
Your Entity, Your Code
 
Bacbkone js
Bacbkone jsBacbkone js
Bacbkone js
 
droidQuery: The Android port of jQuery
droidQuery: The Android port of jQuerydroidQuery: The Android port of jQuery
droidQuery: The Android port of jQuery
 
Matters of State
Matters of StateMatters of State
Matters of State
 
Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3
 
Javascript and jQuery intro
Javascript and jQuery introJavascript and jQuery intro
Javascript and jQuery intro
 
Love and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayLove and Loss: A Symfony Security Play
Love and Loss: A Symfony Security Play
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Zend framework service
Zend framework serviceZend framework service
Zend framework service
 
Writing Sensible Code
Writing Sensible CodeWriting Sensible Code
Writing Sensible Code
 
Drupal Field API. Practical usage
Drupal Field API. Practical usageDrupal Field API. Practical usage
Drupal Field API. Practical usage
 
Drupal 8: Fields reborn
Drupal 8: Fields rebornDrupal 8: Fields reborn
Drupal 8: Fields reborn
 
06 jQuery #burningkeyboards
06 jQuery  #burningkeyboards06 jQuery  #burningkeyboards
06 jQuery #burningkeyboards
 
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
 
05 JavaScript #burningkeyboards
05 JavaScript #burningkeyboards05 JavaScript #burningkeyboards
05 JavaScript #burningkeyboards
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
A resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangleA resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangle
 
Special Events
Special EventsSpecial Events
Special Events
 

Similar to Symfony2 Customization Ways

ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperGary Hockin
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsMichael Peacock
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf Conference
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Jakub Zalas
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hackingJeroen van Dijk
 
Gérer vos objets
Gérer vos objetsGérer vos objets
Gérer vos objetsThomas Gasc
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the TrenchesJonathan Wage
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICKonstantin Kudryashov
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014Matthias Noback
 
Drupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionDrupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionPhilip Norton
 
Symfony War Stories
Symfony War StoriesSymfony War Stories
Symfony War StoriesJakub Zalas
 
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for PerformanceMeet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for PerformanceIvan Chepurnyi
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016Kacper Gunia
 
Migrating to dependency injection
Migrating to dependency injectionMigrating to dependency injection
Migrating to dependency injectionJosh Adell
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenchesLukas Smith
 

Similar to Symfony2 Customization Ways (20)

ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 Developer
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
Gérer vos objets
Gérer vos objetsGérer vos objets
Gérer vos objets
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
The IoC Hydra
The IoC HydraThe IoC Hydra
The IoC Hydra
 
A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014
 
Drupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionDrupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency Injection
 
Symfony War Stories
Symfony War StoriesSymfony War Stories
Symfony War Stories
 
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for PerformanceMeet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
 
Migrating to dependency injection
Migrating to dependency injectionMigrating to dependency injection
Migrating to dependency injection
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 

Recently uploaded

The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 

Recently uploaded (20)

The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 

Symfony2 Customization Ways

  • 1. Symfony2 your way by Rafał Wrzeszcz, 2014 rafal.wrzeszcz@wrzasq.pl http://wrzasq.pl/ http://chilldev.pl/ https://github.com/rafalwrzeszcz https://linkedin.com/in/rafalwrzeszcz
  • 2. Symfony2 – ways to customize ● Dependency Injection Container ● Code ● Bundles ● External tools
  • 3. Dependency Injection (yet without “Container”) class DataSource { protected $adapter; protected $prefix; public function __construct( DataAdapter $adapter, $prefix ) { $this->adapter = $adapter; $this->prefix = $prefix; } } class DataAdapter { protected $sources; public function __construct( array $sources ) { $this->sources = $sources; } } $conn = new DataAdapter( ['srv1', 'srv2'] );$db = new DataSource( $conn, 'prod.' );
  • 4. Putting dependencies into Container class MyExtension extends Extension { public function load( array $configs, ContainerBuilder $container ) { $loader = new XmlFileLoader( $container, new FileLocator(__DIR__ . '/../Resources/config') ); $loader->load('services.xml'); } } <parameter key="my.prefix">prod.</parameter> <parameter key="my.sources" type="collection"> <parameter>srv1</parameter> <parameter>srv2</parameter> </parameter> <service id="my.dataadapter" class="DataAdapter"> <argument>%my.sources%</argument> </service> <service id="my.datasource" class="DataSource"> <argument type="service" id="my.dataadapter"/> <argument>%my.prefix%</argument> </service> $db = $di->get( 'my.datasource' );
  • 5. Semantic configuration my: prefix: "prod." sources: - "srv1" - "srv2" class Configuration implements ConfigurationInterface { public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder(); $treeBuilder->root('my') ->children() ->scalarNode('prefix')->end() ->arrayNode('sources') ->prototype('scalar')->end() ->end() ->end(); return $treeBuilder; } } //MyExtension::load() $config = $this->processConfiguration( new Configuration(), $configs); $container->setParameter( 'my.prefix', $config['prefix']); $container->setParameter( 'my.sources', $config['sources']);
  • 6. Alles zusammen my: prefix: "prod." sources: - "srv1" - "srv2" $db = $di->get( 'my.datasource' ); Services definitions Configuration schema DI extension
  • 7. Overriding services and parameters services: form.resolved_type_factory: class: "MyBundleApplicationBundleFormProfiledTypeFactory" arguments: - "@profiler" parameters: web_profiler.debug_toolbar.position: "top"
  • 8. Less invasive way - %*.class% parameters: form.resolved_type_factory.class: "MyBundleApplicationBundleFormProfiledTypeFactory"
  • 9. Adding .class parameter <service id="my.dataadapter" class="DataAdapter"> <argument>%my.sources%</argument> </service> <service id="my.datasource" class="DataSource"> <argument type="service" id="my.dataadapter"/> <argument>%my.prefix%</argument> </service> <parameter key="my.dataadapter.class">DataAdapter</parameter> <parameter key="my.datasource.class">DataSource</parameter> <service id="my.dataadapter" class="%my.dataadapter.class%"> <argument>%my.sources%</argument> </service> <service id="my.datasource" class="%my.datasource.class%"> <argument type="service" id="my.dataadapter"/> <argument>%my.prefix%</argument> </service>
  • 10. DIC compiler Loading all extensions Merging them DIC compiler Dumping compiled DIC into cache
  • 11. Creating own compiler phase class MyPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { if ($container->hasDefinition('form.resolved_type_factory')) { $definition = $container->getDefinition('form.resolved_type_factory'); $definition->setClass('MyBundleApplicationBundleFormProfiledTypeFactory'); $definition->addMethodCall( 'setProfiler', [new Reference('profiler')] ); } } }
  • 12. Registering compiler pass class MyBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); $container->addCompilerPass( new MyCompilerPass(), PassConfig::TYPE_OPTIMIZE ); } }
  • 13. Adding tags to services <parameter key="my.dataadapter.class">DataAdapter</parameter> <parameter key="my.datasource.class">DataSource</parameter> <service id="my.dataadapter" class="%my.dataadapter.class%"> <argument>%my.sources%</argument> <tag name="my.datasource" alias="data" prefix="%my.prefix_data%"/> <tag name="my.datasource" alias="meta" prefix="%my.prefix_meta%"/> </service>
  • 14. Own tags handler class MyPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { $class = $container->getParameter('my.datasource.class'); foreach ($container->findTaggedServiceIds('my.datasource') as $id => $tags) { foreach ($tags as $tag) { $definition = $container->register($tag['alias'], $class); $definition->setArguments([ new Reference($id), $tag['prefix'] ]); } } } }
  • 15. Most important pre-defined tags ● twig.extension/templating.helper – registering templating helpers, ● security.voter – custom security access logic, ● monolog.logger – marking specific channels for the logger, ● kernel.event_listener/kernel.event_subscriber – subscribing to events, ● data_collector – web profiler data collector. More on http://symfony.com/doc/current/reference/dic_tags.html.
  • 16. Symfony2 – ways to customize ● Dependency Injection Container ● Code ● Bundles ● External tools
  • 17. Events ● move your non-core features to event handlers, ● keep core logic thin and simple, ● provide before and after events.
  • 18. Custom event object class MyLibFormEvent extends Event { const FORM_SUBMITTED = 'my_lib.form.event.submitted'; const FORM_HANDLED = 'my_lib.form.event.handled'; // properties public function __construct(/* custom event params */) { // assign properties } // getters and setters }
  • 19. Dispatching the event $eventDispatcher = $di->get('event_dispatcher'); $eventDispatcher->dispatch( MyLibFormEvent::FORM_SUBMITTED, new MyLibFormEvent(/* custom data */) ); // process form $eventDispatcher->dispatch( MyLibFormEvent::FORM_HANDLED, new MyLibFormEvent(/* custom data */) );
  • 21. Symfony kernel events ● kernel.requestnew request is being dispatched, ● kernel.responseresponse is generated by request handler (like controller), ● kernel.finish_requestfired after request is handled – regardless of operation status, ● kernel.terminateresponse is already sent – we can perform some heavy tasks that won’t afect page load, ● kernel.exceptionunhandled exception occured during request handling.
  • 22. DI tag event_listener <service id="my.lib.response_listener" class="%my.lib.response_listener.class%"> <tag name="kernel.event_listener" event="kernel.response" method="onKernelResponse"/> </service>
  • 24. Writing own aspects <service id="my.lib.security.pointcut" class="%my.lib.security.pointcut.class%"> <tag name="jms_aop.pointcut" interceptor="my.lib.security.interceptor"/> </service> <service id="my.lib.security.interceptor" class="%my.lib.security.interceptor.class%"/>
  • 25. Pointcut class MySecurityPointcut implements PointcutInterface { public function matchesClass(ReflectionClass $class) { return $class->implementsInterface('MyDataAdapterInterface'); } public function matchesMethod(ReflectionMethod $method) { return $method->getName() == 'read'; } }
  • 26. Interceptor class MySecurityInterceptor implements MethodInterceptorInterface { public function intercept(MethodInvocation $invocation) { if (/* security checks */) { // you can modify $invocation->arguments array $result = $invocation->proceed(); // you can post-process results return $result; } else { throw new SecurityException('Unauthorized access attempt.'); } } }
  • 27. Symfony2 – ways to customize ● Dependency Injection Container ● Code ● Bundles ● External tools
  • 28. Bundles inheritance class MySecurityBundle extends Bundle { public function getParent() { return 'SonataUserBundle'; } }
  • 29. Overriding controllers class AdminSecurityController extends SonataUserBundleControllerAdminSecurityController { public function loginAction() { // own login handling logic } }
  • 30. Overriding routing _admin_security: # cascade checks: # MySecurityBundle/Resources/config/routing/admin_security.xml # SonataUserBundle/Resources/config/routing/admin_security.xml resource: "@SonataUserBundle/Resources/config/routing/admin_security.xml" prefix: "/admin"
  • 31. Overriding templates public function loginAction() { // action logic return $this->templating->renderResponse( 'SonataUserBundle:Admin:Security/login.html.php', $params ); }
  • 32. Overriding versus extending {# MySecurityBundle/Resources/views/Admin/Security/login.html.twig #} {% extends '::layout.html.twig' %} {% block sidebar %} <h3>Table of Contents</h3> {# ... #} {{ parent() }} {% endblock %}
  • 33. Application templates ● app/Resources/MySecurityBundle/views/Admin/Security/login.html.php application resource, ● src/MySecurityBundle/Resources/views/Admin/Security/login.html.php inheriting bundle, ● src/SonataUserBundle/Resources/views/Admin/Security/login.html.php source template.
  • 34. Symfony2 – ways to customize ● Dependency Injection Container ● Code ● Bundles ● External tools
  • 35. Composer https://getcomposer.org/ wget -O - https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin
  • 38. React (react/http) $app = function ($request, $response) { $response->writeHead(200, ['Content-Type' => 'text/plain']); $response->end("Hello Worldn"); }; $loop = ReactEventLoopFactory::create(); $socket = new ReactSocketServer($loop); $http = new ReactHttpServer($socket, $loop); $http->on('request', $app); $socket->listen(1337); $loop->run();
  • 41. ESI example <body> <?php echo $this['actions']->render( $this['actions']->controller('MySecurityBundle:Panel:sidebar'), ['strategy' => 'esi'] ); ?> <h1>My blog</h1> <?php /* page content */ ?> </body>
  • 42. QA tools – CLI ● php -l ● phpcs (squizlabs/php_codesniffer) ● phpcpd (sebastian/phpcpd) ● phpmd (phpmd/phpmd) ● phpunit (phpunit/phpunit) ● phpdoc (phpdocumentor/phpdocumentor)
  • 43. QA tools – in the cloud ● CIfor open source – Travis (https://travis-ci.org/), ● Version Eyedependencies tracking (https://www.versioneye.com/), ● Coverallscode coverage tracking (https://coveralls.io/).

Editor's Notes

  1. Ale przedefiniowywanie usług trąci nieco hackowaniem - możemy w ten sposób naruszyć pewien kontrakt. Może się okazać, że z czasem usługa, którą nadpisujemyu zacznie przyjmować dodatkowe parametry. Istnieje bardziej subtelny sposób, który sprowadza się mniej więcej do tego samego - podmienienia klasy, z której będzie instancjowana usługa - lecz przy pomocy samych parametrów, tak, aby nie ryzykować ingerencji w jakiekolwiek interakcje z usługą (takie jak wywołania metod). Ten sposob to parametr z sufiksem ".class". Jest to konwencja, dzięki której właśnie mamy możliwość zawsze podmiany implementacji usługi na naszą (oczywiście musi ona być kompatybilna).
  2. Jak to działa? Po prostu definiując nasze usługi tworzymy jeden dodatkowy parametr dla każdej z nich z sufiksem ".class" (także dobrze jest o tym pamiętać rónież nazywając parametry - tak, aby unikać nazw parametrów z tym sufiksem). Parametr ten przechowuje nazwę klasy wykorzystywanej przez usługę i umożliwia jej łatwą zmianę (wystarczy nadpisać jego wartość, nie trzeba nadpisywać całej usługi). W taki sposób (z użyciem parametru klasy) zdefiniowane są wszystkie usługi samego Symfony2, a także większości popularnych (i tych mniej popularnych też) bundli. Generalnie praktycznie nic nas nie kosztuje dodanie takiego parametru do naszych usług, a potrafi to nieraz uratować tyłek, szczególnie, jeśli tworzymy jakiś bundle ogólnego przeznaczenia, z którego mieliby korzystać inni.
  3. Kolejną rzeczą, którą możemy modyfikować względem bazowego bundle’a jest routing. Przy czym aby nasze przesłanianie było możliwe trzeba skorzystać ze specjalnej notacji, która oznacza odniesienie do zasobów względem danego bundle’a. W ten sposób możemy przesłonić dany statyczny plik tworząc plik o takiej samej nazwie i ścieżce.
  4. Bardzo podobnie ma się sprawa z przesłanianiem szablonów. Właściwie dosłownie tak samo – aby przesłonić szablon widoku tworzymy plik o takiej samej nazwie i takiej samej ścieżce w naszym bundlu.
  5. Ale, w przypadku szablonów należy pamiętać o jednej istotnej rzeczy, a mianowicie różnice pomiędzy przesłanianiem szablonów, a ich rozszerzaniem. Jest to o tyle problematyczne, że angielskojęzyczne nazwy konstrukcji odpowiedzialnych za te poszczególne cechy systemu szablonów są zbieżne z nomenklaturą w programowaniu obiektowym, ale ich działanie jest odmienne, żeby nawet nie powiedzieć odwrotne. Przesłaniając szablon całkowicie przesłaniamy go w systemie, nie ma żadnej możliwości dostępu do niego, nasz szablon musi go w całości zastąpić Korzystając z mechanizmu rozszerzania definiujemy logiczny ciąg zagnieżdżania szablonów – w tym przypadku nasz widok zostanie osadzony w innym, konkretnie w głównym layoucie aplikacji. Użycie `parent()` w kodzie odnosi się właśnie do tego zagnieżdżenia, nie do przsłoniętego widoku z bundle’a.
  6. W przypadku szablonów mamy też możliwość przesłaniania szablonów w jeszcze jeden sposób – przez zasoby samej aplikacji. Zasoby aplikacji mają najwyższy priorytet, lecz warto zwrócić uwagę na inną budowę ścieżki.
  7. I w końcu ostatnia część, a mianowicie zewnętrzne usługi i narzędzia. Nie samym Symfony człowiek żyje. Na szczęście społeczność Symfony dobrze o tym wie, framework ten jest bardzo otwarty i “przyjazny” w kwestii integracji z zewnętrznymi usługami, API, czy narzędziami. W bardzo wielu frameworkach istnieje podejście tworzenia wszystkiego samemu, podczas gdy w Symfony podejście jest zazwyczaj odwrotne – jeśli istnieje już do czegoś rowzwiązanie to w Symfony2 często znajdziemy integrację z takim rozwiązaniem.
  8. Tworząc projekt w Symfony praktycznie nie obejdziemy się bez Composera (nie jestem jego wielbicielem, ale jest to obecnie praktycznie de facto standard, więc nie ma co wynajdywać koła na nowo).
  9. Jedną z większych, moim zdaniem, ułomności w Composerze jest sposób podpinania się z własną implementacją pod cokolwiek, no ale nie będę się rozwodził o moich wewnętrznych odczuciach… W Composerze możemy podpiąć się pod zdarzenia (ich listę można znaleźć w specyfikacji na stronie). Sensio (twórcy Symfony) udostępniają kilka gotowych skryptów, które pozwalają zautomatyzować cykl pracy z aplikacją.
  10. Ale Composer daje nam pewną bardzo potężną broń. Chyba najbrzydszy z jakichkolwiek dziś przeze mnie tutaj prezentowanych hacków. Jeśli myśleliście, że przedefiniowywanie definicji usług w DIC było złe, to spójrzcie na to.<klik> Otóż możemy całkiem przesłonić klasy dowolnej ładowanej przez nas biblioteki naszymi własnymi jeśli tylko nadpiszemy autoloader generowany przez Composera. Ale jest jeden warunek – musimy skorzystać z autoloadera typu classmap (niezależnie od tego, że Composer i tak generuje dla nas class-mapę, chodzi o hierarchię loaderów, class-mapa jako najszybsza i generowana docelowo, jest pierwszym miejscem, gdzie wygenerowany autoloader szuka klasy).
  11. Kolejnym ciekawym i niezmiernie obiecującym projektem jest React. Implementuje on model przetwarzania request-response znany z wielu innych platform, takich jak chociażby Node.js. Co to ma wspólnego z Symfony? Oczywiście możemy, jako funkcję obsługującą żądanie zaimplementować bootstrapping naszej aplikacji Symfony, ale jest jeszcz lepiej – coś takiego już istnieje.
  12. Kożyści są bardzo duże, przede wszystkim odchodzi konieczność każdorazowego bootstrapowania aplikacji, która nawet przy bardzo zoptymalizowanych projektach wymaga zazwyczaj dużo operacji wejścia/wyjścia (chociażby wczytywanie plików), co jest nieraz największym obciążeniem. Możemy również wykorzystać nową architekturę i wyeliminować niektóre inne zależności, na przykład niektórych rzeczy nie trzeba trzymać w cache’u, czy sesji, gdyż można je trzymać bezpośrednio w pamięci procesu. Nie ma niestety róży bez kolców. Jest to kompletna zmiana podejścia w przypadku PHP, pamiętajmy, że w normalnym trybie skrypty PHP są zawsze uruchamiane w odrębnym środowisku. W tym przypadku musimy pamiętać, że nasz skrypt działa nieprzerwanie, każde kolejne zapytanie operuje w tym samym środowisku, a więc musimy być świadomi, że na przykład ta sama instancja naszego obiektu będzie wykorzystana podobnie, więc inicjując obiekty musimy być pewni kiedy się ona wykonuje.