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

Symfony2 and Zend Framework 2: the perfect team

Enrico Zimuel
November 22, 2013

Symfony2 and Zend Framework 2: the perfect team

The next generation of frameworks is upon us, and now that they’re more decoupled and component-based than ever before and use the same standard for naming and autoloading, there is no reason to stick to a single framework for your projects. During this session, we will go through several ways of combining Symfony2 and Zend Framework 2, so that you walk away being able to focus even more on on writing the complex custom logic your project needs, and don’t have to worry about the rest.
In the talk we will show how to create a RESTful API for an existing Symfony2 project using Apigiliry, an API builder written in ZF2. Moreover we will show how to consume the API in an existing Symfony2 project using ZF2 (ZendService_Api).

Enrico Zimuel

November 22, 2013
Tweet

More Decks by Enrico Zimuel

Other Decks in Programming

Transcript

  1. Symfony2 and Zend Framework 2:
    Symfony2 and Zend Framework 2:
    The Perfect Team
    The Perfect Team
    Stefan Koopmanschap, Enrico Zimuel

    View Slide

  2. About us

    Stefan Koopmanschap

    Enterpreneur: Ingewikkeld and
    Techademy

    Member of Dutch Web Alliance

    Symfony Community Manager

    Co-Founder PHPBenelux, now
    PFZ.nl

    [email protected]

    Enrico Zimuel

    Software Engineer at Zend
    Technologies

    Zend Framework and
    Apigility Core Team

    Co-founder PUG Turin

    [email protected]

    View Slide

  3. PHP frameworks

    Symfony and Zend Framework are the most
    used PHP frameworks worldwide

    Both offer a tons of features that can improve
    the development of web applications

    Modular architectures and high quality PHP
    code (SoC + SOLID principles)

    Why don't use it together to get the best
    features of both?

    View Slide

  4. Religion war?
    ZF sucks!
    Symfony?
    Oh My!

    View Slide

  5. Instead of think about
    ZF2 || Symfony 2
    think about
    ZF2 && Symfony 2

    View Slide

  6. PSR-*

    Framework interoperability standards

    Meant to make it easier to work with multiple
    frameworks

    Naming standards and coding standards

    For instance: only one autoloader!

    http://www.php-fig.org/

    View Slide

  7. PSR-0

    Autoloading standard:
    \\(\)*
    Each namespace separator is converted to a
    DIRECTORY_SEPARATOR when loading from the file
    system

    View Slide

  8. PSR-1

    Basic coding standard:
    Files MUST use only Namespaces and classes MUST follow PSR-0
    Class constants MUST be declared in all upper case
    with underscore separators
    Method names MUST be declared in camelCase
    ...

    View Slide

  9. PSR-2

    Coding style guide:
    Code MUST follow PSR-1
    Code MUST use 4 spaces for indenting, not tabs
    There MUST be one blank line after the namespace
    declaration, and there MUST be one blank line after the
    block of use declarations
    Opening braces for classes MUST go on the next line,
    and closing braces MUST go on the next line after the
    body
    ...

    View Slide

  10. PSR-3

    Logger interface:
    The LoggerInterface exposes eight methods to write
    logs to the eight RFC 5424 levels (debug, info, notice,
    warning, error, critical, alert, emergency)
    A ninth method, log, accepts a log level as first
    argument. Calling this method with one of the log level
    constants MUST have the same result as calling the
    level-specific method
    ...

    View Slide

  11. View Slide

  12. Composer

    Composer (getcomposer.org) can help the
    management of projects that use Symfony2
    and ZF2
    – Select your favorite Symfony2 and ZF2
    components using composer.json
    – php composer.phar install
    – Components installed in /vendor
    – Include the /vendor/autoload.php in your
    PHP code, that's it!

    View Slide

  13. Use case:
    Use case:
    Create an API for an existing
    Create an API for an existing
    Symfony 2 application
    Symfony 2 application
    using ZF2/Apigility
    using ZF2/Apigility

    View Slide

  14. What is Apigility?

    Apigility is an API builder for PHP (written in ZF2)

    Apigility helps you to create APIs with REST
    and RPC services that take care of:
    – Error handling
    – Authentication
    – Validation and filtering
    – Content negotiation
    – Versioning

    http://apigility.org

    View Slide

  15. Install Apigility

    Via release tarball/zip:
    – Goes to https://github.com/zfcampus/zf-apigility-skeleton/releases

    Via composer:
    – curl ­s https://getcomposer.org/installer | php ­­
    – php composer.phar create­project ­sdev
    zfcampus/zf­apigility­skeleton path/to/install

    Via github:
    – git clone
    https://github.com/zfcampus/zf­apigility­skeleton.git
    – curl ­s https://getcomposer.org/installer | php
    – php composer.phar install

    View Slide

  16. Execute the admin UI

    Enable the development mode:
    – php public/index.php development enable

    Execute the apigility skeleton in a web server
    (e.g. PHP internal web server >=5.4.9):
    – php ­S 0:8000 ­t public/ public/index.php

    Goes to the apigility admin UI using a browser
    (e.g. http://localhost:8000)

    View Slide

  17. Apigility Admin UI

    View Slide

  18. Apigility Dashboard

    View Slide

  19. API for a Symfony2 app

    Goal:
    – Create a RESTful API for an existing Symfony2
    application

    Requirements:
    – We want to reuse the existing code (Model) of the
    Symfony2 application and just consume it for the
    API

    View Slide

  20. Steps to do in the Apigility UI

    Create a new API (e.g. Post)

    Create a new REST Service
    – Route to match: /post[:/id]
    – Rest parameters:

    Identifier name: id

    Collection name: post

    View Slide

  21. Edit the configuration

    Edit the config/module.config.php of your API module
    (e.g. Blog)

    In 'zf-rest' set the 'entity_class' to the Entity used by
    Symfony2 (e.g. BlogBundle\Entity\Post) and the
    'identifier_name' to the ID used by the Entity (e.g. id)

    In 'zf-hal' => 'metadata_map' set the 'identifier_name'
    to the Entity id used by Symfony2 (e.g. id) and the
    'hydrator' => 'ClassMethods' for the entity.

    View Slide

  22. Edit composer.json

    Include the “require” of the Symfony2 application in
    composer.json of Apigility

    For instance:
    "require": {
    "php": ">=5.3.3",
    "zendframework/zendframework": "dev-develop",
    "rwoverdijk/assetmanager": "dev-master",
    "zfcampus/zf-apigility": "dev-master",
    "zfcampus/zf-configuration": "dev-master",
    "symfony/symfony": "2.3.*",
    "doctrine/orm": ">=2.2.3,<2.4-dev",
    "doctrine/doctrine-bundle": "1.2.*",
    “twig/extensions": "1.0.*",
    ...

    View Slide

  23. Steps to do in the source code

    We need to map the Post resource of Apigility
    with the Post service used in the Symfony2 app:
    – Boostrap the AppKernel of Symfony inside the
    constructor of V1/Rest/Post/PostResource
    – Get the Post service from the Container of Symfony2
    – Change the specific methods (fetch, fetchAll, create,
    etc) using the Post service methods of the Symfony2
    app

    View Slide

  24. V1/Rest/Post/PostResource
    class PostResource extends AbstractResourceListener
    {
    protected $postService;
    public function __construct()
    {
    $dir = '/path/to/Symfony2/application';
    require_once $dir . '/app/AppKernel.php';
    $kernel = new \AppKernel('prod', false);
    $kernel->loadClassCache();
    $kernel->boot();
    $this->postService = $kernel->getContainer()->get('postservice');
    }
    //...

    View Slide

  25. Service/Post in Symfony2
    class Post
    {
    private $doctrine;
    public function __construct($doctrine) {
    $this->doctrine = $doctrine;
    }
    public function persist($entity) {
    $this->doctrine->getManager()->persist($entity);
    $this->doctrine->getManager()->flush();
    }
    public function getAll() {
    return $this->doctrine->getRepository('BlogBundle:Post')->findAll();
    }
    public function get($id) {
    return $this->doctrine->getRepository('BlogBundle:Post')->find($id);
    }
    }

    View Slide

  26. RESTful methods in Apigility
    ...
    // GET /post/id
    public function fetch($id)
    {
    return $this->postService->get($id);
    }
    // GET /post
    public function fetchAll($params = array())
    {
    return $this->postService->getAll();
    }
    ...

    View Slide

  27. Use case:
    Use case:
    Consume an (Apigility) API
    Consume an (Apigility) API
    in Symfony 2
    in Symfony 2
    using ZF2
    using ZF2 (ZendService_Api)
    (ZendService_Api)

    View Slide

  28. composer create-project
    symfony/framework-standard-edition
    project

    View Slide

  29. Composer.json
    "require": {
    "php": ">=5.3.3",
    "symfony/symfony": "2.3.*",
    (...)
    "zendframework/zendservice-api": "dev-master"
    },

    View Slide

  30. composer install

    View Slide

  31. Composer installation...

    View Slide

  32. Under the vendor folder...

    View Slide

  33. ZendService_Api

    This is a micro HTTP framework to consume
    generic API calls in PHP

    It can be used to create PHP libraries that
    consume specific HTTP API using simple
    configuration array (or files)

    It uses the Zend\Http\Client component of
    Zend Framework 2

    https://github.com/zendframework/ZendService_Api

    View Slide

  34. Now let's get to work

    View Slide

  35. The API as a Symfony2 service

    View Slide

  36. namespace ForumPhp\BlogBundle\Service;
    class ApiService
    {
    protected $client = null;
    public function __construct($client)
    { }
    protected function init()
    { }
    }
    ApiService

    View Slide

  37. public function __construct($client)
    {
    $this->client = $client;
    $this->init();
    }

    View Slide

  38. protected function init()
    {
    $this->client->setApi('blogget', function ($params) {
    return array(
    'url' => 'http://localhost:8000/post', // URL to post API
    'header' => array(
    'Content-Type' => 'application/json'
    ),
    'method' => 'GET',
    'response' => array(
    'valid_codes' => array(200)
    )
    );
    });
    }

    View Slide

  39. /**
    * @Route("/")
    * @Template()
    */
    public function indexAction()
    {
    $client = $this->container->get('apiservice');
    $posts = $client->blogget();
    return array('posts' => $posts);
    }

    View Slide

  40. Some stuff I won't show...

    Zend\Barcode

    Zend\Captcha

    Zend\Crypt

    Zend\Feed

    Zend\I18n

    ZendService_*

    View Slide

  41. How to integrate
    How to integrate
    Symfony2 in a
    Symfony2 in a
    Zend Framework 2 project
    Zend Framework 2 project

    View Slide

  42. How to use Symfony2 in ZF2

    Use composer.json to include the Symfony2
    components

    Execute the update (or install) command of
    composer

    The Symfony2 composer will be installed in /vendor

    MVC approach:

    Register the Symfony2 components in the
    ServiceManager

    “Standard” approach:

    Use the Symfony2 components directly
    (instantiate the class and use it)

    View Slide

  43. composer.json
    {
    "require": {
    "php": ">=5.3.3",
    "zendframework/zendframework": "2.0.*",
    "symfony/yaml": "2.2.*",
    "symfony/dom-crawler": "2.2.*",
    },
    "autoload": {
    "psr-0": {
    "Application": "module/Application/src"
    }
    }
    }

    View Slide

  44. Symfony component as invokable
    // a module config "module/SomeModule/config/module.config.php"
    return array(
    'service_manager' => array(
    'invokables' => array(
    // Keys are the service names
    // Values are valid class names to instantiate
    'YamlParser' => 'Symfony\Component\Yaml\Parser',
    'DomCrawler' => 'Symfony\Component\DomCrawler\Crawler',
    // ...
    ),
    )
    );

    View Slide

  45. Symfony component as factory
    // a module config "module/SomeModule/config/module.config.php"
    return array(
    'service_manager' => array(
    'factories' => array(
    // Keys are the service names.
    // Valid values include names of classes implementing
    // FactoryInterface, instances of classes implementing
    // FactoryInterface, or any PHP callbacks
    'YamlParser' => 'Symfony\Component\Yaml\Parser',
    'DomCrawler' => function ($html) {
    return new Symfony\Component\DomCrawler\Crawle($html)
    }
    // ...
    ),
    )
    );

    View Slide

  46. Use a service in a Controller
    class AlbumController extends AbstractActionController
    {
    public function indexAction()
    {
    $sm = $this->getServiceLocator();
    $yamlParser = $sm->get('YamlParser');
    $domCrawler = $sm->get('DomCrawler');
    }
    // ...
    }

    View Slide

  47. Symfony 2 components

    Some components useful for ZF2 users:
    – BrowserKit (simulates a web browser)
    – CssSelector
    – Filesystem
    – Finder (file search)
    – OptionsResolver
    – Process (executes commands in sub-processes)
    – Serializer (handle serializing data structures)
    – YAML parser

    View Slide

  48. Concluding
    Concluding

    View Slide

  49. To integrate

    PSR / Framework Interoperability

    Composer

    Pick your components

    Don't stop at Symfony/Zend Framework

    Don't Reinvent The Wheel!

    View Slide

  50. Where to go?
    http://packagist.org

    View Slide

  51. Thanks!
    http://framework.zend.com
    Give feedback: https://joind.in/9364
    http://www.symfony.com http://apigility.org

    View Slide