Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Symfony2's descend into phpDocumentor2

Mike van Riel
September 14, 2012

Symfony2's descend into phpDocumentor2

Mike van Riel

September 14, 2012
Tweet

More Decks by Mike van Riel

Other Decks in Technology

Transcript

  1. joind.in / 7059
    phpDocumentor
    A Symfony Components use-case by Mike van Riel

    View Slide

  2. joind.in / 7059
    phpDocumentor
    Who am I?
    Mike van Riel

    @mvriel

    Lead Developer for
    phpDocumentor 2

    Core Developer for Cilex

    Contributor for many others

    Foster-father of 2 (dogs)

    View Slide

  3. joind.in / 7059
    phpDocumentor
    What is going to be covered?

    Introduction to Symfony Components

    Timeline of phpDocumentor2: Components

    Autoloader

    Console

    Finder

    EventDispatcher

    Twig

    View Slide

  4. joind.in / 7059
    phpDocumentor
    “With this presentation I intend to inspire
    you to reduce the amount of code you
    maintain, and use Symfony Components
    to help you achieve that.”

    View Slide

  5. joind.in / 7059
    phpDocumentor
    Components

    View Slide

  6. joind.in / 7059
    phpDocumentor
    Benefits
    Less
    maintenance
    Reliable
    Easy
    To use

    Unit-tested

    Peer-
    reviewed

    Widely used

    Community
    Support

    Automatic
    updates

    Less code to
    maintain

    View Slide

  7. joind.in / 7059
    phpDocumentor
    Which components are there?

    Browserkit

    Classloader

    Config

    Console

    CssSelector

    Dependency
    Injection

    DomCrawler

    Event
    Dispatcher

    Finder

    Form

    Http
    Foundation

    HttpKernel

    Locale

    Process

    Routing

    Security

    Serializer

    Templating

    Translation

    Validator

    Yaml

    View Slide

  8. joind.in / 7059
    phpDocumentor
    Installing
    {
    "require": {
    "symfony/config": "2.*"
    }
    }
    $ pear channel-discover pear.symfony.com
    $ pear install symfony2/config
    Composer
    Pear

    View Slide

  9. joind.in / 7059
    phpDocumentor

    View Slide

  10. joind.in / 7059
    phpDocumentor
    “phpDocumentor
    did not use Symfony”

    View Slide

  11. joind.in / 7059
    phpDocumentor
    First version

    View Slide

  12. joind.in / 7059
    phpDocumentor
    Later

    View Slide

  13. joind.in / 7059
    phpDocumentor
    Stuck on PHP 5.2.6

    View Slide

  14. joind.in / 7059
    phpDocumentor
    Introducing plugins

    View Slide

  15. joind.in / 7059
    phpDocumentor
    Moving to PHP 5.3.3

    Faster performance

    Enabled Symfony2
    Components

    Namespaces

    PSR-0 Compatibility

    View Slide

  16. joind.in / 7059
    phpDocumentor
    Missing a lightweight framework

    View Slide

  17. joind.in / 7059
    phpDocumentor
    Missing a lightweight framework

    View Slide

  18. joind.in / 7059
    phpDocumentor
    Cilex was born
    Class Loader Console
    Pimple
    Cilex

    View Slide

  19. joind.in / 7059
    phpDocumentor
    Minimal CLI Application
    require_once __DIR__ . '/cilex.phar';
    $app = new \Cilex\Application('Cilex');
    $app->command(new \Cilex\Command\GreetCommand());
    $app->run();
    namespace Cilex\Command;
    use Symfony\Component\Console\Input\InputArgument, Symfony\Component\Console\Input\InputInterface,
    Symfony\Component\Console\Input\InputOption, Symfony\Component\Console\Output\OutputInterface;
    class GreetCommand extends Command
    {
    protected function configure()
    {
    $this->setName('demo:greet')
    ->setDescription('Greet someone')
    ->addArgument('name', InputArgument::OPTIONAL, 'Who do you want to greet?')
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
    $name = $input->getArgument('name');
    $output->writeln('Hello'.($name ? ' '.$name : ''));
    }
    }

    View Slide

  20. joind.in / 7059
    phpDocumentor
    Cilex

    View Slide

  21. joind.in / 7059
    phpDocumentor
    Now with Cilex

    View Slide

  22. joind.in / 7059
    phpDocumentor
    Components
    Class Loader

    View Slide

  23. joind.in / 7059
    phpDocumentor
    What does it do?

    Autoloader

    PSR-0 compatible

    PEAR compatible

    Can use classmaps for extra
    performance

    Can use APC to cache

    View Slide

  24. joind.in / 7059
    phpDocumentor
    Installing
    {
    "require": {
    "symfony/class-loader": "2.*"
    }
    }
    $ pear channel-discover pear.symfony.com
    $ pear install pear.symfony.com/ClassLoader
    Composer
    Pear

    View Slide

  25. joind.in / 7059
    phpDocumentor
    Example
    $loader = new UniversalClassLoader();
    $loader->registerNamespaces(array(
    'Symfony' => __DIR__.'/../vendor/symfony/symfony/src',
    'Monolog' => __DIR__.'/../vendor/monolog/monolog/src',
    ));
    $loader->register();

    View Slide

  26. joind.in / 7059
    phpDocumentor
    Components
    Console

    View Slide

  27. joind.in / 7059
    phpDocumentor
    What does it do?

    Enables Commands

    Provides default list command

    Provides default help command

    Interactive Commands

    Testability

    View Slide

  28. joind.in / 7059
    phpDocumentor
    Installing
    {
    "require": {
    "symfony/console": "2.*"
    }
    }
    $ pear channel-discover pear.symfony.com
    $ pear install pear.symfony.com/Console
    Composer
    Pear

    View Slide

  29. joind.in / 7059
    phpDocumentor
    Commands

    a single activity of a command line application

    Example: `phpdoc template:list`

    May have options

    Example: --help

    May have one or more arguments

    Example: `scrybe manual:to-html file1.rst file2.rst`

    Can be interactive

    Question-based instead of option-based

    View Slide

  30. joind.in / 7059
    phpDocumentor
    Example from phpDocumentor
    $console = new Console\Application($name, $version);
    protected function addCommandsForProjectNamespace()
    {
    $this->command(
    new \phpDocumentor\Command\Project\ParseCommand()
    );
    $this->command(
    new \phpDocumentor\Command\Project\RunCommand()
    );
    $this->command(
    new \phpDocumentor\Command\Project\TransformCommand()
    );
    }
    Convenience method provided by Cilex
    $console->add(new GreetCommand());
    $console->run();
    without Cilex

    View Slide

  31. joind.in / 7059
    phpDocumentor
    Creating a command (with Cilex)
    namespace Cilex\Command;
    use Symfony\Component\Console\Input\InputArgument,
    Symfony\Component\Console\Input\InputInterface,
    Symfony\Component\Console\Input\InputOption,
    Symfony\Component\Console\Output\OutputInterface;
    class GreetCommand extends Command
    {
    protected function configure()
    {
    $this->setName('demo:greet')
    ->setDescription('Greet someone')
    ->addArgument('name', InputArgument::OPTIONAL, 'Who do you want
    to greet?')
    }
    protected function execute(InputInterface $input, OutputInterface
    $output)
    {
    $name = $input->getArgument('name');
    $output->writeln('Hello'.($name ? ' '.$name : ''));
    }
    }

    View Slide

  32. joind.in / 7059
    phpDocumentor
    Creating a command (without Cilex)
    namespace My\Application\Command;
    use Symfony\Component\Console\Input\InputArgument,
    Symfony\Component\Console\Input\InputInterface,
    Symfony\Component\Console\Input\InputOption,
    Symfony\Component\Console\Output\OutputInterface,
    Symfony\Component\Console\Command\Command;
    class GreetCommand extends Command
    {
    protected function configure()
    {
    $this->setName('demo:greet')
    ->setDescription('Greet someone')
    ->addArgument('name', InputArgument::OPTIONAL, 'Who do you want to
    greet?')
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
    $name = $input->getArgument('name');
    $output->writeln('Hello'.($name ? ' '.$name : ''));
    }
    }

    View Slide

  33. joind.in / 7059
    phpDocumentor
    Let's pause for a moment
    http://www.flickr.com/photos/nicsuzor/2554668884

    View Slide

  34. joind.in / 7059
    phpDocumentor
    FileSet

    View Slide

  35. joind.in / 7059
    phpDocumentor
    Gathering files

    View Slide

  36. joind.in / 7059
    phpDocumentor
    Components
    Finder

    View Slide

  37. joind.in / 7059
    phpDocumentor
    What does it do?

    Finds files and folders

    Returns them as SplFileInfo objects

    Provides a DSL to retrieve a specific set of files

    Highly configurable and filterable

    Can use streams to find files in

    Example: `\Zend_Service_Amazon_S3`

    View Slide

  38. joind.in / 7059
    phpDocumentor
    Installing
    {
    "require": {
    "symfony/finder": "2.*"
    }
    }
    $ pear channel-discover pear.symfony.com
    $ pear install pear.symfony.com/Finder
    Composer
    Pear

    View Slide

  39. joind.in / 7059
    phpDocumentor
    Example from phpDocumentor
    $finder = new \Symfony\Component\Finder\Finder();
    $finder
    ->files()
    ->in($path)
    ->name(
    '/\.('.implode('|', $this->allowed_extensions).')$/'
    )
    ->ignoreDotFiles($this->getIgnoreHidden())
    ->filter(
    function(\SplFileInfo $file) use ($patterns) {
    if (!$patterns) {
    return true;
    }
    // apply ignore list on path instead of file, finder
    // can't do that by default
    return !preg_match($patterns, $file->getPathname());
    }
    );

    View Slide

  40. joind.in / 7059
    phpDocumentor
    Plugins
    (revisited)

    View Slide

  41. joind.in / 7059
    phpDocumentor
    Gathering files

    View Slide

  42. joind.in / 7059
    phpDocumentor
    Components
    EventDispatcher

    View Slide

  43. joind.in / 7059
    phpDocumentor
    What does it do?

    Allows a non-linear approach

    For example: hooks for a plugin

    Similar to: concepts from Aspect Oriented
    Programming

    Provide third-parties with controlled
    interaction

    Observer variant: Event Dispatcher pattern

    View Slide

  44. joind.in / 7059
    phpDocumentor
    Installing
    {
    "require": {
    "symfony/event-dispatcher": "2.*"
    }
    }
    $ pear channel-discover pear.symfony.com
    $ pear install pear.symfony.com/EventDispatcher
    Composer
    Pear

    View Slide

  45. joind.in / 7059
    phpDocumentor
    Events

    Have a name (eg. event.log)

    Are objects too

    Are used to:

    Trigger listeners

    Transfer state

    View Slide

  46. joind.in / 7059
    phpDocumentor
    Stock example
    $listener = new AcmeListener();
    $dispatcher->addListener(
    'foo.action', array($listener, 'onFooAction')
    );
    use Symfony\Component\EventDispatcher\EventDispatcher;
    $dispatcher = new EventDispatcher();
    $event = new FilterOrderEvent($order);
    $dispatcher->dispatch(
    StoreEvents::STORE_ORDER, $event
    );

    View Slide

  47. joind.in / 7059
    phpDocumentor
    Example from phpDocumentor
    $this->event_dispatcher->addListener(
    $event->getDescription(),
    array($this, $method->getName())
    );
    * @phpdoc-event reflection.docblock.tag.export
    */
    public function exportTag($data)
    {
    /** @var \phpDocumentor\Reflection\BaseReflector $subject */
    $subject = $data->getSubject();
    ...
    }
    $event = ..\Event\ExportDocBlockExtractionEvent::createInstance($this)
    ->setDocblock($this->doc_block)
    \phpDocumentor\Event\Dispatcher::getInstance()->dispatch(
    'reflection.docblock-extraction.export', $event
    );

    View Slide

  48. joind.in / 7059
    phpDocumentor
    Twig Templates

    View Slide

  49. joind.in / 7059
    phpDocumentor
    Using Twig to generate artifacts

    View Slide

  50. joind.in / 7059
    phpDocumentor
    Components
    Twig

    View Slide

  51. joind.in / 7059
    phpDocumentor
    What does it do?

    Converts a template into any text
    format

    Is inspired on Jinja, the Python
    templating engine

    Provides a concise, readable interface

    View Slide

  52. joind.in / 7059
    phpDocumentor
    Installing
    {
    "require": {
    "twig/twig": "1.*"
    }
    }
    $ pear channel-discover pear.twig-project.org
    $ pear install twig/Twig
    Composer
    Pear

    View Slide

  53. joind.in / 7059
    phpDocumentor
    Example from phpDocumentor
    $base_extension = new \phpDocumentor\Plugin\Twig\Extension(
    $structure, $transformation
    );
    $env->addExtension($base_extension);
    $env = new \Twig_Environment(
    new \Twig_Loader_Filesystem(
    $transformation->getTransformer()->getTemplatesPath().'/..'
    .DIRECTORY_SEPARATOR.$template_path
    )
    );
    file_put_contents(
    $destination,
    $environment->render(
    substr($transformation->getSource(), strlen($template_path))
    )
    );

    View Slide

  54. joind.in / 7059
    phpDocumentor
    Example template



    My Webpage



    {% for item in navigation %}


    {{ item.caption }}


    {% endfor %}

    My Webpage
    {{ a_variable }}


    View Slide

  55. joind.in / 7059
    phpDocumentor
    Conclusion

    Reduce the amount of LOC
    you need to maintain

    Use Components

    Build on the shoulders of
    giants

    It's easy

    View Slide

  56. joind.in / 7059
    phpDocumentor
    Questions?

    Please rate this talk on
    http://joind.in/7059

    More information can
    be found at:
    http://symfony.com/components

    You can follow me on
    twitter: @mvriel

    View Slide