RESTful Modules in ZF2
Walter Dal Mut – walter.dalmut@gmail.com - @walterdalmut
               https://github.com/wdalmut




                @walterdalmut - www.corley.it - www.upcloo.com
About Me
                      • Walter Dal Mut (@walterdalmut)
                      • Electronic Engineer
                            • Polytechnic University of Turin
                      • Startupper
                            • Corley S.r.l. – www.corley.it
                                   • Cloud Computing Services
                            • UpCloo Ltd. – www.upcloo.com
                                   • Semantic Most Related Links service




           @walterdalmut - www.corley.it - www.upcloo.com
Summary
• REST introduction
• REST constraints
• Types of RESTful services
• ZF2 RESTful modules
   • RESTful ZF2 URI tunneling module
   • RESTful ZF2 CRUD module




                           @walterdalmut - www.corley.it - www.upcloo.com
RESTful? What it means in few words…
• Representational State Transfer (REST)

• Architecture is based on Client-Server
   • Clients initiate requests to servers; servers process requests and return
     appropriate responses
• Flexible, the application must know messages format
   • XML
   • JSON
   • Etc.


                             @walterdalmut - www.corley.it - www.upcloo.com
RESTful services are resource centric
• Resources (sources of specific information)
• Each resource is referenced with a global identifier (URI, etc.)
• Any number of connectors can mediate the request
   •   Clients
   •   Servers
   •   Caches
   •   Tunnels




                          @walterdalmut - www.corley.it - www.upcloo.com
REST Constraints
• Client-Server
   • A uniform interface separates clients from servers.
• Stateless
   • The client–server communication is further constrained by no client context being
     stored on the server between requests.
• Cacheable
   • Clients can cache responses
• Layered System
   • Intermediary servers may improve system scalability by enabling load-balancing and
     by providing shared caches. They may also enforce security policies.
• Uniform interface
   • Simplify and decouples the architecture


                               @walterdalmut - www.corley.it - www.upcloo.com
Several types of RESTful services
• URI Templates
   • http://rest.domain.tld/order/{orderID}
   • One of the major uses for URI templates is as human- and machine-readable
     documentation.
• URI Tunneling
   • http://rest.domain.tld/PlaceOrder?pizza=margherita&type=classic
      • Rest.domain.tld  service
      • PlaceOrder method
      • Pizza=margherita&type=classic  arguments
• POX – Plain Old XML over HTTP
   • Similar to URI Tunneling but information will be sent as XML document in the
     HTTP request from the customer.
                             @walterdalmut - www.corley.it - www.upcloo.com
POX – Plain Old XML over HTTP
   example
                     POST /PlaceOrder HTTP/1.1
                     Content-Type: application/xml
Client application                                                                         Application domain
                     <Order>
                       <Pizza>
                         <Name>margherita</Name>
                         <Type>classic</Type>
                       </Pizza>
                     </Order>

                     HTTP/1.1 200 OK

                     <OrderConfirmation>
                       <OrderID>1345</OrderID>
                     </OrderConfirmation>




                                          @walterdalmut - www.corley.it - www.upcloo.com
CRUD Webservices
• CRUD what it means?
   • Create, Read, Update and Delete
   • Patterns for manipulating resources across the network
• Extended usage of HTTP verbs
   •   GET
   •   POST
   •   PUT
   •   DELETE
• Using HTTP as an application protocol instead of a transport protocol
   • Web is really a big framework for building distributed systems.

                            @walterdalmut - www.corley.it - www.upcloo.com
HTTP verbs in CRUD services
• Get Read Operation
   • Used to retrive resource details
   • http://rest.service.tld/order/10
• Post  Create Operation
   • Used to create new resources
• Put Update Operation
   • Used to update existing resources
• Delete Delete Operation
   • Used to delete existing resources

POST/PUT can be exchanged and sometimes PUT/DELETE can be excluded to
enable javascript integration (PUT/DELETE not supported browser side
[HTTP_X_HTTP_METHOD_OVERRIDE parameter])

                                 @walterdalmut - www.corley.it - www.upcloo.com
CRUD Summary

Verb     URI or Template   Use
POST     /order            Create a new order, and upon success, receive a Location header specifying the
                           new order’s URI.
GET      /order/{id}       Request the current state of the order specified by the
                           URI.
PUT      /order/{id}       Update an order at the given URI with new information,
                           providing the full representation.
DELETE   /order/{id}       Logically remove the order identified by the given URI.




                                 @walterdalmut - www.corley.it - www.upcloo.com
