blast/turbine

此包已被废弃,不再维护。作者建议使用 hawkbit/hawkbit 包。

PSR-7 微型 PHP 框架

2.3.2 2017-05-07 15:41 UTC

README

Latest Version on Packagist Software License Build Status Total Downloads Coverage Status

Hawkbit\Application 微型框架是一个高度可定制的、事件驱动的框架,兼容 PSR-7StackPHPZend Stratigility

Hawkbit\Application 使用最新的 League\Route 进行路由,League\Container 进行依赖注入,League\Event 进行事件分发,Zend Config 进行配置。

Hawkbit\Application 是 Proton 的一个高级衍生产品,也是 Marco Bunge 的 Hawkbit 应用组件集合的一部分。Hawkbit 应用 1.x 也被称为 Blast Hawkbit 应用。

快速入门

请参阅 public/ 以获取示例用法并阅读文档。

集成

Hawkbit 应用也提供可选的包

动机

我的愿景是提供一个能够以相同方式处理 HTTP 和 CLI 的微型框架。开发者应该能够重用它代码,根据他的需求设计业务层。Hawkbit 应该是一个辅助工具而不是预定义的框架。是的,它正在积极开发中。

我喜欢 PSR、phpleague 和最小化依赖集,并想创建一个使用最佳包的微型框架,并将其捆绑在美观的应用程序层中。我也喜欢基于组件的开发风格。

Hawkbit 是基于 phpleague 包构建的,并考虑了 PSR。Hawkbit 的设计是为了与您的代码共存而不是替换代码库。Hawkbit 的依赖性很小。最后但并非最不重要的是,Hawkbit 不强迫开发者如何设计应用程序的业务逻辑,因为我们更喜欢使用 POPO(Plain Old PHP Objects)作为控制器/命令(业务逻辑的访问器)。

目前我设计和开发所有的 Hawkbit 包,并管理整个代码库。我会很感激得到支持,甚至更好的是:贡献者!

有关详细信息,请参阅 Issue #33

特别感谢

感谢提交 PR、识别 Bus 或任何其他改进!

安装

使用 Composer

Hawkbit\Application可在Packagist上找到,并可以使用Composer进行安装。可以通过运行以下命令或更新您的composer.json文件来实现。

composer require hawkbit/hawkbit

composer.json

{
    "require": {
        "hawkbit/hawkbit": "~2.0"
    }
}

请确保将您的Composer自动加载文件也包含在您的项目中。

<?php

require __DIR__ . '/vendor/autoload.php';

下载.zip文件

此项目也可以在GitHub上作为.zip文件下载。访问发布页面,选择您想要的版本,然后点击“源代码(zip)”下载按钮。

要求

此版本支持以下版本的PHP。

  • PHP 5.5
  • PHP 5.6
  • PHP 7.0
  • PHP 7.1
  • HHVM

设置

创建新应用

<?php

require __DIR__.'/../vendor/autoload.php';

$app = new \Hawkbit\Application();

带配置创建新应用

<?php

$config = [
    'key' => 'value'
];
$app = new \Hawkbit\Application($config);

添加路由

<?php

/** @var Hawkbit\Application $app */
$app->get('/', function ($request, $response) {
    $response->getBody()->write('<h1>It works!</h1>');
    return $response;
});

$app->get('/hello/{name}', function ($request, $response, $args) {
    $response->getBody()->write(
        sprintf('<h1>Hello, %s!</h1>', $args['name'])
    );
    return $response;
});

运行应用

<?php

$app->run();

参见我们的示例/public/index.php

配置

向应用添加额外配置

Hawkbit\Application配置由zend-config管理。

<?php

//add many values
$app->setConfig([
    'database' => [
        'default' => 'mysql://root:root@localhost/acmedb',
    ],
    'services' => [
        'Acme\Services\ViewProvider',
    ]
]);

//add a single value
$app->setConfig('baseurl', 'localhost/');

$app->getConfig()->baseurl = 'localhost/';
$app->getConfig()['baseurl'] = 'localhost/';

访问配置

<?php

//access all configuration
$app->getConfig();

//get configuration item
$default = $app->getConfig('database')->default; // returns 'mysql://root:root@localhost/acmedb
$default = $app->getConfig()->database->default; // returns 'mysql://root:root@localhost/acmedb
$default = $app->getConfig('database')['default']; // returns 'mysql://root:root@localhost/acmedb
$default = $app->getConfig()['database']['default']; // returns 'mysql://root:root@localhost/acmedb

