Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/hawkbitphp/hawkbit

PSR-7 Micro PHP framework - advanced derivate of Proton by Alex Bilbie
https://github.com/hawkbitphp/hawkbit

console-framework event-driven framework http micro-framework middleware php php7 php71 psr-7 psr7-handler psr7-middleware web-framework

Last synced: 5 days ago
JSON representation

PSR-7 Micro PHP framework - advanced derivate of Proton by Alex Bilbie

Awesome Lists containing this project

README

        

# Hawkbit\Application

[![Latest Version on Packagist][ico-version]][link-packagist]
[![Software License][ico-license]](LICENSE.md)
[![Build Status][ico-travis]][link-travis]
[![Total Downloads][ico-downloads]][link-downloads]
[![Coverage Status][ico-coveralls]][link-coveralls]

Hawkbit\Application micro framework is a high customizable, event driven and compatible with
[PSR-7](https://github.com/php-fig/http-message),
[StackPHP](http://stackphp.com/) and
[Zend Stratigility](https://github.com/zendframework/zend-stratigility).

Hawkbit\Application uses latest versions of [League\Route](https://github.com/thephpleague/route) for routing,
[League\Container](https://github.com/thephpleague/container) for dependency injection,
[League\Event](https://github.com/thephpleague/event) for event dispatching,
[Zend Config](https://docs.zendframework.com/zend-config/) for configuration.

Hawkbit\Application is an advanced derivate of [Proton](https://github.com/alexbilbie/Proton) and part of Hawkbit\Application Component collection by Marco Bunge. Hawkbit\Application 1.x is also known as Blast Hawkbit\Application.

### Quick start

Please see [public/](public/) for example usage and read documentation.

### Integrations

Hawkbit\Application delivers also optional packages:

- Database: [`hawkbit/database`](https://github.com/HawkBitPhp/hawkbit-database)
- Doctrine ORM Wrapper: [`hawkbit/doctrine`](https://github.com/HawkBitPhp/hawkbit-doctrine)
- Plates View Engine: [`hawkbit/presentation`](https://github.com/HawkBitPhp/hawkbit-presentation)

## Motivation

> My vision is to provide a micro framework which is able to handle HTTP and CLI in the same fashion. The developer should be able to reuse it's code, design it's business layer by his needs. Hawkbit should be a supporting tool instead of predefined framework. And yes it is under active development.
>
> I love PSR, phpleague und a minimal set of dependecies and want to create a micro framework which is used the best packages out there and bundeld in a nice application layer. I'm also love the style of component-based development.
>
> Hawkbit is built on top phpleague packages and keep PSR in mind. Hawkbit is designed to co-exist whith your code instead of replace code base. Hawkbit does has a small dependency footprint. Last but not least Hawkbit does not force the developer how to design the application bussiness logic, since we prefer to use POPO's for Controllers / Commands (the accessor to bussiness logic).
>
> At the moment I design and develop all Hawkbit packages and manage the whole codebase. I would be appreciate for support or even better: for contributors!

Please refer to [Issue #33](https://github.com/HawkBitPhp/hawkbit/issues/33) for details.

## Special thanks

Thank you for PR, identifing Bus, or any other Improvements!

- [designcise](https://github.com/designcise)
- [Vitalij Mik](https://github.com/BlackScorp)

## Install

### Using Composer

Hawkbit\Application is available on [Packagist](https://packagist.org/packages/hawkbit/hawkbit) and can be installed using [Composer](https://getcomposer.org/). This can be done by running the following command or by updating your `composer.json` file.

```bash
composer require hawkbit/hawkbit
```

composer.json

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

Be sure to also include your Composer autoload file in your project:

```php
'value'
];
$app = new \Hawkbit\Application($config);
```

Add routes

```php
get('/', function ($request, $response) {
$response->getBody()->write('

It works!

');
return $response;
});

$app->get('/hello/{name}', function ($request, $response, $args) {
$response->getBody()->write(
sprintf('

Hello, %s!

', $args['name'])
);
return $response;
});
```

Run application

```php
run();
```

See also our example at `/public/index.php`.

## Configuration

Add additional configuration to application

Hawkbit\Application Configuration is managed by [zend-config](https://docs.zendframework.com/zend-config/).

```php
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/';
```

Access configuration

```php
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
```

## Middlewares

Hawkbit\Application middlewares allows advanced control of lifecycle execution.

```php
addMiddleware(new Acme\SomeMiddleware);
```

Hawkbit\Application uses it's own runner `Hawkbit\Application\MiddelwareRunner`

## Routing

Hawkbit\Application uses routing integration of `league/route` and allows access to route collection methods directly.

Basic usage with anonymous functions:

```php
get('/', function ($request, $response) {
$response->getBody()->write('

It works!

');
return $response;
});

$app->get('/hello/{name}', function ($request, $response, $args) {
$response->getBody()->write(
sprintf('

Hello, %s!

', $args['name'])
);
return $response;
});

$app->run();
```

#### Access app from anonymous function

Hawkbit\Application allows to access itself from anonymous function through closure binding.

```php
get('/hello/{name}', function ($request, $response, $args) {

// access Hawkbit\Application
$app = $this;

$response->getBody()->write(
sprintf('

Hello, %s!

', $args['name'])
);
return $response;
});

```

Basic usage with controllers:

```php
get('/', 'HomeController::index'); // calls index method on HomeController class

$app->run();
```

```php
getBody()->write('

It works!

');
return $response;
}
}
```

Automatic constructor injection of controllers:

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

$app->run();
```

*Please use boot method in Service Providers for correct injection of services into controller!*

```php
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;
}
}
```

For more information about routes [read this guide](http://route.thephpleague.com/)

### Route groups

Hawkbit\Application add support for route groups.

```php
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');
});
```

#### Available vars

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

## Middleware integrations

### StackPHP

Basic usage with StackPHP (using `Stack\Builder` and `Stack\Run`):

```php
get('/', function ($request, $response) {
$response->setContent('

Hello World

');
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

Basic usage with Stratigility (using `Zend\Stratigility\MiddlewarePipe`):

```php
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('

');

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

$response->getBody()->write('

');
});

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

echo $response->getBody(); //prints

Hello World

```

## Error handling

Hawkbit\Application uses Whoops error handling framework and determines the error handler by request content type.

Set your own handler:

```php
getErrorHandler()->push(new Acme\ErrorResponseHandler);
```

By default Hawkbit\Application runs with error options disabled. To enable debugging add

```php
setConfig('error', true);
```

By default Hawkbit\Application is catching all errors. To disable error catching add

```php
setConfig('error.catch', false);
```

## Console

The console application inherit all methods from Http Application except routing and PSR-7 handling and capturing.
In addition to http application, the console application does not support all events (Refer to events for more
information!)

## Logging

Hawkbit\Application has built in support for Monolog. To access a channel call:

```php
getLogger('channel name');
```

For more information about channels read this guide - [https://github.com/Seldaek/monolog/blob/master/doc/usage.md#leveraging-channels](https://github.com/Seldaek/monolog/blob/master/doc/usage.md#leveraging-channels).

## Events

You can intercept requests and responses at seven points during the lifecycle. You can manipulate Request, Response and
ErrorResponse via `Hawkbit\ApplicationEvent`.

### Application event

```php
getParamCollection(); // returns a mutable \ArrayObject

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

```

### request.received

```php
addListener($app::EVENT_REQUEST_RECEIVED, function (\Hawkbit\Application\ApplicationEvent $event) {
$request = $event->getRequest();

// manipulate $request

$event->setRequest($request);
});
```

This event is fired when a request is received but before it has been processed by the router.

### response.created

*Not available for Console applications!*

```php
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);
});
```

This event is fired when a response has been created but before it has been output.

### response.sent

*Not available for Console applications! Please use `shutdown`*

```php
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);
});
```

This event is fired when a response has been output and before the application lifecycle is completed. Not available for Console Applications!

### runtime.error

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

This event is always fired when an error occurs.

### lifecycle.error

*Not available for Console applications! Please use `runtime.error`*

`$errorResponse` is used as default response

```php
addListener($app::EVENT_LIFECYCLE_ERROR, function (\Hawkbit\Application\ApplicationEvent $event, \Exception $exception) {
$errorResponse = $event->getErrorResponse();

//manipulate error response and process exception

$event->setErrorResponse($errorResponse);
});
```

This event is fired only when an error occurs while handling request/response lifecycle.
This event is fired after runtime.error

### lifecycle.complete

*Not available for Console applications! Please use `shutdown`*

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

This event is fired when a response has been output and before the application lifecycle is completed.

### shutdown

```php
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()
});
```

This event is always fired after each operation is completed or failed.

### Custom Events

You can fire custom events using the event emitter directly:

```php
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());
```

## Dependency Injection Container

Hawkbit\Application uses `League/Container` as its dependency injection container.

You can bind singleton objects into the container from the main application object using ArrayAccess:

```php
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;
};
```

or by container access:

```php
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;
});
```

Multitons can be added using the `add` method on the container:

```php
getContainer()->add('foo', function () {
return new Foo();
});
```

Service providers can be registered using the `register` method on the Hawkbit\Application app or `addServiceProvider` on the container:

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

For more information about service providers check out this page - [http://container.thephpleague.com/service-providers/](http://container.thephpleague.com/service-providers/).

For easy testing down the road it is recommended you embrace constructor injection:

```php
getContainer()->add('Bar', function () {
return new Bar();
});

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

### Container

Set your own container needs an instance of `\League\Container\ContainerInterface`

```php
setContainer($container);
```

Get container

```php
getContainer();
```

## Services

Hawkbit\Application uses dependency injection container to access services. Following integrations can be exchanged.

### Configurator

Uses in `Application::setConfig()`,`Application::getConfig()` and `Application::hasConfig()`

```php
getConfigurator();
```

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

### error handler

```php
getContainer()->share(\Whoops\Run::class, new \Whoops\Run());
```

```php
getErrorHandler();
```

### error response handler

```php
getContainer()->share(\Whoops\Handler\HandlerInterface::class, Acme\ErrorResponseHandler::class);
```

```php
getErrorResponseHandler();
```

### psr logger

Get a new logger instance by channel name

```php
getContainer()->add(\Psr\Log\LoggerInterface::class, \Monolog\Logger::class);
```

```php
getLogger('channel name');
```

Get a list of available logger channels

```php
getLoggerChannels();
```

### psr server request

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

```php
getRequest();
```

### psr response

```php
getContainer()->add(\Psr\Http\Message\ResponseInterface::class, \Zend\Diactoros\Response::class);
```

```php
getRequest();
```

### response emitter

```php
getContainer()->share(\Zend\Diactoros\Response\EmitterInterface::class, \Zend\Diactoros\Response\SapiEmitter::class);
```

```php
getResponseEmitter();
```

## Change log

Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.

## Testing

``` bash
$ composer test
```

## Contributing

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

## Security

If you discover any security related issues, please email instead of using the issue tracker.

## Credits

- [Marco Bunge](https://github.com/mbunge)
- [Alex Bilbie](https://github.com/alexbilbie) (Proton)
- [All contributors](https://github.com/hawkbit/hawkbit/graphs/contributors)

## License

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

[ico-version]: https://img.shields.io/packagist/v/hawkbit/hawkbit.svg?style=flat-square
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
[ico-travis]: https://img.shields.io/travis/HawkBitPhp/hawkbit/master.svg?style=flat-square
[ico-downloads]: https://img.shields.io/packagist/dt/hawkbit/hawkbit.svg?style=flat-square
[ico-coveralls]: https://img.shields.io/coveralls/HawkBitPhp/hawkbit/master.svg?style=flat-square

[link-packagist]: https://packagist.org/packages/hawkbit/hawkbit
[link-travis]: https://travis-ci.org/HawkBitPhp/hawkbit
[link-downloads]: https://packagist.org/packages/hawkbit/hawkbit
[link-author]: https://github.com/mbunge
[link-contributors]: ../../contributors
[link-coveralls]: https://coveralls.io/github/HawkBitPhp/hawkbit