Status code definition (short list)
• 2xx (Positives)
    • 200 OK – The request has succeeded.
    • 201 Created – The server accept the request and it has created the resource.
    • 202 Accepted – The request has been accepted for processing, but the processing has not been completed.
• 4xx (Client Errors)
    •   400 Bad Request – The request could not be understood by the server due to malformed syntax.
    •   401 Unauthorized – The request requires user authentication.
    •   403 Forbidden – The server understood the request, but is refusing to fulfill it.
    •   404 Not found – The server has not found anything matching the Request-URI.
    •   405 Method not allowed – The method specified in the Request-Line is not allowed for the resource identified
        by the Request-URI.
• 5xx (Server Errors)
    • 500 Internal Server Error – The server encountered an unexpected condition which prevented it from fulfilling
      the request.
    • 501 Not implemented – The server does not support the functionality required to fulfill the request.
    • 503 Service unavailable – The server is currently unable to handle the request due to a temporary overloading
      or maintenance of the server.

                                        @walterdalmut - www.corley.it - www.upcloo.com
RESTful module idea
                                                             • Router
                                                                • Wire requests to RESTful controllers
                                                             • RESTful Controllers
requests      Router                                            • Uses HTTP verbs to call dedicated
                                                                   actions
                                                                • Query models in order to serve
                          RESTful                                  responses
                                            Models           • POST Processors
                         Controllers
                                                                • Create valid messages using formats
                                                                      • JSON
 Responses     POST                                                   • XML
             Processor                                                • Etc.




                             @walterdalmut - www.corley.it - www.upcloo.com
Realize ZF2 tunneling RESTful module
• ZF1 provides «Zend_Rest_Server» that realize URI tunneling
• We can realize the same thing in 2 minutes thanks to ZF2 flexibility.

• We need to configure
   • Router
   • Events

• A simple example here:
   • https://github.com/wdalmut/ZF2-Tunneling-Restful-Module-Skeleton

                           @walterdalmut - www.corley.it - www.upcloo.com
ZF2 URI Tunneling - Configuration
<?php
return array(                                                                              We have created a simple base route «/tunnel»
    'controllers' => array(
        'invokables' => array(                                                             and a dynamic rule that select a «model» and an
          'index' => 'TunnelingRestController',
        )                                                                                  attached «action»
    ),
    'router' => array(
        'routes' => array(
             'tunneling' => array(                                                         In simple words
                 'type' => 'ZendMvcRouterHttpSegment',
                 'options' => array(                                                       • http://my-app.local/tunnel/menu/get?id=1
                     'route' => '/tunnel',
                     'defaults' => array(                                                  • «menu»
                         'controller' => 'index',
                         'action' => 'index'                                                    • The model «TunnelingModelMenu»
                     ),
                 ),                                                                        • «get»
                 'may_terminate' => true,
                 'child_routes' => array(                                                       • The model action «get()»
                     'default' => array(
                         'type' => 'ZendMvcRouterHttpSegment',                         • «id=1>
                         'options' => array(
                             'route' => '[/:model/:action]',                                    • The action parameters «get(1)»
                             'constraints' => array(
                                 'controller' => 'index',
                                 'model' => '[a-zA-Z][a-zA-Z0-9_]*',
                                 'action' => '[a-zA-Z][a-zA-Z0-9_]*'
                             ),
                         ),
                     ),
                 ),
             ),
        ),
    )
);
                                                           @walterdalmut - www.corley.it - www.upcloo.com
ZF2 URI Tunneling - Controller
<?php
namespace TunnelingRest;                                                                        The base «AbstractController» is very flexible
Use …                                                                                            and enable us to use the «dispatch» action to
class Controller extends AbstractController                                                      realize what we need in few lines.
{
    public function onDispatch(MvcEvent $e)
    {
        $routeMatch = $e->getRouteMatch();                                                       In practice we allocate the model and call the
        $params = $routeMatch->getParams();
        $vars = get_object_vars($e->getRequest()->getQuery());                                   requested action. The return variable is used as
        $filter = new ZendFilterFilterChain();                                                response.
        $filter->attach(new ZendFilterWordDashToCamelCase());
        $filter->attach(new ZendFilterCallback("lcfirst"));
        $action = $filter->filter($params["action"]);
        $filter->attach(new ZendFilterCallback("ucfirst"));                                   In case of missing model or missing action an
        $model = $filter->filter($params["model"]);
                                                                                                 «InvalidArgumentException» is thrown.
        $classname = "TunnelingModel{$model}";
        if (class_exists($classname)) {
            $clazz = new $classname;
            if (property_exists($clazz, $action)) {
                 $ret = call_user_func_array(array($clazz, $action), $vars);
                 $e->setResult($ret);
                 return;
            } else {
                 throw new InvalidArgumentException("Method "{$action}" doesn't exists'");
            }
        } else {
            throw new InvalidArgumentException("Class "{$classname}" doesn't exists'");
        }
    }
}
                                                                 @walterdalmut - www.corley.it - www.upcloo.com
