Построение собственного фреймворка с MicroKernelTrait¶
Класс Kernel
по умолчанию включённый в приложения Symfony использует
MicroKernelTrait
, чтобы
конфигурировать пакеты, маршруты и сервис-контейнер в одном классе.
Этот подход микро-ядра настолько гибок, что позволяет вам контролировать структуру вашего приложения и функции достаточно легко.
Приложение Symfony в одном файле¶
Начните с абсолютно пустого каталога. И установите эти компоненты Symfony через Composer:
1 2 3 | $ composer require symfony/config symfony/http-kernel \
symfony/http-foundation symfony/routing \
symfony/dependency-injection symfony/framework-bundle
|
Далее, создайте файл index.php
, определяющий класс ядра и выолняющий его:
использовать Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
использовать Symfony\Component\Config\Loader\LoaderInterface;
использовать Symfony\Component\DependencyInjection\ContainerBuilder;
использовать Symfony\Component\HttpFoundation\JsonResponse;
использовать Symfony\Component\HttpFoundation\Request;
использовать Symfony\Component\HttpKernel\Kernel как BaseKernel
использовать Symfony\Component\Routing\RouteCollectionBuilder;
require __DIR__.'/vendor/autoload.php';
class Kernel extends BaseKernel
{
use MicroKernelTrait;
public function registerBundles()
{
return array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle()
);
}
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
{
// PHP-эквивалент config/packages/framework.yaml
$c->loadFromExtension('framework', array(
'secret' => 'S0ME_SECRET'
));
}
protected function configureRoutes(RouteCollectionBuilder $routes)
{
// ядро - это сервис, указывающий на этот класс
// необязательный 3ий аргумент - имя маршрута
$routes->add('/random/{limit}', 'kernel:randomNumber');
}
public function randomNumber($limit)
{
return new JsonResponse(array(
'number' => rand(0, $limit)
));
}
}
$kernel = new Kernel('dev', true);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
Вот и всё! Чтобы протестировать, вы можете запустить встроенный веб-сервер:
1 | $ php -S localhost:8000
|
Потом посмотрите JSON-ответ в вашем браузере:
Методы “микро” ядра¶
Когда вы используете MicroKernelTrait
, ваше ядро требует ровно три метода,
определяющих ваши пакеты, сервисы и маршруты:
- registerBundles()
- Тот же
registerBundles()
, что вы видите в обычном ядре. - configureContainer(ContainerBuilder $c, LoaderInterface $loader)
- Этот метод строит и конфигурирует контейнер. На практике, вы будете использовать
loadFromExtension
, чтобы сконфигурировать разные пакеты (эквивалент того, что вы видите в обычном файлеconfig/packages/*
). Вы можете также зарегистрировать сервисы напрямую в PHP или загрузить внешние файлы конфигурации (показано ниже). - configureRoutes(RouteCollectionBuilder $routes)
- Ваша задача в этом методе - добавить маршруты в приложение.
RouteCollectionBuilder
имеет методы, которые делают добавление маршрутов в PHP веселее. Вы также можете агрузить внешние файлы конфигурации (показано ниже).
Продвинутый пример: Twig, аннотации и панель инструментов веб-отладки¶
Цель MicroKernelTrait
не в том, чтобы иметь приложение из одного файла. Она в том,
чтобы дать вам возможность выбирать ваши пакеты и структуру.
Вначале, вы наверное захотите определить ваши PHP-классы в каталог src/
. Сконфигурируйте
ваш файл composer.json
так, чтобы он загружал оттуда:
1 2 3 4 5 6 7 8 9 10 | {
"require": {
"...": "..."
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
|
Теперь, представьте, что вы хотите использовать Twig и загружать маршруты через аннотации.
Вместо того, чтобы помещать всё в index.php
, создайте новый src/Kernel.php
,
чтобы содержать ядро. Теперь он выглядит так:
// src/Kernel.php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\RouteCollectionBuilder;
use Doctrine\Common\Annotations\AnnotationRegistry;
$loader = require __DIR__.'/../vendor/autoload.php';
// автозагрузка аннотаций
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
class Kernel extends BaseKernel
{
use MicroKernelTrait;
public function registerBundles()
{
$bundles = array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
);
if ($this->getEnvironment() == 'dev') {
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
}
return $bundles;
}
protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/framework.yaml');
// сконфигурировать WebProfilerBundle только, если пакет подключен
if (isset($this->bundles['WebProfilerBundle'])) {
$c->loadFromExtension('web_profiler', array(
'toolbar' => true,
'intercept_redirects' => false,
));
}
}
protected function configureRoutes(RouteCollectionBuilder $routes)
{
// импортировать WebProfilerRoutes только, если пакет подключен
if (isset($this->bundles['WebProfilerBundle'])) {
$routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml', '/_wdt');
$routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml', '/_profiler');
}
// загрузить маршруты аннотаций
$routes->import(__DIR__.'/../src/Controller/', '/', 'annotation');
}
// необязательно, чтобы использовать стандартный каталог кеша Symfony
public function getCacheDir()
{
return __DIR__.'/../var/cache/'.$this->getEnvironment();
}
// необязательно, чтобы использовать каталог логов Symfony
public function getLogDir()
{
return __DIR__.'/../var/log';
}
}
В отличие от предыдущего ядра, это загружает внешний файл app/config/config.yml
, так
как конфигурация становится больше:
- YAML
1 2 3 4 5 6
# app/config/config.yml framework: secret: S0ME_SECRET templating: engines: ['twig'] profiler: { only_exceptions: false }
- XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<!-- app/config/config.xml --> <?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:framework="http://symfony.com/schema/dic/symfony" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> <framework:config secret="S0ME_SECRET"> <framework:templating> <framework:engine>twig</framework:engine> </framework:templating> <framework:profiler only-exceptions="false" /> </framework:config> </container>
- PHP
1 2 3 4 5 6 7 8 9 10
// app/config/config.php $container->loadFromExtension('framework', array( 'secret' => 'S0ME_SECRET', 'templating' => array( 'engines' => array('twig'), ), 'profiler' => array( 'only_exceptions' => false, ), ));
Также загружает маршруты аннотации из каталога src/Controller/
, который имеет в себе
один файл:
// src/Controller/MicroController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;
class MicroController extends Controller
{
/**
* @Route("/random/{limit}")
*/
public function randomNumber($limit)
{
$number = rand(0, $limit);
return $this->render('micro/random.html.twig', array(
'number' => $number
));
}
}
Файлы шаблонов должны жить в каталоге Resources/views/
того же каталога, в котором находится
ваше ядро. Так как Kernel
живёт в src/
, то этот шаблон находится в
src/Resources/views/micro/random.html.twig
:
1 2 3 4 5 6 7 8 9 10 | <!-- src/Resources/views/micro/random.html.twig -->
<!DOCTYPE html>
<html>
<head>
<title>Random action</title>
</head>
<body>
<p>{{ number }}</p>
</body>
</html>
|
Наконец, вам нужен фронт-контроллер для загрузки и запуска приложения. Создайте
public/index.php
:
// public/index.php
use Symfony\Component\HttpFoundation\Request;
require __DIR__.'/../src/Kernel.php';
$kernel = new Kernel('dev', true);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
Вот и всё! Этот URL /random/10
будет работать, Twig будет отображать, и вы даже увидите
внизу панель инструментов веб-отладки. Итоговая структура выглядит так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | your-project/
├─ config/
│ └─ framework.yaml
├─ public/
| └─ index.php
├─ src/
| ├─ Kernel.php
| ├─ Controller
| | └─ MicroController.php
│ └─ Resources
| └─ views
| └─ micro
| └─ random.html.twig
├─ var/
| ├─ cache/
│ └─ log/
├─ vendor/
│ └─ ...
├─ composer.json
└─ composer.lock
|
Как и раньше, вы можете использовать встроенный PHP-сервер:
1 2 | cd public/
$ php -S localhost:8000
|
Просмотрите страницу в браузере:
Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.