中间件

Hawkbit\Application中间件允许对生命周期执行进行高级控制。

<?php

$app->addMiddleware(new Acme\SomeMiddleware);

Hawkbit\Application使用它自己的运行器Hawkbit\Application\MiddlewareRunner

路由

Hawkbit\Application使用league/route的路由集成,并允许直接访问路由集合方法。

匿名函数的基本使用

<?php
// index.php

$app->get('/', function ($request, $response) {
    $response->getBody()->write('<h1>It works!</h1>');
    return $response;
});

$app->get('/hello/{name}', function ($request, $response, $args) {
    $response->getBody()->write(
        sprintf('<h1>Hello, %s!</h1>', $args['name'])
    );
    return $response;
});

$app->run();

从匿名函数访问应用

Hawkbit\Application允许通过闭包绑定从匿名函数访问自身。

<?php

$app->get('/hello/{name}', function ($request, $response, $args) {
    
    // access Hawkbit\Application
    $app = $this;
    
    $response->getBody()->write(
        sprintf('<h1>Hello, %s!</h1>', $args['name'])
    );
    return $response;
});

控制器的基本使用

<?php

require __DIR__.'/../vendor/autoload.php';

$app = new Hawkbit\Application();

$app->get('/', 'HomeController::index'); // calls index method on HomeController class

$app->run();
<?php

// HomeController.php

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;

class HomeController
{
    public function index(ServerRequestInterface $request, ResponseInterface $response, array $args)
    {
        $response->getBody()->write('<h1>It works!</h1>');
        return $response;
    }
}

控制器的自动构造函数注入

<?php

// index.php

require __DIR__.'/../vendor/autoload.php';

$app = new Hawkbit\Application();

$app->getContainer()->add('CustomService', new CustomService);
$app->get('/', 'HomeController::index'); // calls index method on HomeController class

$app->run();

请使用Service Providers中的boot方法以正确注入服务到控制器!

<?php

// HomeController.php

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;

class HomeController
{
    /**
     * @var CustomService
     */
    private $service;

    /**
     * @param CustomService $application
     */
    public function __construct(CustomService $service = null)
    {
        $this->service = $service;
    }

    /**
     * @return CustomService
     */
    public function getService()
    {
        return $this->service;
    }
    
    public function index(ServerRequestInterface $request, ResponseInterface $response, array $args)
    {
        //do somehing with service
        $service = $this->getService();
        return $response;
    }
}

有关路由的更多信息,请阅读此指南

路由组

Hawkbit\Application支持路由组。

<?php

$app->group('/admin', function (\League\Route\RouteGroup $route) {

    //access app container (or any other method!)
    $app = $this;
    
    $route->map('GET', '/acme/route1', 'AcmeController::actionOne');
    $route->map('GET', '/acme/route2', 'AcmeController::actionTwo');
    $route->map('GET', '/acme/route3', 'AcmeController::actionThree');
});

可用变量

  • $route - \League\Route\RouteGroup
  • $this - \Hawkbit\Application

中间件集成

StackPHP

使用Stack\BuilderStack\Run的基本使用

<?php

// index.php
require __DIR__.'/../vendor/autoload.php';

$app = new Hawkbit\Application();

$app->get('/', function ($request, $response) {
    $response->setContent('<h1>Hello World</h1>');
    return $response;
});

$httpKernel = new Hawkbit\Application\Symfony\HttpKernelAdapter($app);

$stack = (new \Stack\Builder())
    ->push('Some/MiddleWare') // This will execute first
    ->push('Some/MiddleWare') // This will execute second
    ->push('Some/MiddleWare'); // This will execute third

$app = $stack->resolve($httpKernel);
\Stack\run($httpKernel); // The app will run after all the middlewares have run

Zend Stratigility

使用Zend\Stratigility\MiddlewarePipe的基本使用

<?php

use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\ServerRequestFactory;
use Hawkbit\Application;
use Hawkbit\Application\Stratigility\MiddlewarePipeAdapter;

$application = new Application();
$application->get('/', function($request, ResponseInterface $response){
    $response->getBody()->write('Hello World');
});
$middleware = new MiddlewarePipeAdapter($application);

//wrap html heading
$middleware->pipe('/', function($request, ResponseInterface $response, $next){
    $response->getBody()->write('<h1>');

    /** @var ResponseInterface $response */
    $response = $next($request, $response);

    $response->getBody()->write('</h1>');
});

/** @var ResponseInterface $response */
$response = $middleware(ServerRequestFactory::fromGlobals(), $application->getResponse());

echo $response->getBody(); //prints <h1>Hello World</h1>

错误处理

Hawkbit\Application使用Whoops错误处理框架,并通过请求内容类型确定错误处理器。

设置自己的处理器

<?php

$app->getErrorHandler()->push(new Acme\ErrorResponseHandler);

默认情况下,Hawkbit\Application以禁用错误选项的方式运行。要启用调试,请添加

<?php

$app->setConfig('error', true);

默认情况下,Hawkbit\Application捕获所有错误。要禁用错误捕获,请添加

<?php

$app->setConfig('error.catch', false);

控制台

控制台应用程序继承了Http应用程序的所有方法,除了路由和PSR-7处理以及捕获。除了Http应用程序,控制台应用程序不支持所有事件(更多信息请参考事件!)

日志记录

Hawkbit\Application内置了对Monolog的支持。要访问通道,请调用

<?php

$app->getLogger('channel name');

有关通道的更多信息,请阅读此指南 - https://github.com/Seldaek/monolog/blob/master/doc/usage.md#leveraging-channels

事件

您可以在生命周期中的七个点上拦截请求和响应。您可以通过Hawkbit\ApplicationEvent来操作请求、响应和ErrorResponse。

应用程序事件

<?php

/** @var \Hawkbit\Application\ApplicationEvent $event */

// custom params
$event->getParamCollection(); // returns a mutable \ArrayObject

// access application
$event->getApplication();

request.received

<?php

$app->addListener($app::EVENT_REQUEST_RECEIVED, function (\Hawkbit\Application\ApplicationEvent $event) {
    $request = $event->getRequest();
    
    // manipulate $request
    
    $event->setRequest($request);
});

当接收到请求但尚未由路由器处理时,会触发此事件。

response.created

对于控制台应用程序不可用!

<?php

$app->addListener($app::EVENT_RESPONSE_CREATED, function (\Hawkbit\Application\ApplicationEvent $event) {
    $request = $event->getRequest();
    $response = $event->getResponse();
        
    // manipulate request or response
    
    $event->setRequest($request);
    $event->setResponse($response);
});

在创建响应但尚未输出之前,会触发此事件。

response.sent

对于控制台应用程序不可用!请使用shutdown

<?php

$app->addListener($app::EVENT_RESPONSE_SENT, function (\Hawkbit\Application\ApplicationEvent $event) {
    $request = $event->getRequest();
    $response = $event->getResponse();
    
    // manipulate request or response
    
    $event->setRequest($request);
    $event->setResponse($response);
});

在输出响应并在应用程序生命周期完成后,会触发此事件。对于控制台应用程序不可用!

runtime.error

<?php

$app->addListener($app::EVENT_RUNTIME_ERROR, function (\Hawkbit\Application\ApplicationEvent $event, $exception) use ($app) {
    //process exception
});

当发生错误时,始终会触发此事件。

lifecycle.error

对于控制台应用程序不可用!请使用runtime.error

$errorResponse用作默认响应

<?php

$app->addListener($app::EVENT_LIFECYCLE_ERROR, function (\Hawkbit\Application\ApplicationEvent $event, \Exception $exception) {
    $errorResponse = $event->getErrorResponse();
 
    //manipulate error response and process exception
        
    $event->setErrorResponse($errorResponse);
});

当在处理请求/响应生命周期时发生错误时,会触发此事件。在runtime.error之后触发此事件

lifecycle.complete

对于控制台应用程序不可用!请使用shutdown

<?php

$app->addListener($app::EVENT_LIFECYCLE_COMPLETE, function (\Hawkbit\Application\ApplicationEvent $event) {
    // access the request using $event->getRequest()
    // access the response using $event->getResponse()
});

在输出响应并在应用程序生命周期完成后,会触发此事件。

shutdown

<?php

$app->addListener($app::EVENT_SHUTDOWN, function (\Hawkbit\Application\ApplicationEvent $event, $response, $terminatedOutputBuffers = []) {
    // access the response using $event->getResponse()
    // access terminated output buffer contents
    // or force application exit()
});

每次操作完成后或失败后,都会触发此事件。

自定义事件

您可以直接使用事件发射器触发自定义事件

<?php

// addListener
$app->addListener('custom.event', function ($event, $time) {
    return 'the time is '.$time;
});

// or with class addListener
$app->addListener(Acme\Event::class, function (Acme\Event $event, $time) {
    return 'the time is '.$time;
});

// Publish
$app->getEventEmitter()->emit('custom.event', time());

依赖注入容器

Hawkbit\Application使用League/Container作为其依赖注入容器。

您可以使用ArrayAccess从主应用程序对象将单例对象绑定到容器中,或者通过容器访问

<?php
/** @var Hawkbit\Application $app */
$app['db'] = function () use($app) {
    $config = $app->getConfig('database');
    $manager = new Illuminate\Database\Capsule\Manager;

    $manager->addConnection([
        'driver'    => 'mysql',
        'host'      => $config['host'],
        'database'  => $config['name'],
        'username'  => $config['user'],
        'password'  => $config['pass'],
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci'
    ], 'default');

    $manager->setAsGlobal();

    return $manager;
};

或使用容器

<?php
/** @var Hawkbit\Application $app */
$app->getContainer()->share('db', function () use($app) {
    $config = $app->getConfig('database');
    $manager = new Illuminate\Database\Capsule\Manager;

    $manager->addConnection([
        'driver'    => 'mysql',
        'host'      => $config['db_host'],
        'database'  => $config['db_name'],
        'username'  => $config['db_user'],
        'password'  => $config['db_pass'],
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci'
    ], 'default');

    $manager->setAsGlobal();

    return $manager;
});

可以使用容器的add方法添加多重实例

<?php

//callback
$app->getContainer()->add('foo', function () {
    return new Foo();
});

可以使用Hawkbit\Application app上的register方法或容器的addServiceProvider注册服务提供程序

<?php

$app->register('\My\Service\Provider');
$app->getContainer()->addServiceProvider('\My\Service\Provider');

有关服务提供程序的信息,请查看此页面 - http://container.thephpleague.com/service-providers/

为了便于后续测试,建议您采用构造函数注入

<?php

$app->getContainer()->add('Bar', function () {
        return new Bar();
});

$app->getContainer()->add('Foo', function () use ($app) {
        return new Foo(
            $app->getContainer()->get('Bar')
        );
});

容器

设置自己的容器需要\League\Container\ContainerInterface的实例

<?php

$app->setContainer($container);

获取容器

<?php

$app->getContainer();

服务

Hawkbit\Application使用依赖注入容器来访问服务。以下集成可以交换。

配置器

用于 Application::setConfig()Application::getConfig()Application::hasConfig()

<?php

$app->getConfigurator();
<?php

$app->getContainer()->share(\Zend\Config\Config::class, new \Zend\Config\Config([], true));

错误处理器

<?php

$app->getContainer()->share(\Whoops\Run::class, new \Whoops\Run());
<?php

$app->getErrorHandler();

错误响应处理器

<?php

$app->getContainer()->share(\Whoops\Handler\HandlerInterface::class, Acme\ErrorResponseHandler::class);
<?php

$app->getErrorResponseHandler();

psr 日志记录器

通过通道名称获取新的日志记录器实例

<?php

$app->getContainer()->add(\Psr\Log\LoggerInterface::class, \Monolog\Logger::class);
<?php

$app->getLogger('channel name');

获取可用的日志记录器通道列表

<?php

$app->getLoggerChannels();

psr 服务器请求

<?php

$app->getContainer()->share(\Psr\Http\Message\ServerRequestInterface::class, \Zend\Diactoros\ServerRequestFactory::fromGlobals());
<?php

$app->getRequest();

psr 响应

<?php

$app->getContainer()->add(\Psr\Http\Message\ResponseInterface::class, \Zend\Diactoros\Response::class);
<?php

$app->getRequest();

响应发射器

<?php

$app->getContainer()->share(\Zend\Diactoros\Response\EmitterInterface::class, \Zend\Diactoros\Response\SapiEmitter::class);
<?php

$app->getResponseEmitter();

变更日志

有关最近更改的更多信息,请参阅 CHANGELOG

测试

$ composer test

贡献

有关详细信息,请参阅 CONTRIBUTING

安全

如果您发现任何与安全相关的问题,请通过电子邮件 [email protected] 而不是使用问题跟踪器。

鸣谢

许可证

MIT 许可证 (MIT)。有关更多信息,请参阅 许可证文件