ZF2 URI Tunneling – Model example
<?php
namespace TunnelingModel;                                                                   As you can see, the «model» is a simple class
                                                                                             definition.
class Menu
{
    public function get($id)
    {                                                                                        • /tunnel/menu/get?id=1
        return array("id" => $id);
    }                                                                                        • /tunnel/menu/add?x=pizza&y=4
    public function add($name, $value)
    {                                                                                        Very simple implementation
        return array("name" => $name, "value" => $value);
    }
}




                                                            @walterdalmut - www.corley.it - www.upcloo.com
ZF2 URI Tunneling – JSON responses
<?php
namespace Tunneling;
                                                                                              Thanks to events we can wire controller output
use ZendMvcMvcEvent;
                                                                                              to a post processor that converts responses in
class Module
                                                                                              json messages.
{
    public function onBootstrap($e)
    {
        /** @var ZendModuleManagerModuleManager $moduleManager */
                                                                                              • Attach a «postProcess» action and create a
        $moduleManager = $e->getApplication()->getServiceManager()->get('modulemanager');
        /** @var ZendEventManagerSharedEventManager $sharedEvents */
                                                                                                json message.
        $sharedEvents = $moduleManager->getEventManager()->getSharedManager();


          $sharedEvents->attach(
              'ZendMvcControllerAbstractController',
              MvcEvent::EVENT_DISPATCH,
              array($this, 'postProcess'),
              -100
          );
      }
//…
      public function postProcess(MvcEvent $e)
      {
          $routeMatch = $e->getRouteMatch();
          if (strpos($routeMatch->getMatchedRouteName(), "tunneling") !== false) {
              $e->getResponse()->setContent(json_encode($e->getResult()->getVariables()));
              return $e->getResponse();
          }
      }
}


                                                             @walterdalmut - www.corley.it - www.upcloo.com
ZF2 RESTful CRUD modules
• ZF2 provides a base controller class that can help us to realize RESTful
  modules in few steps
   • ZendMvcControllerAbstractRestfulController

• CRUD based implementation (Extended)
   •   get($id)
   •   delete($id)
   •   update($id)
   •   create($id)


                           @walterdalmut - www.corley.it - www.upcloo.com
ZF2 RESTful CRUD module example
• Clone ZF2 Skeleton Application
   • Git clone https://github.com/zendframework/ZendSkeletonApplication.git my-app
   • Git submodule init
   • Git submodule update
• Clone a ZF2 RESTful module
   • Git submodule add https://github.com/wdalmut/ZF2-Restful-Module-Skeleton.git module/Main
• Add «Main» module into «configs/application.config.php»
• Create you application virtual host and try it
   •   http://my-app.local/rest/info/json                                              [getList]
   •   http://my-app.local/rest/info/json/1                                            [get]
   •   curl –X POST –d ‘hello=world’ http://my-app.local/rest/info                     [create]
   •   curl –X PUT –d ‘hello=ciao’ http://my-app.local/rest/info/1                     [update]
   •   curl –X DELETE http://my-app.local/rest/info/1                                  [delete]

                                      @walterdalmut - www.corley.it - www.upcloo.com
RESTful Controllers
<?php
                                                         • RESTful Controller should extends AbstractRestfulController
namespace MainController;
                                                            • 5 abstract methods (CRUD + List)
use ZendMvcControllerAbstractRestfulController;
                                                                 • getList
class InfoController extends AbstractRestfulController
{                                                                     • GET operation without parameters
    public function getList()
    {                                                                 • /rest/json/info
    }
        return array('ciao' => 'mondo');
                                                                 • Get
    public function get($id)                                          • READ resource with parameters (ID)
    {
                                                                      • /rest/json/info/1
    }
                                                                 • Delete
    public function delete($id)
    {                                                                 • DELETE a resource
    }                                                            • Update
    public function update($id, $data)                                • UPDATE a resource
    {
                                                                 • Create
    }
                                                                      • CREATE a new resource
    public function create($data = null)
    {

    }
}


                                                          @walterdalmut - www.corley.it - www.upcloo.com
