Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

About us ● Stefan Koopmanschap ● Enterpreneur: Ingewikkeld and Techademy ● Member of Dutch Web Alliance ● Symfony Community Manager ● Co-Founder PHPBenelux, now PFZ.nl ● stefan@ingewikkeld.net ● Enrico Zimuel ● Software Engineer at Zend Technologies ● Zend Framework and Apigility Core Team ● Co-founder PUG Turin ● enrico@zend.com

Slide 3

Slide 3 text

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?

Slide 4

Slide 4 text

Religion war? ZF sucks! Symfony? Oh My!

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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/

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

PSR-1 ● Basic coding standard: Files MUST use only

Slide 9

Slide 9 text

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 ...

Slide 10

Slide 10 text

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 ...

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

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!

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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)

Slide 17

Slide 17 text

Apigility Admin UI

Slide 18

Slide 18 text

Apigility Dashboard

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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.

Slide 22

Slide 22 text

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.*", ...

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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'); } //...

Slide 25

Slide 25 text

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); } }

Slide 26

Slide 26 text

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(); } ...

Slide 27

Slide 27 text

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)

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

composer install

Slide 31

Slide 31 text

Composer installation...

Slide 32

Slide 32 text

Under the vendor folder...

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

Now let's get to work

Slide 35

Slide 35 text

The API as a Symfony2 service

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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) ) ); }); }

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

Some stuff I won't show... ● Zend\Barcode ● Zend\Captcha ● Zend\Crypt ● Zend\Feed ● Zend\I18n ● ZendService_*

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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)

Slide 43

Slide 43 text

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" } } }

Slide 44

Slide 44 text

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', // ... ), ) );

Slide 45

Slide 45 text

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) } // ... ), ) );

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

Concluding Concluding

Slide 49

Slide 49 text

To integrate ● PSR / Framework Interoperability ● Composer ● Pick your components ● Don't stop at Symfony/Zend Framework ● Don't Reinvent The Wheel!

Slide 50

Slide 50 text

Where to go? http://packagist.org

Slide 51

Slide 51 text

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