Kernel Http for any Eureka Framework application.
Define global Application, Controller & Component kernel versions
If you wish to install it in your project, require it via composer:
composer require eureka/kernel-http<?php
declare(strict_types=1);
/*
* Copyright (c) Romain Cottard
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Eureka\Kernel\Http\Application\Application;
use Eureka\Kernel\Http\Kernel;
//~ Define Loader & add main classes for config
require_once __DIR__ . '/vendor/autoload.php';
$root = realpath(__DIR__ . '/');
$env = 'dev';
$debug = true;
// Run application
// Applications exception should be caught. Try catch useful only when you have a bug in kernel component
try {
$application = new Application(new Kernel($root, $env, $debug));
$response = $application->run();
$application->send($response);
} catch (\Exception $exception) {
echo 'Exception: ' . $exception->getMessage() . PHP_EOL;
echo 'Trace: ' . $exception->getTraceAsString() . PHP_EOL;
exit(1);
}config/
|_ packages/
| |_ domains/
| - user.yaml
| - app.yaml
| - database.yaml
| - services.yaml
|_ dev/
| - app.yaml
|_ test/
| - app.yaml
|_ secrets/
| - database.yaml
|_ services.yaml
Config loading order and overrides:
kernel.yamlis loaded- Then
services.yaml - Then
packages/ - Then
{current_env}/ - Finally
secrets/
parameters:
#~ Debug
kernel.debug: false
#~ Environment
kernel.environment: 'prod' # Overridden in Kernel class, but define here as helper
#~ Errors
kernel.error.display: 'false'
kernel.error.reporting: !php/const E_ALL
#~ Directories
kernel.directory.root: '..' # Overridden in Kernel class, but define here as helper
kernel.directory.cache: '%kernel.directory.root%/var/cache'
kernel.directory.log: '%kernel.directory.root%/var/log'
kernel.directory.config: '%kernel.directory.root%/config'
kernel.directory.vendor: '%kernel.directory.root%/vendor'
#~ Compiler passes
kernel.compiler_pass:
- My\Custom\CompilerPassparameters:
app.name: 'kernel'
services:
# Main container
Psr\Container\ContainerInterface:
alias: 'service_container'
# Main Logger
logger:
alias: Psr\Log\NullLogger
# Main cache item pool
cache:
alias: Psr\Cache\CacheItemPoolInterface
#~ PSR-17 Factories public alias (used by Application via container directly)
response_factory:
alias: Nyholm\Psr7\Factory\Psr17Factory
public: true
request_factory:
alias: Nyholm\Psr7\Factory\Psr17Factory
public: true
server_request_factory:
alias: Nyholm\Psr7\Factory\Psr17Factory
public: true
stream_factory:
alias: Nyholm\Psr7\Factory\Psr17Factory
public: true
uri_factory:
alias: Nyholm\Psr7\Factory\Psr17Factory
public: true
services:
_defaults:
autowire: true
public: true # Important, because Controller middleware use container to get appropriate controller and use it
#~ Auto discovery kernel controllers (mainly error controller + interfaces)
Eureka\Kernel\Http\Controller\:
resource: '../../vendor/eureka/kernel-http/src/Controller/*'
calls:
- setLogger: [ '@logger' ]
- setRouter: [ '@router' ]
- setResponseFactory: [ '@response_factory' ]
- setRequestFactory: [ '@request_factory' ]
- setServerRequestFactory: [ '@server_request_factory' ]
- setStreamFactory: [ '@stream_factory' ]
- setUriFactory: [ '@uri_factory' ]
#~ Auto discovery application controllers
Application\Controller\:
resource: '../../src/Controller/*'
calls:
- setLogger: [ '@logger' ]
- setRouter: [ '@router' ]
- setResponseFactory: [ '@response_factory' ]
- setRequestFactory: [ '@request_factory' ]
- setServerRequestFactory: [ '@server_request_factory' ]
- setStreamFactory: [ '@stream_factory' ]
- setUriFactory: [ '@uri_factory' ]
#~ Auto discovery kernel services
Eureka\Kernel\Http\Service\:
resource: '../../vendor/eureka/kernel-http/src/Service/*'parameters:
# app.middleware Name is important, used by app to get list of middlewares
# order is important, as the first is process, then the following, etc.
app.middleware:
error: 'Eureka\Kernel\Http\Middleware\ErrorMiddleware'
router: 'Eureka\Kernel\Http\Middleware\RouterMiddleware'
logger: 'Eureka\Kernel\Http\Middleware\ResponseTimeLoggerMiddleware'
quota: 'Eureka\Kernel\Http\Middleware\RateLimiterMiddleware'
controller: 'Eureka\Kernel\Http\Middleware\ControllerMiddleware'
services:
_defaults:
autowire: true
public: true # Must be true, because Application use container to retrieve each middleware and assign them to handler
bind:
$applicationName: '%app.name%'
$logger: '@logger'
$cache: '@cache'
#~ Global Kernel Services Middleware
Eureka\Kernel\Http\Middleware\:
resource: '../../vendor/eureka/kernel-http/src/Middleware'
#~ Global Application Services Middleware
Application\Middleware\:
resource: '../../src/Middleware'services:
_defaults:
autowire: true
router:
alias: Symfony\Component\Routing\Router
Symfony\Component\Routing\:
resource: '../../vendor/symfony/routing/*'
exclude: '../../vendor/symfony/routing/{Router,Tests}'
Symfony\Component\Config\:
resource: '../../vendor/symfony/config/*'
exclude: '../../vendor/symfony/config/{FileLocator,Tests}'
Symfony\Component\Config\Loader\LoaderInterface:
alias: Symfony\Component\Routing\Loader\YamlFileLoader
Symfony\Component\Config\FileLocatorInterface:
alias: Symfony\Component\Config\FileLocator
Symfony\Component\Config\FileLocator:
arguments:
- '%kernel.directory.config%'
Symfony\Component\Routing\Router:
arguments:
$loader: '@Symfony\Component\Routing\Loader\YamlFileLoader'
$resource: 'routes.yaml'
$options:
cache_dir: '%kernel.directory.cache%/%kernel.environment%'
debug: '%kernel.debug%'services:
_defaults:
autowire: true
router:
alias: Symfony\Component\Routing\Router
Symfony\Component\Routing\:
resource: '../../vendor/symfony/routing/*'
exclude: '../../vendor/symfony/routing/{Router,Tests}'
Symfony\Component\Config\:
resource: '../../vendor/symfony/config/*'
exclude: '../../vendor/symfony/config/{FileLocator,Tests}'
Symfony\Component\Config\Loader\LoaderInterface:
alias: Symfony\Component\Routing\Loader\YamlFileLoader
Symfony\Component\Config\FileLocatorInterface:
alias: Symfony\Component\Config\FileLocator
Symfony\Component\Config\FileLocator:
arguments:
- '%kernel.directory.config%'
Symfony\Component\Routing\Router:
arguments:
$loader: '@Symfony\Component\Routing\Loader\YamlFileLoader'
$resource: 'routes.yaml'
$options:
cache_dir: '%kernel.directory.cache%/%kernel.environment%'
debug: '%kernel.debug%'
services:
_defaults:
autowire: true
Nyholm\Psr7\:
resource: '%kernel.directory.root%/vendor/nyholm/psr7/src/*'
#~ PSR
Eureka\Component\Http\:
resource: '%kernel.directory.root%/vendor/eureka/component-http/src/*'
Psr\Log\:
resource: '%kernel.directory.root%/vendor/psr/log/src/*'
Psr\Cache\CacheItemPoolInterface:
alias: Symfony\Component\Cache\Adapter\ArrayAdapter
Symfony\Component\Cache\Adapter\ArrayAdapter: ~
# ===== HOME =====
home:
path: /
controller: Application\Controller\ExampleController::home
methods: [ GET ]
defaults:
rateLimiterQuota: 100 # Used to set rate limit on this endpoint
rateLimiterTTL: 60 # Used to set rate limit on this endpoint
test_url_with_param:
path: /blog/{id}/{title}
controller: Application\Controller\ExampleController::viewWithParams
methods: [ GET ]
defaults:
someString: 'value'
someBool: true
someInt: 42
requirements:
id: '\d+'
title: '[a-zA-Z-]+'
Default value & requirements values are injected in controller actions, with the following order:
- ServerRequest object (always pass)
- defaults (in same order as defined in yaml file)
- requirements (in same order as defined in yaml. Requirement are always injected as string)
Example of controller:
<?php
declare(strict_types=1);
namespace Eureka\Kernel\Http\Tests\Unit\Mock;
use Eureka\Kernel\Http\Controller\Controller;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class ExampleController extends Controller
{
public function home(): ResponseInterface
{
return $this->getResponse('Hello world!');
}
public function viewWithParams(
ServerRequestInterface $serverRequest,
string $someString,
bool $someBool,
int $someInt,
string $id,
string $title,
): ResponseInterface {
return $this->getResponse("entity id: $id, title: $title, someString: $someString, someBool: " . ($someBool ? 'true' : 'false') . ", someInt: $someInt");
}See the CONTRIBUTING file.
You can install project with the following command:
make installAnd update with the following command:
make updateNB: For the components, the composer.lock file is not committed.
You can run unit tests (with coverage) on your side with following command:
make php/testsYou can run integration tests (without coverage) on your side with following command:
make php/integrationFor prettier output (but without coverage), you can use the following command:
make php/testdox # run tests without coverage reports but with prettified outputYou also can run code style check with following commands:
make php/checkYou also can run code style fixes with following commands:
make php/fixYou can check if any explicit dependency is missing with the following command:
make php/depsTo perform a static analyze of your code (with phpstan, lvl 9 at default), you can use the following command:
make php/analyseTo ensure you code still compatible with current supported version at Deezer and futures versions of php, you need to run the following commands (both are required for full support):
Minimal supported version:
make php/min-compatibilityMaximal supported version:
make php/max-compatibilityAnd the last "helper" commands, you can run before commit and push, is:
make ci This project is currently under The MIT License (MIT). See LICENSE file for more information.