First of all play with routes
'router' => array(
    'routes' => array(                                                  • Create a base route /rest that enable also formatters
        'restful' => array(
            'type' => 'ZendMvcRouterHttpSegment',                       • Formatter allow us to switch easly to JSON,
            'options' => array(
                'route' => '/rest[/:formatter]',
                                                                               XML etc.
                'constraints' => array(                                 • Child routes play with controller and identifiers
                    'formatter' => '[a-zA-Z0-9_-]*',
                ),
            ),
            'may_terminate' => true,
            'child_routes' => array(
                'default' => array(
                    'type' => 'ZendMvcRouterHttpSegment',
                    'options' => array(
                        'route' => '[/:controller[/:id]]',
                        'constraints' => array(
                            'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                            'id' => '[a-zA-Z0-9_-]*'
                        ),
                    ),
                ),
            ),
        ),
    ),




                                                @walterdalmut - www.corley.it - www.upcloo.com
Formatters
• RESTful services can handle different type of messages
   •   JSON
   •   XML
   •   Images
   •   Etc
• The high modularity of ZF2 MVC implementation enable us to add
  different layers of abstractions and formatters is one of this.
   • Client must know what kind of messages type have to handle.
   • Post Processors are used to render messages


                           @walterdalmut - www.corley.it - www.upcloo.com
Formatters «configs/module.config.php»
'errors' => array(
    'post_processor' => 'json-pp',                      • The configuration allows us to define different «post processors»
    'show_exceptions' => array(
        'message' => true,
                                                        • Errors can be detailed more, for example traces, messages etc.
        'trace' => true
    )
),
'di' => array(
    'instance' => array(
        'alias' => array(
            'json-pp' => 'MainPostProcessorJson',
            'jsonp-pp' => 'MainPostProcessorJsonp',
            'image-pp' => 'MainPostProcessorImage'
        )
    )
),




                                                @walterdalmut - www.corley.it - www.upcloo.com
Wiring events (Module.php)
/**
 * @param MvcEvent $e
 */
 public function onBootstrap($e)
                                                                                                     • Event position -100
 {
     /** @var ZendModuleManagerModuleManager $moduleManager */
                                                                                                         • Handle post processors
     $moduleManager = $e->getApplication()->getServiceManager()->get('modulemanager');
     /** @var ZendEventManagerSharedEventManager $sharedEvents */
                                                                                                     • Event position 100
     $sharedEvents = $moduleManager->getEventManager()->getSharedManager();
                                                                                                         • Handle HTTP Method Override
     $sharedEvents->attach(
                                                                                                     • Event position 999
         'ZendMvcControllerAbstractRestfulController',
         MvcEvent::EVENT_DISPATCH,
                                                                                                         • Handle errors
         array($this, 'postProcess'),
         -100
     );


     $sharedEvents->attach(
         'MainControllerInfoController',
         MvcEvent::EVENT_DISPATCH,
         array($e->getApplication()->getServiceManager()->get('MainHttpRestful'), 'onDispatch'),
         100
     );


     $sharedEvents->attach(
         'ZendMvcApplication',
         MvcEvent::EVENT_DISPATCH_ERROR,
         array($this, 'errorProcess'),
         999
     );
 }

                                                       @walterdalmut - www.corley.it - www.upcloo.com
Attach Post Processor to Actions
public function postProcess(MvcEvent $e)
{
    $routeMatch = $e->getRouteMatch();
    $formatter = $routeMatch->getParam('formatter', false);

    $di = $e->getTarget()->getServiceLocator()->get('di');

    if ($formatter !== false) {
        if ($e->getResult() instanceof ZendViewModelViewModel) {
            if (($e->getResult()->getVariables())) {
                $vars = $e->getResult()->getVariables();
            } else {
                $vars = null;
            }
        } else {
            $vars = $e->getResult();
        }

        $postProcessor = $di->get($formatter . '-pp', array(
            'request' => $e->getRequest(),
            'response' => $e->getResponse(),
            'vars' => $vars,
        ));

        $postProcessor->process();

        return $postProcessor->getResponse();
    }

    return null;
}



                                                       @walterdalmut - www.corley.it - www.upcloo.com
Example of JSON Post Processor
<?php
                                                                       <?php
namespace MainPostProcessor;
                                                                       namespace MainPostProcessor;
/**
                                                                       abstract class AbstractPostProcessor
 *
                                                                       {
 */
                                                                           protected $_vars = null;
class Json extends AbstractPostProcessor
                                                                           private $_request = null;
{
                                                                           private $_response = null;
    public function process()
    {
                                                                           public function __construct
        $result = json_encode($this->_vars);
                                                                               (ZendHttpRequest $request, ZendHttpResponse $response, $vars = null)
                                                                           {
        $headers = $this->getResponse()->getHeaders();
                                                                               $this->_vars = $vars;
        $headers->addHeaderLine('Content-Type', 'application/json');
                                                                               $this->_response = $response;
                                                                               $this->_request = $request;
        $this->getResponse()->setHeaders($headers);
                                                                           }
        $this->getResponse()->setContent($result);
    }
                                                                           public function getResponse()
}
                                                                           {
                                                                               return $this->_response;
                                                                           }

                                                                           public function getRequest()
                                                                           {
                                                                               return $this->_request;
                                                                           }

                                                                           abstract public function process();
                                                                       }




                                                          @walterdalmut - www.corley.it - www.upcloo.com
