Zend Framework - Как создать API, доступный как извне, так и изнутри?

Я ищу создать веб-сайт и буду создавать мобильное приложение позднее.

Я хочу иметь возможность предлагать одинаковый уровень данных (например, список книг) как на веб-сайте, так и в приложении. Я бы хотел использовать API для этого, но я изо всех сил пытаюсь найти какие-либо примеры или приличные статьи в Интернете.

Итак, я полагаю, что мой вопрос заключается в том, чтобы создать конечную точку JSON, доступную для мобильного приложения через HTTP (например, http://www.mysite.com/api/v1.0/json) как получить доступ к одной и той же функциональности из моего приложения Zend?

(очевидно, я не хочу дублировать шаги модели "взаимодействие с базой данных" )

Ответ 1

Поскольку Zend действительно не RESTful, к сожалению, ваш лучший выбор - JSON-Rpc.

Вы можете сделать это в контроллере, или вы можете просто сделать ajax.php в дополнение к index.php, чтобы уменьшить накладные расходы, как этот парень сделал здесь

В принципе, все, что вам нужно сделать, это следующее:

$server = new Zend_Json_Server();
$server->setClass('My_Class_With_Public_Methods');
// I've found that a lot of clients only support 2.0
$server->getRequest()->setVersion("2.0");
if ('GET' == $_SERVER['REQUEST_METHOD']) {
    // Indicate the URL endpoint, and the JSON-RPC version used:
    $server->setTarget('/ajax.php')
           ->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);

    // Grab the SMD
    $smd = $server->getServiceMap();

    // Return the SMD to the client
    header('Content-Type: application/json');
    echo $smd;
    return;
}

$server->handle();

то где-то в вашем макете:

$server = new Zend_Json_Server();
$server->setClass('My_Class_With_Public_Methods');
$smd = $server->getServiceMap();
?>
<script>
$(document).ready(function() {
    rpc = jQuery.Zend.jsonrpc({
        url : <?=json_encode($this->baseUrl('/ajax'))?>
        , smd : <?=$smd?>
        , async : true
    });
});
</script>

для примера, здесь этот класс:

class My_Class_With_Public_Methods {
    /**
      * Be sure to properly phpdoc your methods,
      * the rpc clients like it when you do
      * 
      * @param float $param1
      * @param float $param2
      * @return float
      */
    public function someMethodInThatClass ($param1, $param2) {
        return $param1 + $param2;
    }
}

тогда вы можете просто вызвать такие методы в javascript:

rpc.someMethodInThatClass(first_param, second_param, {
    // if async = true when you setup rpc,
    // then the last param is an object w/ callbacks
    'success' : function(data) {

    }
    'error' : function(data) {

    }
});

В Android/iPhone не так много известных библиотек JSON-rpc, но я обнаружил, что это работает с Zend_Json_Server для Android:

http://software.dzhuvinov.com/json-rpc-2.0-base.html

и это работает для iPhone:

http://www.dizzey.com/development/ios/calling-json-rpc-webservice-in-ios/

Отсюда очевидно, что вы можете использовать My_Class_With_Public_Methods так же, как это делает javascript/ваше мобильное приложение.

Ответ 2

С моей точки зрения, это скорее вопрос, связанный с архитектурой, чем вопрос Zend Framework.

То, что вы ищете, это сервис-ориентированная архитектура (SOA).

Посылка SOA проста, создайте единый API, и все проходит через это, будь то внутри или снаружи. Популярным сторонником SOA является Amazon.

На практике это означает, что вы раскрываете свой API точно так же, как и внутренне используете его. В ООП это означает, что всякий раз, когда вы вызываете свой API из внешнего источника (например: REST API), вы укажете имя класса, имя метода и список аргументов, и вы получите объект в ответ, так же, как если бы вы назовете его внутренне.

Например, у вас есть:

class HelloInstance {
    public $hello;
    public function __construct($hello) { $this->hello = $hello; }
}

class Hello {
    public function getHello() { return new HelloInstance('world'); }
}

class FooInstance {
    public $foo;
    public function __construct($foo) { $this->foo = $foo; }
}

class Foo {
    public function getFoo($value) { return new FooInstance($value); }
}

Если вы хотите использовать их внутренне, выполните следующие действия:

$hello = new Hello;
$helloInst = $hello->getHello();

$foo = new Foo;
$fooInst = $foo->getFoo('bar');

Теперь вам просто нужен шлюз, чтобы выставлять этот API извне. Вот очень простой пример:

include_once 'my_classes.php';

$class = $_GET['class'];
$method = $_GET['method'];

$obj = new $class;
$return = $obj->$method(isset($_GET['value']) ? $_GET['value'] : null);

header('Content-Type: application/json');
echo json_encode($return);

Вы можете выполнить те же два вызова, которые я продемонстрировал ранее, и получить те же результаты, используя вызов REST:

http://my_server/my_gateway.php?class=Hello&method=getHello
http://my_server/my_gateway.php?class=Foo&method=getFoo&value=bar