Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Symfony2 your way
by Rafał Wrzeszcz, 2014
rafal.wrzeszcz@wrzasq.pl
http://wrzasq.pl/
http://chilldev.pl/
https://github.co...
Symfony2 – ways to customize
● Dependency Injection Container
● Code
● Bundles
● External tools
Dependency Injection
(yet without “Container”)
class DataSource {
protected $adapter;
protected $prefix;
public function _...
Putting dependencies into Container
class MyExtension extends Extension
{
public function load(
array $configs,
ContainerB...
Semantic configuration
my:
prefix: "prod."
sources:
- "srv1"
- "srv2"
class Configuration
implements ConfigurationInterfac...
Alles zusammen
my:
prefix: "prod."
sources:
- "srv1"
- "srv2"
$db = $di->get(
'my.datasource'
);
Services
definitions
Conf...
Overriding services and parameters
services:
form.resolved_type_factory:
class: "MyBundleApplicationBundleFormProfiledType...
Less invasive way - %*.class%
parameters:
form.resolved_type_factory.class: "MyBundleApplicationBundleFormProfiledTypeFact...
Adding .class parameter
<service id="my.dataadapter" class="DataAdapter">
<argument>%my.sources%</argument>
</service>
<se...
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 $cont...
Registering compiler pass
class MyBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::bui...
Adding tags to services
<parameter key="my.dataadapter.class">DataAdapter</parameter>
<parameter key="my.datasource.class"...
Own tags handler
class MyPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$c...
Most important pre-defined tags
● twig.extension/templating.helper – registering templating helpers,
● security.voter – cu...
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 even...
Custom event object
class MyLibFormEvent extends Event
{
const FORM_SUBMITTED = 'my_lib.form.event.submitted';
const FORM_...
Dispatching the event
$eventDispatcher = $di->get('event_dispatcher');
$eventDispatcher->dispatch(
MyLibFormEvent::FORM_SU...
Subscribing to events
$di->get('event_dispatcher')->addListener(
MyLibFormEvent::FORM_SUBMITTED,
function (MyLibFormEvent ...
Symfony kernel events
● kernel.requestnew request is being dispatched,
● kernel.responseresponse is generated by request h...
DI tag event_listener
<service id="my.lib.response_listener" class="%my.lib.response_listener.class%">
<tag name="kernel.e...
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.po...
Pointcut
class MySecurityPointcut implements PointcutInterface
{
public function matchesClass(ReflectionClass $class)
{
re...
Interceptor
class MySecurityInterceptor implements MethodInterceptorInterface
{
public function intercept(MethodInvocation...
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 fu...
Overriding routing
_admin_security:
# cascade checks:
# MySecurityBundle/Resources/config/routing/admin_security.xml
# Son...
Overriding templates
public function loginAction()
{
// action logic
return $this->templating->renderResponse(
'SonataUser...
Overriding versus extending
{# MySecurityBundle/Resources/views/Admin/Security/login.html.twig #}
{% extends '::layout.htm...
Application templates
● app/Resources/MySecurityBundle/views/Admin/Security/login.html.php
application resource,
● src/MyS...
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::bu...
Autoloading overriding
{
"autoload": {
"classmap": ["src/Symfony/"]
}
}
React
(react/http)
$app = function ($request, $response) {
$response->writeHead(200, ['Content-Type' => 'text/plain']);
$r...
PHP ProcessManager
(marcj/php-pm)
http://marcjschmidt.de/blog/2014/02/08/php-high-performance.html
./bin/ppm start ~/my/pa...
Varnish
templating:
esi: true
ESI example
<body>
<?php echo $this['actions']->render(
$this['actions']->controller('MySecurityBundle:Panel:sidebar'),
['...
QA tools – CLI
● php -l
● phpcs (squizlabs/php_codesniffer)
● phpcpd (sebastian/phpcpd)
● phpmd (phpmd/phpmd)
● phpunit (p...
QA tools – in the cloud
● CIfor open source – Travis (https://travis-ci.org/),
● Version Eyedependencies tracking
(https:/...
Scrutinizer
https://scrutinizer-ci.com/
SensioLabs Insights
https://insight.sensiolabs.com/
Thank you!
Upcoming SlideShare
Loading in …5
×

Symfony2 your way

2,177 views

Published on

I'm a computers enthusiast since when I got my first one in age of 3. I contribute to open source initiatives, work on commercial projects and play with new technologies in my spare, trying to get best experience from all of these forms.

With such variety of project types came different kinds of requirements, coding rules, architectures and company standards. Symfony2 has proven to be a very flexible framework that can be adapted to all of these needs. I will present to you ways in which you can make Symfony2 woring YOUR way.

Published in: Technology
  • Be the first to comment

Symfony2 your way

  1. 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. 2. Symfony2 – ways to customize ● Dependency Injection Container ● Code ● Bundles ● External tools
  3. 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. 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. 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. 6. Alles zusammen my: prefix: "prod." sources: - "srv1" - "srv2" $db = $di->get( 'my.datasource' ); Services definitions Configuration schema DI extension
  7. 7. Overriding services and parameters services: form.resolved_type_factory: class: "MyBundleApplicationBundleFormProfiledTypeFactory" arguments: - "@profiler" parameters: web_profiler.debug_toolbar.position: "top"
  8. 8. Less invasive way - %*.class% parameters: form.resolved_type_factory.class: "MyBundleApplicationBundleFormProfiledTypeFactory"
  9. 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. 10. DIC compiler Loading all extensions Merging them DIC compiler Dumping compiled DIC into cache
  11. 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. 12. Registering compiler pass class MyBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); $container->addCompilerPass( new MyCompilerPass(), PassConfig::TYPE_OPTIMIZE ); } }
  13. 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. 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. 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. 16. Symfony2 – ways to customize ● Dependency Injection Container ● Code ● Bundles ● External tools
  17. 17. Events ● move your non-core features to event handlers, ● keep core logic thin and simple, ● provide before and after events.
  18. 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. 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 */) );
  20. 20. Subscribing to events $di->get('event_dispatcher')->addListener( MyLibFormEvent::FORM_SUBMITTED, function (MyLibFormEvent $event) { // handle the event } );
  21. 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. 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>
  23. 23. JMSAopBundle "jms/aop-bundle": "1.0.1"
  24. 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. 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. 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. 27. Symfony2 – ways to customize ● Dependency Injection Container ● Code ● Bundles ● External tools
  28. 28. Bundles inheritance class MySecurityBundle extends Bundle { public function getParent() { return 'SonataUserBundle'; } }
  29. 29. Overriding controllers class AdminSecurityController extends SonataUserBundleControllerAdminSecurityController { public function loginAction() { // own login handling logic } }
  30. 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. 31. Overriding templates public function loginAction() { // action logic return $this->templating->renderResponse( 'SonataUserBundle:Admin:Security/login.html.php', $params ); }
  32. 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. 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. 34. Symfony2 – ways to customize ● Dependency Injection Container ● Code ● Bundles ● External tools
  35. 35. Composer https://getcomposer.org/ wget -O - https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin
  36. 36. Scripts incenteev/composer-parameter-handler: ScriptHandler::buildParameters sensio/distribution-bundle: ScriptHandler::buildBootstrap ScriptHandler::clearCache ScriptHandler::installAssets ScriptHandler::installRequirementsFile ScriptHandler::removeSymfonyStandardFiles
  37. 37. Autoloading overriding { "autoload": { "classmap": ["src/Symfony/"] } }
  38. 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();
  39. 39. 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
  40. 40. Varnish templating: esi: true
  41. 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. 42. QA tools – CLI ● php -l ● phpcs (squizlabs/php_codesniffer) ● phpcpd (sebastian/phpcpd) ● phpmd (phpmd/phpmd) ● phpunit (phpunit/phpunit) ● phpdoc (phpdocumentor/phpdocumentor)
  43. 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/).
  44. 44. Scrutinizer https://scrutinizer-ci.com/
  45. 45. SensioLabs Insights https://insight.sensiolabs.com/
  46. 46. Thank you!

×