ZF2 RESTful Modules
            Thanks for listening…



                  Any questions?




            @walterdalmut - www.corley.it - www.upcloo.com

RESTful modules in zf2

  • 1.
    RESTful Modules inZF2 Walter Dal Mut – walter.dalmut@gmail.com - @walterdalmut https://github.com/wdalmut @walterdalmut - www.corley.it - www.upcloo.com
  • 2.
    About Me • Walter Dal Mut (@walterdalmut) • Electronic Engineer • Polytechnic University of Turin • Startupper • Corley S.r.l. – www.corley.it • Cloud Computing Services • UpCloo Ltd. – www.upcloo.com • Semantic Most Related Links service @walterdalmut - www.corley.it - www.upcloo.com
  • 3.
    Summary • REST introduction •REST constraints • Types of RESTful services • ZF2 RESTful modules • RESTful ZF2 URI tunneling module • RESTful ZF2 CRUD module @walterdalmut - www.corley.it - www.upcloo.com
  • 4.
    RESTful? What itmeans in few words… • Representational State Transfer (REST) • Architecture is based on Client-Server • Clients initiate requests to servers; servers process requests and return appropriate responses • Flexible, the application must know messages format • XML • JSON • Etc. @walterdalmut - www.corley.it - www.upcloo.com
  • 5.
    RESTful services areresource centric • Resources (sources of specific information) • Each resource is referenced with a global identifier (URI, etc.) • Any number of connectors can mediate the request • Clients • Servers • Caches • Tunnels @walterdalmut - www.corley.it - www.upcloo.com
  • 6.
    REST Constraints • Client-Server • A uniform interface separates clients from servers. • Stateless • The client–server communication is further constrained by no client context being stored on the server between requests. • Cacheable • Clients can cache responses • Layered System • Intermediary servers may improve system scalability by enabling load-balancing and by providing shared caches. They may also enforce security policies. • Uniform interface • Simplify and decouples the architecture @walterdalmut - www.corley.it - www.upcloo.com
  • 7.
    Several types ofRESTful services • URI Templates • http://rest.domain.tld/order/{orderID} • One of the major uses for URI templates is as human- and machine-readable documentation. • URI Tunneling • http://rest.domain.tld/PlaceOrder?pizza=margherita&type=classic • Rest.domain.tld  service • PlaceOrder method • Pizza=margherita&type=classic  arguments • POX – Plain Old XML over HTTP • Similar to URI Tunneling but information will be sent as XML document in the HTTP request from the customer. @walterdalmut - www.corley.it - www.upcloo.com
  • 8.
    POX – PlainOld XML over HTTP example POST /PlaceOrder HTTP/1.1 Content-Type: application/xml Client application Application domain <Order> <Pizza> <Name>margherita</Name> <Type>classic</Type> </Pizza> </Order> HTTP/1.1 200 OK <OrderConfirmation> <OrderID>1345</OrderID> </OrderConfirmation> @walterdalmut - www.corley.it - www.upcloo.com
  • 9.
    CRUD Webservices • CRUDwhat it means? • Create, Read, Update and Delete • Patterns for manipulating resources across the network • Extended usage of HTTP verbs • GET • POST • PUT • DELETE • Using HTTP as an application protocol instead of a transport protocol • Web is really a big framework for building distributed systems. @walterdalmut - www.corley.it - www.upcloo.com
  • 10.
    HTTP verbs inCRUD services • Get Read Operation • Used to retrive resource details • http://rest.service.tld/order/10 • Post  Create Operation • Used to create new resources • Put Update Operation • Used to update existing resources • Delete Delete Operation • Used to delete existing resources POST/PUT can be exchanged and sometimes PUT/DELETE can be excluded to enable javascript integration (PUT/DELETE not supported browser side [HTTP_X_HTTP_METHOD_OVERRIDE parameter]) @walterdalmut - www.corley.it - www.upcloo.com
  • 11.
    CRUD Summary Verb URI or Template Use POST /order Create a new order, and upon success, receive a Location header specifying the new order’s URI. GET /order/{id} Request the current state of the order specified by the URI. PUT /order/{id} Update an order at the given URI with new information, providing the full representation. DELETE /order/{id} Logically remove the order identified by the given URI. @walterdalmut - www.corley.it - www.upcloo.com
  • 12.
    Status code definition(short list) • 2xx (Positives) • 200 OK – The request has succeeded. • 201 Created – The server accept the request and it has created the resource. • 202 Accepted – The request has been accepted for processing, but the processing has not been completed. • 4xx (Client Errors) • 400 Bad Request – The request could not be understood by the server due to malformed syntax. • 401 Unauthorized – The request requires user authentication. • 403 Forbidden – The server understood the request, but is refusing to fulfill it. • 404 Not found – The server has not found anything matching the Request-URI. • 405 Method not allowed – The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. • 5xx (Server Errors) • 500 Internal Server Error – The server encountered an unexpected condition which prevented it from fulfilling the request. • 501 Not implemented – The server does not support the functionality required to fulfill the request. • 503 Service unavailable – The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. @walterdalmut - www.corley.it - www.upcloo.com
  • 13.
    RESTful module idea • Router • Wire requests to RESTful controllers • RESTful Controllers requests Router • Uses HTTP verbs to call dedicated actions • Query models in order to serve RESTful responses Models • POST Processors Controllers • Create valid messages using formats • JSON Responses POST • XML Processor • Etc. @walterdalmut - www.corley.it - www.upcloo.com
  • 14.
    Realize ZF2 tunnelingRESTful module • ZF1 provides «Zend_Rest_Server» that realize URI tunneling • We can realize the same thing in 2 minutes thanks to ZF2 flexibility. • We need to configure • Router • Events • A simple example here: • https://github.com/wdalmut/ZF2-Tunneling-Restful-Module-Skeleton @walterdalmut - www.corley.it - www.upcloo.com
  • 15.
    ZF2 URI Tunneling- Configuration <?php return array( We have created a simple base route «/tunnel» 'controllers' => array( 'invokables' => array( and a dynamic rule that select a «model» and an 'index' => 'TunnelingRestController', ) attached «action» ), 'router' => array( 'routes' => array( 'tunneling' => array( In simple words 'type' => 'ZendMvcRouterHttpSegment', 'options' => array( • http://my-app.local/tunnel/menu/get?id=1 'route' => '/tunnel', 'defaults' => array( • «menu» 'controller' => 'index', 'action' => 'index' • The model «TunnelingModelMenu» ), ), • «get» 'may_terminate' => true, 'child_routes' => array( • The model action «get()» 'default' => array( 'type' => 'ZendMvcRouterHttpSegment', • «id=1> 'options' => array( 'route' => '[/:model/:action]', • The action parameters «get(1)» 'constraints' => array( 'controller' => 'index', 'model' => '[a-zA-Z][a-zA-Z0-9_]*', 'action' => '[a-zA-Z][a-zA-Z0-9_]*' ), ), ), ), ), ), ) ); @walterdalmut - www.corley.it - www.upcloo.com
  • 16.
    ZF2 URI Tunneling- Controller <?php namespace TunnelingRest; The base «AbstractController» is very flexible Use … and enable us to use the «dispatch» action to class Controller extends AbstractController realize what we need in few lines. { public function onDispatch(MvcEvent $e) { $routeMatch = $e->getRouteMatch(); In practice we allocate the model and call the $params = $routeMatch->getParams(); $vars = get_object_vars($e->getRequest()->getQuery()); requested action. The return variable is used as $filter = new ZendFilterFilterChain(); response. $filter->attach(new ZendFilterWordDashToCamelCase()); $filter->attach(new ZendFilterCallback("lcfirst")); $action = $filter->filter($params["action"]); $filter->attach(new ZendFilterCallback("ucfirst")); In case of missing model or missing action an $model = $filter->filter($params["model"]); «InvalidArgumentException» is thrown. $classname = "TunnelingModel{$model}"; if (class_exists($classname)) { $clazz = new $classname; if (property_exists($clazz, $action)) { $ret = call_user_func_array(array($clazz, $action), $vars); $e->setResult($ret); return; } else { throw new InvalidArgumentException("Method "{$action}" doesn't exists'"); } } else { throw new InvalidArgumentException("Class "{$classname}" doesn't exists'"); } } } @walterdalmut - www.corley.it - www.upcloo.com
  • 17.
    ZF2 URI Tunneling– Model example <?php namespace TunnelingModel; As you can see, the «model» is a simple class definition. class Menu { public function get($id) { • /tunnel/menu/get?id=1 return array("id" => $id); } • /tunnel/menu/add?x=pizza&y=4 public function add($name, $value) { Very simple implementation return array("name" => $name, "value" => $value); } } @walterdalmut - www.corley.it - www.upcloo.com
  • 18.
    ZF2 URI Tunneling– JSON responses <?php namespace Tunneling; Thanks to events we can wire controller output use ZendMvcMvcEvent; to a post processor that converts responses in class Module json messages. { public function onBootstrap($e) { /** @var ZendModuleManagerModuleManager $moduleManager */ • Attach a «postProcess» action and create a $moduleManager = $e->getApplication()->getServiceManager()->get('modulemanager'); /** @var ZendEventManagerSharedEventManager $sharedEvents */ json message. $sharedEvents = $moduleManager->getEventManager()->getSharedManager(); $sharedEvents->attach( 'ZendMvcControllerAbstractController', MvcEvent::EVENT_DISPATCH, array($this, 'postProcess'), -100 ); } //… public function postProcess(MvcEvent $e) { $routeMatch = $e->getRouteMatch(); if (strpos($routeMatch->getMatchedRouteName(), "tunneling") !== false) { $e->getResponse()->setContent(json_encode($e->getResult()->getVariables())); return $e->getResponse(); } } } @walterdalmut - www.corley.it - www.upcloo.com
  • 19.
    ZF2 RESTful CRUDmodules • ZF2 provides a base controller class that can help us to realize RESTful modules in few steps • ZendMvcControllerAbstractRestfulController • CRUD based implementation (Extended) • get($id) • delete($id) • update($id) • create($id) @walterdalmut - www.corley.it - www.upcloo.com
  • 20.
    ZF2 RESTful CRUDmodule example • Clone ZF2 Skeleton Application • Git clone https://github.com/zendframework/ZendSkeletonApplication.git my-app • Git submodule init • Git submodule update • Clone a ZF2 RESTful module • Git submodule add https://github.com/wdalmut/ZF2-Restful-Module-Skeleton.git module/Main • Add «Main» module into «configs/application.config.php» • Create you application virtual host and try it • http://my-app.local/rest/info/json [getList] • http://my-app.local/rest/info/json/1 [get] • curl –X POST –d ‘hello=world’ http://my-app.local/rest/info [create] • curl –X PUT –d ‘hello=ciao’ http://my-app.local/rest/info/1 [update] • curl –X DELETE http://my-app.local/rest/info/1 [delete] @walterdalmut - www.corley.it - www.upcloo.com
  • 21.
    RESTful Controllers <?php • RESTful Controller should extends AbstractRestfulController namespace MainController; • 5 abstract methods (CRUD + List) use ZendMvcControllerAbstractRestfulController; • getList class InfoController extends AbstractRestfulController { • GET operation without parameters public function getList() { • /rest/json/info } return array('ciao' => 'mondo'); • Get public function get($id) • READ resource with parameters (ID) { • /rest/json/info/1 } • Delete public function delete($id) { • DELETE a resource } • Update public function update($id, $data) • UPDATE a resource { • Create } • CREATE a new resource public function create($data = null) { } } @walterdalmut - www.corley.it - www.upcloo.com
  • 22.
    First of allplay with routes 'router' => array( 'routes' => array( • Create a base route /rest that enable also formatters 'restful' => array( 'type' => 'ZendMvcRouterHttpSegment', • Formatter allow us to switch easly to JSON, 'options' => array( 'route' => '/rest[/:formatter]', XML etc. 'constraints' => array( • Child routes play with controller and identifiers 'formatter' => '[a-zA-Z0-9_-]*', ), ), 'may_terminate' => true, 'child_routes' => array( 'default' => array( 'type' => 'ZendMvcRouterHttpSegment', 'options' => array( 'route' => '[/:controller[/:id]]', 'constraints' => array( 'controller' => '[a-zA-Z][a-zA-Z0-9_-]*', 'id' => '[a-zA-Z0-9_-]*' ), ), ), ), ), ), @walterdalmut - www.corley.it - www.upcloo.com
  • 23.
    Formatters • RESTful servicescan handle different type of messages • JSON • XML • Images • Etc • The high modularity of ZF2 MVC implementation enable us to add different layers of abstractions and formatters is one of this. • Client must know what kind of messages type have to handle. • Post Processors are used to render messages @walterdalmut - www.corley.it - www.upcloo.com
  • 24.
    Formatters «configs/module.config.php» 'errors' =>array( 'post_processor' => 'json-pp', • The configuration allows us to define different «post processors» 'show_exceptions' => array( 'message' => true, • Errors can be detailed more, for example traces, messages etc. 'trace' => true ) ), 'di' => array( 'instance' => array( 'alias' => array( 'json-pp' => 'MainPostProcessorJson', 'jsonp-pp' => 'MainPostProcessorJsonp', 'image-pp' => 'MainPostProcessorImage' ) ) ), @walterdalmut - www.corley.it - www.upcloo.com
  • 25.
    Wiring events (Module.php) /** * @param MvcEvent $e */ public function onBootstrap($e) • Event position -100 { /** @var ZendModuleManagerModuleManager $moduleManager */ • Handle post processors $moduleManager = $e->getApplication()->getServiceManager()->get('modulemanager'); /** @var ZendEventManagerSharedEventManager $sharedEvents */ • Event position 100 $sharedEvents = $moduleManager->getEventManager()->getSharedManager(); • Handle HTTP Method Override $sharedEvents->attach( • Event position 999 'ZendMvcControllerAbstractRestfulController', MvcEvent::EVENT_DISPATCH, • Handle errors array($this, 'postProcess'), -100 ); $sharedEvents->attach( 'MainControllerInfoController', MvcEvent::EVENT_DISPATCH, array($e->getApplication()->getServiceManager()->get('MainHttpRestful'), 'onDispatch'), 100 ); $sharedEvents->attach( 'ZendMvcApplication', MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'errorProcess'), 999 ); } @walterdalmut - www.corley.it - www.upcloo.com
  • 26.
    Attach Post Processorto Actions public function postProcess(MvcEvent $e) { $routeMatch = $e->getRouteMatch(); $formatter = $routeMatch->getParam('formatter', false); $di = $e->getTarget()->getServiceLocator()->get('di'); if ($formatter !== false) { if ($e->getResult() instanceof ZendViewModelViewModel) { if (($e->getResult()->getVariables())) { $vars = $e->getResult()->getVariables(); } else { $vars = null; } } else { $vars = $e->getResult(); } $postProcessor = $di->get($formatter . '-pp', array( 'request' => $e->getRequest(), 'response' => $e->getResponse(), 'vars' => $vars, )); $postProcessor->process(); return $postProcessor->getResponse(); } return null; } @walterdalmut - www.corley.it - www.upcloo.com
  • 27.
    Example of JSONPost Processor <?php <?php namespace MainPostProcessor; namespace MainPostProcessor; /** abstract class AbstractPostProcessor * { */ protected $_vars = null; class Json extends AbstractPostProcessor private $_request = null; { private $_response = null; public function process() { public function __construct $result = json_encode($this->_vars); (ZendHttpRequest $request, ZendHttpResponse $response, $vars = null) { $headers = $this->getResponse()->getHeaders(); $this->_vars = $vars; $headers->addHeaderLine('Content-Type', 'application/json'); $this->_response = $response; $this->_request = $request; $this->getResponse()->setHeaders($headers); } $this->getResponse()->setContent($result); } public function getResponse() } { return $this->_response; } public function getRequest() { return $this->_request; } abstract public function process(); } @walterdalmut - www.corley.it - www.upcloo.com
  • 28.
    ZF2 RESTful Modules Thanks for listening… Any questions? @walterdalmut - www.corley.it - www.upcloo.com

Editor's Notes

  • #2 Ringrazione l’organizzazione dello ZFDAY, gli sponsor e tutte le persone presenti.
  • #4 Abbiamo solo 30 minuti quindi fare un veloce escursus sui service RESTful e vedremo come realizzare due moduli ZF2.Un primo molto semplice, ispirato a Zend_Rest_Server di ZF1 Un secondo utilizzando un componente integrato nella libreria ZF2
  • #5 Il termite REST è stato coniato nel 2000 da Roy Fielding, uno degli autori del protocollo HTTP, per descrivere un sistema che permette di descrivere ed identificare le risorse web.