Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 28-05-2013 18:50:27

GueloSuperStar
Membre
Lieu: Paris
Date d'inscription: 05-08-2009
Messages: 107

[ZF 1.12.1] Structure pour une api REST

Bonjour,

Je voudrais développer une api de plusieurs services avec la méthode REST mais je ne sais pas vraiment qu'elle est la bonne architecture pour qu'elle soit fiable, robuste et modulable.

J'ai voulu me basé sur cette façon de faire https://github.com/codeinchaos/restful-zend-framework mais je ne sais pas si elle est toujours d'actualité  et surtout si elle est correcte.

J'ai vais essayé de vous expliquer ma façon de faire  et si ça peut aider d'autre ZENDER'S smile

- application/boostrap

Code:

[lang=php]
protected function _initRoutes(){
    $frontController = Zend_Controller_Front::getInstance();
    $routeur = $frontController->getRouter();
    //Add the REST route for the WEBSERVICES module only
    $restRoute = new Zend_Rest_Route($frontController,array(),array('webservices'));
    $routeur->addRoute('rest',$restRoute);
}

- Création d'un module application/modules/webservices

- application/modules/webservices/bootstrap

Code:

[lang=php]
class Webservices_Bootstrap extends Zend_Application_Module_Bootstrap{
    public function _initAutoload(){
        $autoloader = new Zend_Application_Module_Autoloader(array('namespace'=>'Webservices_','basePath'=>APPLICATION_PATH.'/modules/webservices'));
        return $autoloader;
    }
}

- application/modules/webservices/models/Webservices1.php

Code:

[lang=php]
class Webservices_Model_Webservices1{
    /**
     * Add method
     *
     * @return String
     */
    public function test() {
        return 'test method called';
    }
}

- application/modules/webservices/controllers/RestController.php

Code:

[lang=php]
class Webservices_RestController extends Zend_Rest_Controller{
    public function init(){
        $this->_helper->layout->disableLayout();
        $contextSwitch = $this->_helper->getHelper('contextSwitch');
        $contextSwitch->setContext('html',array('suffix'=>'','headers'=>array('Content-Type'=>'text/html;Charset=UTF-8'),'callbacks'=>array()));
        if(!$contextSwitch->hasContext($this->_getparam('format',''))) $this->_request->setParam('format','xml');
        $contextSwitch->addActionContext($this->getRequest()->getActionName(),array('html','json','xml'));
        $contextSwitch->setDefaultContext('xml');
        $contextSwitch->setAutoDisableLayout(true);
        $contextSwitch->setAutoJsonSerialization(false);
        $contextSwitch->initContext();
        $this->_ws = new Webservices_Model_Webservices1();
    }

    public function headAction(){}

    public function indexAction(){$this->_forward('get');}

    public function getAction(){
        $this->getResponse()->setHttpResponseCode(200);
        $resource = strtolower($this->_getParam('resource',''));
        $existResource = false;
        switch(true){
            case ($existResource=strstr($resource, 'questions')):
                $this->_forward('questions');
                break;
            case ($existResource=strstr($resource,'responses')):
                $this->_forward('responses');
                break;
        }
        if(!$existResource){
            $this->getResponse()->setHttpResponseCode(400);
            $this->view->succes = 'false';
            $this->view->error = 'requested resource not found';
            $this->view->method = $resource;
        }
    }

    public function responsesAction(){
        $this->view->succes = 'true';
        $this->view->method = 'responses';
        $result = $this->_ws->test();
        $this->view->result = array('result'=>$result);
    }

    public function questionsAction(){
        $this->getResponse()->setHttpResponseCode(200);
        $this->view->succes = 'true';
        $this->view->method = 'question';
        $this->view->result = array();
    }

    public function postAction(){
        $this->denied();
    }

    public function putAction(){
        $this->denied();
    }

    public function deleteAction(){
        $this->denied();
    }

    public function denied(){
        $this->getResponse()->setHttpResponseCode(403);
        $this->view->succes = 'false';
        $this->view->error = 'Acces denied';
    }
}

- application/modules/webservices/views/scripts/rest/get.json.phtml & response.json.phtml

Code:

[lang=php]
$result = array('succes'=>$this->succes,'method'=>$this->method,'result'=>$this->result,'error'=>$this->error);
echo Zend_Json::encode($result);

- application/modules/webservices/views/scripts/rest/get.xml.phtml & response.xml.phtml

Code:

[lang=php]
$serializer = new App_Serializer_Adapter_Xml();
$result = array('succes'=>$this->succes,'method'=>$this->method,'result'=>$this->result,'error'=>$this->error);
echo$serializer->serialize($result);

- application/modules/webservices/views/scripts/rest/get.phtml & response.phtml

Code:

[lang=php]
Zend_Debug::dump($this->succes);
Zend_Debug::dump($this->method);
Zend_Debug::dump($this->result);
Zend_Debug::dump($this->error);

- library/MyApp/Serialiser/Adapter/Xml.php

Code:

[lang=php]
<?php
class App_Serializer_Adapter_Xml extends Zend_Serializer_Adapter_AdapterAbstract
{
    /**
     * @var array Default options
     */
    protected $_options = array(
            'rootNode' => 'response',
    );

