【问题标题】:Phalcon / REST to existing projectPhalcon / REST 到现有项目
【发布时间】:2015-03-16 13:47:32
【问题描述】:

我正在开发一个具有以下目录结构的 phalcon Web 应用程序:

  /app/
        /cache/
            ...
        /config/
            config.php
            loader.php
            services.php
        /controllers/
            contorllerBase.php
            ...
        /models/
            ...
        /views/
            ...
    /public/
        /css/
        /img/
        /js/
        .htacces
        index.php
        webtools.config.php
        webtools.php
    index.html

我用 phalcon devtools 创建了这个项目,到目前为止它工作正常,但现在我必须为这个项目实现一个 REST 功能。 我的问题是:

  • 在这个结构中我在哪里创建 REST 逻辑?
  • 推荐的实现 REST 的方法是什么? 因为我想要访问视图并且我也需要休息(即:http://localhost/api/..。)

我在互联网上找到了一些解决方案,但它们让我感到困惑,因为它们大多是实现一个没有视图的 REST api。

config.php

return new \Phalcon\Config(array(
    'database' => array(
...
    ),
    'application' => array(
        'controllersDir' => __DIR__ . '/../../app/controllers/',
        'modelsDir' => __DIR__ . '/../../app/models/',
        'viewsDir' => __DIR__ . '/../../app/views/',
        'pluginsDir' => __DIR__ . '/../../app/plugins/',
        'libraryDir' => __DIR__ . '/../../app/library/',
        'cacheDir' => __DIR__ . '/../../app/cache/',
        'logsDir' => __DIR__ . '/../../app/logs',
        'baseUri' => '/',
    )
        ));

loader.php

<?php

$loader = new \Phalcon\Loader();

/**
 * We're a registering a set of directories taken from the configuration file
 */
$loader->registerDirs(
    array(
        $config->application->controllersDir,
        $config->application->modelsDir
    )
)->register();

services.php

<?php

use Phalcon\DI\FactoryDefault;
use Phalcon\Mvc\View;
use Phalcon\Mvc\Url as UrlResolver;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
use Phalcon\Mvc\View\Engine\Volt as VoltEngine;
use Phalcon\Mvc\Model\Metadata\Memory as MetaDataAdapter;
use Phalcon\Session\Adapter\Files as SessionAdapter;

/**
 * The FactoryDefault Dependency Injector automatically register the right services providing a full stack framework
 */
$di = new FactoryDefault();

/**
 * The URL component is used to generate all kind of urls in the application
 */
$di->set('url', function () use ($config) {
    $url = new UrlResolver();
    $url->setBaseUri($config->application->baseUri);

    return $url;
}, true);

/**
 * Setting up the view component
 */
$di->set('view', function () use ($config) {

    $view = new View();

    $view->setViewsDir($config->application->viewsDir);

    $view->registerEngines(array(
        '.volt' => function ($view, $di) use ($config) {

            $volt = new VoltEngine($view, $di);

            $volt->setOptions(array(
                'compiledPath' => $config->application->cacheDir,
                'compiledSeparator' => '_'
            ));

            return $volt;
        },
                '.phtml' => 'Phalcon\Mvc\View\Engine\Php'
            ));

            return $view;
        }, true);

        /**
         * Database connection is created based in the parameters defined in the configuration file
         */
        $di->set('db', function () use ($config) {
            return new DbAdapter(array(
                'host' => $config->database->host,
                'username' => $config->database->username,
                'password' => $config->database->password,
                'dbname' => $config->database->dbname,
                "charset" => $config->database->charset
            ));
        });

        /**
         * If the configuration specify the use of metadata adapter use it or use memory otherwise
         */
        $di->set('modelsMetadata', function () {
            return new MetaDataAdapter();
        });

        /**
         * Start the session the first time some component request the session service
         */
        $di->set('session', function () {
            $session = new SessionAdapter();
            $session->start();

            return $session;
        }); 

index.php

<?php
error_reporting(E_ALL);

$debug = new \Phalcon\Debug();
$debug->listen();

try {
    /**
     * Read the configuration
     */
    $config = include __DIR__ . "/../app/config/config.php";

    /**
     * Read auto-loader
     */
    include __DIR__ . "/../app/config/loader.php";

    /**
     * Read services
     */
    include __DIR__ . "/../app/config/services.php";

    /**
     * Handle the request
     */
    $application = new \Phalcon\Mvc\Application($di);

    echo $application->handle()->getContent();
} catch (\Exception $e) {
    echo $e->getMessage();
}

我真的很感激任何形式的帮助。

【问题讨论】:

  • 我想我会建议添加单独的 module 以提供 REST 功能。但不要等待答案,也许有人有更好的主意。

标签: php rest phalcon


【解决方案1】:

我用过:

路由

在路由文件中(非 API 部分的路由)

include __DIR__ . '/routes_api.php';
$router->mount($api);

在这个 routes_api 中,我创建了一个组并为这个组定义了一个控制器命名空间

$api = new \Phalcon\Mvc\Router\Group(array(
    'namespace' => '\X\Controllers\API',
));

// --- Base API URL prefix
$api->setPrefix('/api');

路由像往常一样定义,采用 REST 服务的风格,例如:

$api->addGet('/addresses', array('controller' => 'addresses', 'action' => 'listMe'));

控制器:

我在控制器下创建了一个文件夹 api,类位于命名空间中,作为组中定义的类(命名空间 X\Controllers\API),具有一个实现一些 REST 礼貌方法的类库所有 REST 控制器:

class AddressesController extends \X\ApiControllerBase

控制器基础:

class ApiControllerBase extends \Phalcon\Mvc\Controller

为所有 REST 提供 JSON 样式响应的自定义实现

public function initialize()
{
   $this->response = new \X\ApiResponse();
}

通过 OAuth 服务器为 REST 部分提供授权网关,并对入站查询字符串进行一些采集/过滤/清理,以用于分页和其他实用程序,这些实用程序可用于我已覆盖的所有 REST 控制器:

public function beforeExecuteRoute($dispatcher)

在控制器操作中,我使用一种方法返回响应,该方法从我的自定义响应实现中的分页器获取数据(跟随者):

$this->response->setResponse($paginator);
return $this->response;

那么对于输出样式:

class ApiResponse extends \Phalcon\Http\Response
{
    public function __construct($content=null, $code=null, $status=null)
    {
        parent::__construct($content, $code, $status);
        $this->setHeader('Content-Type', 'application/json');
    }

    public function setResponse($response, $limit = null, $processitems = null)
    {
        // .... some manipulations of data from controllers ... building of arrays ....
        $this->setContent(json_encode(array('error' => false) + $response));
    }

    public function setResponseError($description, $error = true) {
        //Set status code
        $this->setStatusCode(200, 'OK');
        $this->setContent(json_encode(array('error' => $error, 'error_description' => $description)));
    }
}

需要一个控制器来管理对 /api 的请求而不需要任何休息操作,默认情况下它应该以路由命名,所以它应该是 ApiController,你可以调整路由系统以便更改或引发错误 (http://docs.phalconphp.com/en/latest/reference/dispatching.html#inject-model-instances)

服务:

最后,为了管理几种错误(也抛出异常),输出为 JSON {error: true, message: "...."},我在 index.php 中实现了一个 beforeException调度器事件:

$di->setShared('dispatcher', function() {
    $eventsManager = new Phalcon\Events\Manager();

    $eventsManager->attach("dispatch", function($event, $dispatcher, $exception) {
        /* @var $dispatcher Phalcon\Mvc\Dispatcher */
        if ($event->getType() == 'beforeException') {
            $ctrl = $dispatcher->getActiveController();

           if($ctrl instanceof \X\ApiControllerBase) {
                $dispatcher->forward(array(
                    'namespace' => '\\',
                    'controller' => 'error',
                    'action' => 'api',
                    'params' => array('message' => $exception->getMessage())
                ));
                return false;
            }

    $dispatcher = new Phalcon\Mvc\Dispatcher();
    //Bind the EventsManager to the Dispatcher
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
);

然后是错误控制器,由调度程序使用转发方法调用(在这种情况下没有命名空间,它位于控制器文件夹内):

class ErrorController extends \Phalcon\Mvc\Controller {

    public function route404Action() {
        $this->response->setStatusCode(404 , 'Not Found');
    }

    public function apiAction() {
        $pars = $this->dispatcher->getParams();
        $this->response = new \X\ApiResponse();
        $this->response->setResponseError($pars['message']);
        return $this->response;
    }

}

希望对你有帮助:)

【讨论】:

  • 感谢您的评论,它看起来对我很好。但是当我试图重现你的代码时,遇到了写Test\Controllers\ApiController handler class cannot be loaded的错误。到目前为止,我在控制器内创建了 api 文件夹。在这个目录中,我创建了 AdressesController.phpApiControllerBase.phpApiResponse.php 和 namspace Test\Controllers\API,之后我创建了 routes_api.php 并将其添加到 services.php
  • this: $di-&gt;set('dispatcher', function() { $dispatcher = new \Phalcon\Mvc\Dispatcher(); $dispatcher-&gt;setDefaultNamespace('Test\Controllers'); return $dispatcher; }); $router = new \Phalcon\Mvc\Router(); include __DIR__ . '/routes_api.php'; $router-&gt;mount($api); 我认为 routes_api.php 有问题。 &lt;?php $api = new \Phalcon\Mvc\Router\Group(array( 'namespace' =&gt; 'Test\Controllers\API', )); // --- Base API URL prefix $api-&gt;setPrefix('/api'); $api-&gt;addGet('/addresses', array('controller' =&gt; 'addresses', 'action' =&gt; 'listMe'));
  • 如果您的意思是按原样使用我的代码,请在 beforeException 中删除部分: if($ctrl instanceof \ApiController) { $dispatcher->forward(array ( 'namespace' => '\\', 'controller' => 'error', 'action' => 'api', 'params' => array('message' => 'API 函数未找到或调用方法未找到支持的') ));返回假; } 这是一个错字
  • 编辑了没有错字的答案并添加了错误控制器。
  • 我把我的项目上传到了github,因为这里写的有点难。 github.com/eszikk/phalcon如果你看一下我会很高兴的。
猜你喜欢
  • 1970-01-01
  • 2013-04-22
  • 2021-06-19
  • 2015-04-10
  • 1970-01-01
  • 2017-12-08
  • 2020-12-22
  • 2016-02-21
  • 2023-03-15
相关资源
最近更新 更多