$30 off During Our Annual Pro Sale. View Details »

Symfony – In Plain English

Symfony – In Plain English

For every newcomer, Symfony appears to be an invincible beast at first glance. But taking a look from the distance reveals some patterns that are quite easy to grasp. We'll take a look at Symfony's concepts and philosophy, its components, the full-stack framework and the ecosystem. In a nutshell, this talk teaches you on a beginner's level what all the Symfony fuss is about and why it became *the* top-notch PHP project it is nowadays.

http://dcmuc16.drupalcamp.de/sessions/symfony-plain-english

Philipp Rieber

December 03, 2016
Tweet

More Decks by Philipp Rieber

Other Decks in Programming

Transcript

  1. @bicpi
    Symfony – In Plain English Philipp Rieber
    #DCMuc16

    View Slide

  2. #DCMuc16

    View Slide

  3. #DCMuc16

    View Slide

  4. @bicpi
    PHP・Symfony・DevOps・Technical Writer
    https://philipp-rieber.net
    #DCMuc16

    View Slide

  5. @bicpi
    PHP・Symfony・DevOps・Technical Writer
    https://philipp-rieber.net
    #DCMuc16

    View Slide

  6. ottonova.de
    We are creating a better private health insurance company for you.
    #DCMuc16

    View Slide

  7. @sfugmuc
    Symfony User Group Munich
    #DCMuc16

    View Slide

  8. First, Symfony2 is a reusable set of standalone, decoupled, and
    cohesive PHP components that solve common web development
    problems.
    – Fabien Potencier

    http://fabien.potencier.org/what-is-symfony2.html
    What is Symfony?
    #DCMuc16

    View Slide

  9. BrowserKit
    ClassLoader
    Config
    Asset
    Console
    CssSelector
    Debug
    DependencyInjection
    DomCrawler
    EventDispatcher
    ExpressionLanguage
    Filesystem
    Finder
    Form
    Guard
    HttpFoundation
    HttpKernel
    Icu
    Intl
    Ldap
    Locale
    OptionsResolver
    Process
    PropertyAccess
    PropertyInfo
    Routing
    Security
    Serializer
    Stopwatch
    Templating
    Translation
    Validator
    VarDumper
    Yaml
    Guard
    Workflow
    #DCMuc16

    View Slide

  10. BrowserKit
    ClassLoader
    Config
    Asset
    Console
    CssSelector
    Debug
    DependencyInjection
    DomCrawler
    EventDispatcher
    ExpressionLanguage
    Filesystem
    Finder
    Form
    Guard
    HttpFoundation
    HttpKernel
    Icu
    Intl
    Ldap
    Locale
    OptionsResolver
    Process
    PropertyAccess
    PropertyInfo
    Routing
    Security
    Serializer
    Stopwatch
    Templating
    Translation
    Validator
    VarDumper
    Yaml
    Guard
    Workflow
    #DCMuc16

    View Slide

  11. $ composer require symfony/yaml
    Yaml Component #DCMuc16

    View Slide

  12. $ composer require symfony/yaml
    require 'vendor/autoload.php';
    Yaml Component #DCMuc16

    View Slide

  13. $ composer require symfony/yaml
    require 'vendor/autoload.php';
    use Symfony\Component\Yaml\Yaml;
    Yaml Component #DCMuc16

    View Slide

  14. $ composer require symfony/yaml
    require 'vendor/autoload.php';
    use Symfony\Component\Yaml\Yaml;
    $yaml = <<parameters:
    user: symfony
    pass: awesome
    YAML;
    Yaml Component #DCMuc16

    View Slide

  15. $ composer require symfony/yaml
    require 'vendor/autoload.php';
    use Symfony\Component\Yaml\Yaml;
    $yaml = <<parameters:
    user: symfony
    pass: awesome
    YAML;
    $config = Yaml::parse($yaml);
    Yaml Component #DCMuc16

    View Slide

  16. $ composer require symfony/yaml
    require 'vendor/autoload.php';
    use Symfony\Component\Yaml\Yaml;
    $yaml = <<parameters:
    user: symfony
    pass: awesome
    YAML;
    $config = Yaml::parse($yaml);
    // ['parameters' => ['user' => 'symfony', 'pass' => 'awesome']]
    Yaml Component #DCMuc16

    View Slide

  17. BrowserKit
    ClassLoader
    Config
    Asset
    Console
    CssSelector
    Debug
    DependencyInjection
    DomCrawler
    EventDispatcher
    ExpressionLanguage
    Filesystem
    Finder
    Form
    Guard
    HttpFoundation
    HttpKernel
    Icu
    Intl
    Ldap
    Locale
    OptionsResolver
    Process
    PropertyAccess
    PropertyInfo
    Routing
    Security
    Serializer
    Stopwatch
    Templating
    Translation
    Validator
    VarDumper
    Yaml
    Guard
    Workflow
    #DCMuc16

    View Slide

  18. $ composer require symfony/finder
    Finder Component #DCMuc16

    View Slide

  19. $ composer require symfony/finder
    Finder Component
    require 'vendor/autoload.php';
    use Symfony\Component\Finder\Finder;
    #DCMuc16

    View Slide

  20. $ composer require symfony/finder
    Finder Component
    require 'vendor/autoload.php';
    use Symfony\Component\Finder\Finder;
    $finder = Finder::create();
    #DCMuc16

    View Slide

  21. $ composer require symfony/finder
    Finder Component
    require 'vendor/autoload.php';
    use Symfony\Component\Finder\Finder;
    $finder = Finder::create()
    ->in('/Users/bicpi/photos');

    #DCMuc16

    View Slide

  22. $ composer require symfony/finder
    Finder Component
    require 'vendor/autoload.php';
    use Symfony\Component\Finder\Finder;
    $finder = Finder::create()
    ->in('/Users/bicpi/photos')
    ->files();

    #DCMuc16

    View Slide

  23. $ composer require symfony/finder
    Finder Component
    require 'vendor/autoload.php';
    use Symfony\Component\Finder\Finder;
    $finder = Finder::create()
    ->in('/Users/bicpi/photos')
    ->files()
    ->name('*.jpg');

    #DCMuc16

    View Slide

  24. $ composer require symfony/finder
    Finder Component
    require 'vendor/autoload.php';
    use Symfony\Component\Finder\Finder;
    $finder = Finder::create()
    ->in('/Users/bicpi/photos')
    ->files()
    ->name('*.jpg')
    ->size('>= 1M');
    #DCMuc16

    View Slide

  25. $ composer require symfony/finder
    Finder Component
    require 'vendor/autoload.php';
    use Symfony\Component\Finder\Finder;
    $finder = Finder::create()
    ->in('/Users/bicpi/photos')
    ->files()
    ->name('*.jpg')
    ->size('>= 1M');
    foreach ($finder as $file) {
    echo $file->getFilename() . "\n";
    }
    #DCMuc16

    View Slide

  26. Do one thing. 

    Make it excellent. 

    Stay out of the way.
    – Unix Philosophy

    #DCMuc16

    View Slide

  27. • …
    • Console Command Line Interface
    • Filesystem Basic utilities for the filesystem
    • Translation Tools for internationalisation
    • …
    #DCMuc16

    View Slide

  28. Then, based on these components, Symfony2 is also a full-stack web
    framework.
    – Fabien Potencier

    http://fabien.potencier.org/what-is-symfony2.html
    What ELSE is Symfony?
    #DCMuc16

    View Slide

  29. BrowserKit ClassLoader
    Config
    Asset
    Console
    CssSelector
    Debug
    DependencyInjection
    DomCrawler
    EventDispatcher
    ExpressionLanguage
    Filesystem
    Finder
    Form
    Guard
    HttpFoundation
    HttpKernel
    Icu
    Intl
    Ldap
    Locale
    OptionsResolver
    Process
    PropertyAccess
    PropertyInfo
    Routing
    Security
    Serializer
    Stopwatch
    Templating
    Translation
    Validator
    VarDumper
    Yaml
    Guard
    Workflow
    Your Application
    #DCMuc16

    View Slide


  30. #DCMuc16

    View Slide

  31. Request

    1
    #DCMuc16

    View Slide

  32. Request

    Response
    2
    1
    #DCMuc16
    ?

    View Slide

  33. Request

    Response
    2
    3
    #DCMuc16
    1
    ?

    View Slide

  34. Request

    Symfony full-stack
    Response
    #DCMuc16
    1
    2
    3

    View Slide

  35. It is all about transforming a
    Request into a Response
    #DCMuc16

    View Slide

  36. HttpFoundation\Request

    HTTP Header, $_GET, $_POST, $_COOKIE, $_SESSION, $_SERVER

    #DCMuc16

    View Slide

  37. HttpFoundation\Request

    HTTP Header, $_GET, $_POST, $_COOKIE, $_SESSION, $_SERVER

    HttpKernel

    Web framework core, “Glues” the components,

    Loads configuration and “Bundles”, Controls flow, Event Driven
    #DCMuc16

    View Slide

  38. HttpFoundation\Request

    HTTP Header, $_GET, $_POST, $_COOKIE, $_SESSION, $_SERVER

    HttpFoundation\Response

    HTTP Status Code, HTTP Header, Content (HTML, JSON …)
    HttpKernel

    Web framework core, “Glues” the components,

    Loads configuration and “Bundles”, Controls flow, Event Driven
    #DCMuc16

    View Slide

  39. HTTP specification
    #DCMuc16

    View Slide

  40. #DCMuc16
    Code please.

    View Slide

  41. Request

    /blog/article?id=34
    #DCMuc16

    View Slide

  42. Request

    /blog/article?id=34
    class BlogController extends Controller
    {







    }
    #DCMuc16

    View Slide

  43. Request

    /blog/article?id=34
    class BlogController extends Controller
    {
    /**
    * @Route("/blog/article")
    */
    public function articleAction(Request $request)
    {







    }
    }
    #DCMuc16

    View Slide

  44. Request

    /blog/article?id=34
    class BlogController extends Controller
    {
    /**
    * @Route("/blog/article")
    */
    public function articleAction(Request $request)
    {







    }
    }
    #DCMuc16

    View Slide

  45. Request

    /blog/article?id=34
    class BlogController extends Controller
    {
    /**
    * @Route("/blog/article")
    */
    public function articleAction(Request $request)
    {
    $id = $request->query->get('id');






    }
    }
    #DCMuc16

    View Slide

  46. Request

    /blog/article?id=34
    class BlogController extends Controller
    {
    /**
    * @Route("/blog/article")
    */
    public function articleAction(Request $request)
    {
    $id = $request->query->get('id');
    $article = $database->findArticle($id);





    }
    }
    #DCMuc16

    View Slide

  47. Request

    /blog/article?id=34
    class BlogController extends Controller
    {
    /**
    * @Route("/blog/article")
    */
    public function articleAction(Request $request)
    {
    $id = $request->query->get('id');
    $article = $database->findArticle($id);
    if (!$article) {
    return new Response('Article not found.', 404);
    }



    }
    }
    #DCMuc16

    View Slide

  48. Request

    /blog/article?id=34
    class BlogController extends Controller
    {
    /**
    * @Route("/blog/article")
    */
    public function articleAction(Request $request)
    {
    $id = $request->query->get('id');
    $article = $database->findArticle($id);
    if (!$article) {
    return new Response('Article not found.', 404);
    }



    }
    }
    #DCMuc16
    Response 404

    Article not found

    View Slide

  49. Request

    /blog/article?id=34
    class BlogController extends Controller
    {
    /**
    * @Route("/blog/article")
    */
    public function articleAction(Request $request)
    {
    $id = $request->query->get('id');
    $article = $database->findArticle($id);
    if (!$article) {
    return new Response('Article not found.', 404);
    }
    $html = $view->renderArticle($article);
    }
    }
    #DCMuc16

    View Slide

  50. Request

    /blog/article?id=34
    class BlogController extends Controller
    {
    /**
    * @Route("/blog/article")
    */
    public function articleAction(Request $request)
    {
    $id = $request->query->get('id');
    $article = $database->findArticle($id);
    if (!$article) {
    return new Response('Article not found.', 404);
    }
    $html = $view->renderArticle($article);
    return new Response($html, 200);
    }
    }
    #DCMuc16
    Response 200

    Article 34

    View Slide

  51. During the Request ➾ Response flow,

    many more components will assist
    #DCMuc16

    View Slide

  52. • Routing Match URL to controller action
    • Templating Render templates
    • Security Decide about access
    • Config Load configuration
    • Forms Create HTML forms
    • …
    #DCMuc16

    View Slide

  53. Who is going to configure all this?

    View Slide

  54. Symfony Configuration
    #DCMuc16

    View Slide

  55. Symfony Configuration
    dev prod test
    #DCMuc16

    View Slide

  56. Symfony Configuration
    dev
    /app_dev.php/articles /app.php/articles
    prod test
    UseCaseTest
    #DCMuc16

    View Slide

  57. Front Controller Symfony Configuration
    dev
    /app_dev.php/articles /app.php/articles
    prod test
    UseCaseTest
    #DCMuc16

    View Slide

  58. Symfony Configuration
    dev
    /app_dev.php/articles /app.php/articles
    prod test
    UseCaseTest
    Test class
    #DCMuc16

    View Slide

  59. Symfony Configuration
    dev
    /app_dev.php/articles /app.php/articles
    new AppKernel('prod', false);
    new AppKernel('dev', true); new AppKernel('test', false);
    prod test
    UseCaseTest
    #DCMuc16

    View Slide

  60. Symfony Configuration
    dev
    /app_dev.php/articles /app.php/articles
    new AppKernel('prod', false);
    new AppKernel('dev', true); new AppKernel('test', false);
    config_prod.yml config_test.yml
    config_dev.yml
    prod test
    UseCaseTest
    #DCMuc16

    View Slide

  61. Symfony Configuration
    dev
    /app_dev.php/articles /app.php/articles
    new AppKernel('prod', false);
    new AppKernel('dev', true); new AppKernel('test', false);
    config_prod.yml config_test.yml
    config_dev.yml
    prod test
    config.yml
    UseCaseTest
    #DCMuc16

    View Slide

  62. database:

    driver: pdo_mysql

    charset: utf8




    # …
    config.yml
    #DCMuc16

    View Slide


  63. database:

    driver: pdo_mysql

    charset: utf8

    user: '%db_user%'
    password: '%db_password%'


    # …
    config.yml
    #DCMuc16

    View Slide

  64. imports:
    - { resource: parameters.yml }
    database:

    driver: pdo_mysql

    charset: utf8

    user: '%db_user%'
    password: '%db_password%'


    # …
    config.yml
    #DCMuc16

    View Slide

  65. imports:
    - { resource: parameters.yml }
    database:

    driver: pdo_mysql

    charset: utf8

    user: '%db_user%'
    password: '%db_password%'


    # …
    config.yml parameters.yml
    parameters:






    #DCMuc16

    View Slide

  66. imports:
    - { resource: parameters.yml }
    database:

    driver: pdo_mysql

    charset: utf8

    user: '%db_user%'
    password: '%db_password%'


    # …
    config.yml parameters.yml
    parameters:






    added to .gitgnore
    #DCMuc16

    View Slide

  67. imports:
    - { resource: parameters.yml }
    database:

    driver: pdo_mysql

    charset: utf8

    user: '%db_user%'
    password: '%db_password%'


    # …
    config.yml parameters.yml
    parameters:






    db_user: drupal
    db_password: ThisIsSuperS3cr3t


    # …
    added to .gitgnore
    #DCMuc16

    View Slide

  68. Dependency Injection
    #DCMuc16

    View Slide

  69. Logger Beispiel
    /**
    * @Route("/weather/at/{zip}")
    */
    public function weatherAction(string $zip)
    {
    }
    #DCMuc16

    View Slide

  70. Logger Beispiel
    /**
    * @Route("/weather/at/{zip}")
    */
    public function weatherAction(string $zip)
    {
    // ...

    // ... Do heavy stuff to calculate $weatherData from $zip ...
    // ...

    $theWeather = $this->render('weather.html.twig', $weatherData);
    return new Response($theWeather, 200));
    }
    #DCMuc16
    Lots of stuff happens here to prepare the weather data

    View Slide

  71. Logger Beispiel
    Let’s extract this to an independent service class!
    class WeatherForecast
    {
    public function forZip(string $zip): array
    {
    // ...
    // ... Do heavy stuff to calculate $weatherData from $zip ...

    // ...
    return $weatherData;
    }
    }
    #DCMuc16

    View Slide

  72. Logger Beispiel
    class WeatherForecast
    {
    public function forZip(string $zip): array
    {
    // ...
    // ... Do heavy stuff to calculate $weatherData from $zip ...

    // ...
    return $weatherData;
    }
    }
    #DCMuc16
    It only does ONE thing!

    View Slide

  73. Logger Beispiel
    /**
    * @Route("/weather/at/{zip}")
    */
    public function weatherAction(string $zip)
    {
    $weatherForecast = new WeatherForecast();
    $weatherData = $weatherForecast->forZip($zip);
    $theWeather = $this->render('weather.html.twig', $weatherData);
    return new Response($theWeather, 200));
    }
    Then use the service from the controller!
    #DCMuc16

    View Slide

  74. Logger Beispiel
    class WeatherForecast
    {
    public function forZip(string $zip): array
    {
    $logger = new FileLogger('/var/log/weather.log');
    // ...
    // ... Things might go wrong ...

    $logger->notice('No forecast found for ZIP '.$zip);

    // ... Things might work

    $logger->info('Forecast provided for ZIP '.$zip);
    // ...
    return $weatherData;
    }
    }
    But now imagine a dependency to a Logger service
    #DCMuc16

    View Slide

  75. Logger Beispiel
    class WeatherForecast
    {
    public function forZip(string $zip): array
    {
    $logger = new FileLogger('/var/log/weather.log');
    // ...
    // ... Things might go wrong ...

    $logger->notice('No forecast found for ZIP '.$zip);

    // ... Things might work

    $logger->info('Forecast provided for ZIP '.$zip);
    // ...
    return $weatherData;
    }
    }
    But now imagine a dependency to a Logger service
    #DCMuc16
    • How to test this code?
    • How to switch the log file?
    • How to use a different logger?

    View Slide

  76. Logger Beispiel
    class WeatherForecast

    {
    private $logger;
    public function __construct($logger)

    {
    $this->logger = $logger;
    }
    public function forZip(string $zip): array 

    {
    // ...
    $this->logger->info('Forecast provided for ZIP '.$zip);
    // ...
    }
    }
    Why not inject the logger dependency?
    #DCMuc16

    View Slide

  77. Logger Beispiel
    class WeatherForecast

    {
    private $logger;
    public function __construct(Psr\Log\LoggerInterface $logger)

    {
    $this->logger = $logger;
    }
    public function forZip(string $zip): array 

    {
    // ...
    $this->logger->info('Forecast provided for ZIP '.$zip);
    // ...
    }
    }
    And type hint it against an interface contract?
    #DCMuc16

    View Slide

  78. Logger Beispiel
    class FileLogger implements Psr\Log\LoggerInterface

    {


    private $logFilePath;
    public function __construct(string $logFilePath)

    {
    $this->logFilePath = $logFilePath;
    }
    public function notice($message) { … }

    public function info($message) { … }



    }
    #DCMuc16

    View Slide

  79. Logger Beispiel
    /**
    * @Route("/weather/at/{zip}")
    */
    public function weatherAction(string $zip)
    {
    $logger = new FileLogger('/var/log/weather.log');

    $weatherForecast = new WeatherForecast($logger);

    // ...
    }
    Inject the logger dependency into the constructor
    #DCMuc16

    View Slide

  80. #DCMuc16
    Service Container

    View Slide

  81. services:

    config.yml
    #DCMuc16
    Now shift the service creation to a service container

    View Slide

  82. services:

    logger:

    class: FileLogger




    config.yml
    #DCMuc16

    View Slide

  83. services:

    logger:

    class: FileLogger

    arguments:

    - '/var/log/weather.log'



    config.yml
    #DCMuc16

    View Slide

  84. services:

    logger:

    class: FileLogger

    arguments:

    - '/var/log/weather.log'
    weather_forecast:

    class: WeatherForecast

    config.yml
    #DCMuc16

    View Slide

  85. services:

    logger:

    class: FileLogger

    arguments:

    - '/var/log/weather.log'
    weather_forecast:

    class: WeatherForecast

    arguments:

    - '@logger'
    config.yml
    #DCMuc16

    View Slide

  86. /**
    * @Route("/weather/at/{zip}")
    */
    public function weatherAction(string $zip)
    {
    $weatherForecast = $this->container->get('...');
    $weatherData = $weatherForecast->forZip($zip);
    $theWeather = $this->render('weather.html.twig', $weatherData);
    return new Response($theWeather, 200));
    }
    #DCMuc16

    View Slide

  87. /**
    * @Route("/weather/at/{zip}")
    */
    public function weatherAction(string $zip)
    {
    $weatherForecast = $this->container->get('weather_forecast');
    $weatherData = $weatherForecast->forZip($zip);
    $theWeather = $this->render('weather.html.twig', $weatherData);
    return new Response($theWeather, 200));
    }
    #DCMuc16

    View Slide

  88. config.yml
    #DCMuc16
    services:

    logger:

    class: NullLogger
    weather_forecast:

    class: WeatherForecast

    arguments:

    - '@logger'


    View Slide

  89. config.yml
    #DCMuc16
    services:

    logger:

    class: DatabaseLogger
    weather_forecast:

    class: WeatherForecast

    arguments:

    - '@logger'


    View Slide

  90. #DCMuc16
    Console

    View Slide

  91. File upload script with some flags, options and arguments
    #DCMuc16
    $ ./upload-files --overwrite cat-1.jpg cat-2.jpg cat-3.jpg 


    View Slide

  92. File upload script with some flags, options and arguments
    #DCMuc16
    $ ./upload-files --overwrite cat-1.jpg cat-2.jpg cat-3.jpg 

    Uploading 'cat-1.jpg' ...


    View Slide

  93. File upload script with some flags, options and arguments
    #DCMuc16
    $ ./upload-files --overwrite cat-1.jpg cat-2.jpg cat-3.jpg 

    Uploading 'cat-1.jpg' ...

    Uploading 'cat-2.jpg' ...


    View Slide

  94. File upload script with some flags, options and arguments
    #DCMuc16
    $ ./upload-files --overwrite cat-1.jpg cat-2.jpg cat-3.jpg 

    Uploading 'cat-1.jpg' ...

    Uploading 'cat-2.jpg' ...

    Uploading 'cat-3.jpg' ...

    View Slide

  95. #DCMuc16
    Now we gonna tackle $_SERVER['argv'] !

    View Slide

  96. use Symfony\Component\Console\Command\Command;

    class UploadFilesCommand extends Command
    {
    }
    #DCMuc16
    #DCMuc16

    View Slide

  97. use Symfony\Component\Console\Command\Command;

    class UploadFilesCommand extends Command
    {
    protected function configure()
    {
    // ...
    }
    }
    #DCMuc16

    View Slide

  98. use Symfony\Component\Console\Command\Command;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Output\OutputInterface;
    class UploadFilesCommand extends Command
    {
    protected function configure()
    {
    // ...
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
    // ...
    }
    }
    #DCMuc16

    View Slide

  99. class UploadFilesCommand extends Command
    {
    protected function configure()
    {

    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
    }
    }
    #DCMuc16

    View Slide

  100. class UploadFilesCommand extends Command
    {
    protected function configure()
    {
    $this

    ->setName('upload-files');

    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
    }
    }
    #DCMuc16

    View Slide

  101. class UploadFilesCommand extends Command
    {
    protected function configure()
    {
    $this

    ->setName('upload-files')
    ->addOption('overwrite', 'o', InputOption:: VALUE_NONE, 'Overwrite files?');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
    }
    }
    #DCMuc16

    View Slide

  102. class UploadFilesCommand extends Command
    {
    protected function configure()
    {
    $this
    ->setName('upload-files')
    ->addOption('overwrite', 'o', InputOption:: VALUE_NONE, 'Overwrite files?')
    ->addArgument('filePaths', InputArgument::IS_ARRAY, 'Files to upload?');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {

    }
    }
    #DCMuc16

    View Slide

  103. class UploadFilesCommand extends Command
    {
    protected function configure()
    {
    $this

    ->setName('upload-files')
    ->addOption('overwrite', 'o', InputOption:: VALUE_NONE, 'Overwrite files?')
    ->addArgument('filePaths', InputArgument::IS_ARRAY, 'Files to upload?');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
    }
    }
    #DCMuc16

    View Slide

  104. class UploadFilesCommand extends Command
    {
    protected function configure()
    {
    $this

    ->setName('upload-files')
    ->addOption('overwrite', 'o', InputOption:: VALUE_NONE, 'Overwrite files?')
    ->addArgument('filePaths', InputArgument::IS_ARRAY, 'Files to upload?');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
    $overwrite = $input->hasOption('overwrite');
    }
    }
    #DCMuc16

    View Slide

  105. class UploadFilesCommand extends Command
    {
    protected function configure()
    {
    $this

    ->setName('upload-files')
    ->addOption('overwrite', 'o', InputOption:: VALUE_NONE, 'Overwrite files?')
    ->addArgument('filePaths', InputArgument::IS_ARRAY, 'Files to upload?');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
    $overwrite = $input->hasOption('overwrite');
    foreach ($input->getArgument('filePaths') as $path) {
    }
    }
    }
    #DCMuc16

    View Slide

  106. class UploadFilesCommand extends Command
    {
    protected function configure()
    {
    $this

    ->setName('upload-files')
    ->addOption('overwrite', 'o', InputOption:: VALUE_NONE, 'Overwrite files?')
    ->addArgument('filePaths', InputArgument::IS_ARRAY, 'Files to upload?');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
    $overwrite = $input->hasOption('overwrite');
    foreach ($input->getArgument('filePaths') as $path) {
    $output->writeLn("Uploading '{$path}' ... ");
    // ... do the upload depending on $overwrite
    }
    }
    }
    #DCMuc16

    View Slide

  107. Anything else?
    #DCMuc16

    View Slide

  108. Bundles
    • ~ PlugIns, but even better
    • Everything in Symfony Full-Stack is a Bundle
    • Yes, Symfony Full-Stack itself is a Bundle
    • Core and custom code is in Bundles
    • Registered in HttpKernel
    #DCMuc16

    View Slide

  109. • PSR – PHP Standards Recommendations
    • HTTP Specification
    Symfony ♥ Standards
    #DCMuc16

    View Slide

  110. • Git & GitHub
    • Semantic Versioning – Breaking.Feature.Fix
    • Dependency Injection
    • Event Driven
    • Popularize ORMs
    • New level of code quality and architecture
    • Command Line Tools
    Symfony drives Innovation
    … just to name a few
    (in the PHP world, at least …)
    #DCMuc16

    View Slide

  111. • Twig
    • Composer
    • Monolog
    • Swiftmailer
    • Silex
    • PHP CS Fixer


    Symfony “by-products”
    #DCMuc16

    View Slide

  112. • Outstanding Documentation
    • Huge ecosystem of 3rd-party bundles
    • Creates many “celebrities”
    • Conferences
    • Certification
    Symfony’s Community
    (and SensioLabs)
    #DCMuc16

    View Slide

  113. Evolution, not Revolution
    Symfony 3
    #DCMuc16

    View Slide

  114. @bicpi
    Questions?
    https://philipp-rieber.net
    #DCMuc16

    View Slide

  115. Links
    • http://symfony.com/
    • https://github.com/symfony
    • http://fabien.potencier.org/what-is-symfony2.html
    • http://symfony.com/doc/current/create_framework
    • http://www.php-fig.org/
    #DCMuc16

    View Slide