    /**
     * Serialize PHP value to XML
     *
     * @param  mixed $value
     * @param  array $opts
     * @return string
     * @throws Zend_Serializer_Exception on XML encoding exception
     */
    public function serialize($value, array $opts = array())
    {
        $opts = $opts + $this->_options;

        try {
            $dom = new DOMDocument('1.0','utf-8');
            $root = $dom->appendChild($dom->createElement($opts['rootNode']));
            $this->createNodes($dom, $value, $root, false);
            return $dom->saveXml();
        } catch (Exception $e) {
            require_once 'Zend/Serializer/Exception.php';
            throw new Zend_Serializer_Exception('Serialization failed', 0, $e);
        }
    }

    /**
     * Deserialize XML to PHP value
     *
     * @param  string $json
     * @param  array $opts
     * @return mixed
     */
    public function unserialize($xml, array $opts = array())
    {
        try {
            $json = Zend_Json::fromXml($xml);
            return (array) Zend_Json::decode($json, Zend_Json::TYPE_OBJECT);
        } catch (Exception $e) {
            require_once 'Zend/Serializer/Exception.php';
            throw new Zend_Serializer_Exception('Unserialization failed by previous error', 0, $e);
        }
    }

    private function createNodes($dom, $data, &$parent)
    {
        switch (gettype($data)) {
            case 'string':
            case 'integer':
            case 'double':
                $parent->appendChild($dom->createTextNode($data));
                break;

            case 'boolean':
                switch ($data) {
                    case true:
                        $value = 'true';
                        break;

                    case false:
                        $value = 'false';
                        break;
                }

                $parent->appendChild($dom->createTextNode($value));
                break;

            case 'object':
            case 'array':
                foreach ($data as $key => $value) {

                    if (is_object($value) and $value instanceOf DOMDocument and !empty($value->firstChild)) {
                        $node = $dom->importNode($value->firstChild, true);
                        $parent->appendChild($node);
                    } else {
                        $attributes = null;

                        // SimpleXMLElements can contain key with @attribute as the key name
                        // which indicates an associated array that should be applied to the xml element

                        if (is_object($value) and $value instanceOf SimpleXMLElement) {
                            $attributes = $value->attributes();
                            $value = (array) $value;
                        }

                        // don't emit @attribute as an element of it's own
                        if ($key[0] !== '@')
                        {
                            if (gettype($value) == 'array' and !is_numeric($key)) {
                                $child = $parent->appendChild($dom->createElement($key));

                                if ($attributes)
                                {
                                    foreach ($attributes as $attrKey => $attrValue)
                                    {
                                        $child->setAttribute($attrKey, $attrValue);
                                    }
                                }

                                $this->createNodes($dom, $value, $child);
                            } else {

                                if (is_numeric($key)) {
                                    $key = sprintf('%s', $this->depluralize($parent->tagName));
                                }

                                $child = $parent->appendChild($dom->createElement($key));

                                if ($attributes)
                                {
                                    foreach ($attributes as $attrKey => $attrValue)
                                    {
                                        $child->setAttribute($attrKey, $attrValue);
                                    }
                                }

                                $this->createNodes($dom, $value, $child);
                            }
                        }
                    }
                }

                break;
        }
    }

    private function depluralize($word) {
        $rules = array(
                'ss' => false,
                'os' => 'o',
                'ies' => 'y',
                'xes' => 'x',
                'oes' => 'o',
                'ies' => 'y',
                'ves' => 'f',
                's' => null
        );

        // Loop through all the rules
        foreach(array_keys($rules) as $key) {
            // If the end of the word doesn't match the key, it's not a candidate for replacement.
            if (substr($word, (strlen($key) * -1)) != $key) {
                continue;
            }

            // If the value of the key is false, stop looping  and return the original version of the word.
            if ($key === false) {
                return $word;
            }

            // apply the rule
            return substr($word, 0, strlen($word) - strlen($key)) . $rules[$key];
        }
        return $word;
    }
}

- URLS pour appeler le websrvice (testé en ligne de commande) :

- curl http://localhost/webservices/rest/resource/responses
- curl http://localhost/webservices/rest/resource/responses/format/xml
- curl http://localhost/webservices/rest/resource/responses/format/json
- curl http://localhost/webservices/rest/resource/responses/format/html
- curl http://localhost/webservices/rest/resource/questions
...

Tout aide, exemple de web services avec rest et amélioration de ma méthode est la bienvenue

Merci pour vos retour les Zender's wink

Dernière modification par GueloSuperStar (28-05-2013 19:01:54)


A+ Guelo Super Star

Hors ligne

 

#2 04-01-2015 12:46:29

zd_flo
Nouveau membre
Lieu: Paris
Date d'inscription: 04-01-2015
Messages: 3
Site web

Re: [ZF 1.12.1] Structure pour une api REST

Je t'aiderai bien mais j'ai pas encore le niveau >< ! Dès que j'aurai pris du skill je reviens sur ton post donner un avis constructif smile

Hors ligne

 

#3 04-01-2015 18:25:56

tdutrion
Administrateur
Lieu: Dijon, Paris, Edinburgh
Date d'inscription: 23-12-2009
Messages: 613
Site web

Re: [ZF 1.12.1] Structure pour une api REST

Le post est un peu vieux zd_flo, j'espère pour GueloSuperStar qu'il s'est débloqué depuis le temps...

Quite à déterrer, autant répondre à la question à l'aide des outils d'aujourd'hui : tu peux utiliser Apigility pour construire une api rest avec un projet ZF1.

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages