hawkbit / hawkbit
PSR-7 微型 PHP 框架
Requires
- php: >=5.5.9
- filp/whoops: ^2.1
- league/climate: ^3.2
- league/container: ^2.4
- league/event: ^2.1
- league/route: ~3.0
- monolog/monolog: ^1.22
- zendframework/zend-config: ^2.6
- zendframework/zend-diactoros: ^1.4
Requires (Dev)
- phpunit/phpunit: ~4.8
- symfony/http-kernel: ~2.7|~3.0
- symfony/psr-http-message-bridge: *
- zendframework/zend-stratigility: ~1.1.2|~1.3.1
Suggests
- symfony/http-kernel: Dependency of symfony http foundation adapter
- symfony/psr-http-message-bridge: Dependency of symfony http foundation adapter
- zendframework/zend-stratigility: Dependency of stratigility middleware adapter
Provides
README
Hawkbit\Application 微型框架是一个高度可定制、事件驱动,并且与 PSR-7、StackPHP 和 Zend Stratigility 兼容。
Hawkbit\Application 使用了最新版本的 League\Route 进行路由,League\Container 进行依赖注入,League\Event 进行事件分发,Zend Config 进行配置。
Hawkbit\Application 是 Proton 的一个高级衍生版本,也是 Marco Bunge 的 Hawkbit 应用组件集合的一部分。Hawkbit 应用程序 1.x 也被称为 Blast Hawkbit 应用程序。
快速入门
请参阅 public/ 以获取示例用法并阅读文档。
集成
Hawkbit 应用程序还提供了可选的软件包
- 数据库:
hawkbit/database
- Doctrine ORM 包装器:
hawkbit/doctrine
- Plates 视图引擎:
hawkbit/presentation
动机
我的愿景是提供一个能够以相同方式处理 HTTP 和 CLI 的微型框架。开发者应该能够重用其代码,根据他的需求设计其业务层。Hawkbit 应该是一个辅助工具,而不是预定义的框架。是的,它目前正在积极开发中。
我喜欢 PSR、phpleague 和最小依赖集,并希望创建一个微框架,它使用了最好的软件包,并捆绑在一个良好的应用程序层中。我也喜欢基于组件的开发风格。
Hawkbit 是建立在 phpleague 软件包之上,并考虑到 PSR。Hawkbit 是设计来与您的代码共存,而不是替换代码库。Hawkbit 确实有一个小的依赖足迹。最后但并非最不重要的是,Hawkbit 不会强迫开发者如何设计应用程序的业务逻辑,因为我们更喜欢使用 POPO's(用于业务逻辑的访问器)。
目前我设计和开发所有 Hawkbit 软件包,并管理整个代码库。我将非常欣赏支持,甚至更好的:贡献者!
请参阅 问题 #33 以获取详细信息。
特别感谢
感谢您提交 PR、识别 Bus 或其他改进!
安装
使用 Composer
Hawkbit 应用程序可在 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\MiddelwareRunner
路由
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
与StackPHP的基本用法(使用Stack\Builder
和Stack\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
与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 Application的所有方法,除了路由和PSR-7处理和捕获。除了Http Application之外,控制台应用程序不支持所有事件(更多信息请参阅事件!)
日志
Hawkbit\Application内置了对Monolog的支持。要访问通道,请调用
<?php $app->getLogger('channel name');
有关通道的更多信息,请阅读此指南 - https://github.com/Seldaek/monolog/blob/master/doc/usage.md#leveraging-channels.
事件
您可以在生命周期中的七个点上拦截请求和响应。您可以通过Hawkbit\ApplicationEvent
来操纵Request、Response和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之后触发。
生命周期完成
控制台应用程序不支持此事件!请使用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() });
此事件在响应输出之后、应用程序生命周期完成之前触发。
关闭
<?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 logger
通过通道名称获取新的日志记录器实例
<?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。
安全
如果您发现任何与安全相关的问题,请通过电子邮件mjls@web.de报告,而不是使用问题跟踪器。
鸣谢
- Marco Bunge
- Alex Bilbie(Proton)
- 所有贡献者
许可
MIT许可(MIT)。有关更多信息,请参阅许可文件。