Pekerjaan mikro tipis

Pada tanggal 25 April 2019, versi alpha baru dari mikroframework Slim melihat cahaya hari, dan pada tanggal 18 Mei itu tumbuh menjadi beta . Saya sarankan agar Anda membiasakan diri dengan versi baru.


Di bawah potongan:


  • Tentang inovasi kerangka kerja
  • Menulis aplikasi sederhana di Slim-4
  • Tentang Slim dan PhpStorm Friendship

Baru di Slim 4


Inovasi kunci dibandingkan dengan versi 3:


  • Versi minimum PHP adalah 7.1;
  • Dukungan untuk PSR-15 (Middleware);
  • Menghapus penerapan pesan http. Instal pustaka yang kompatibel PSR-7 dan gunakan;
  • Ketergantungan Jerawat dihapus. Instal wadah kompatibel PSR-11 favorit Anda dan gunakan;
  • Kemampuan untuk menggunakan router Anda (Sebelumnya, tidak mungkin untuk meninggalkan FastRoute );
  • Mengubah implementasi penanganan kesalahan;
  • Perubahan implementasi dari output respon;
  • Menambahkan pabrik untuk membuat instance aplikasi;
  • Pengaturan yang dihapus;
  • Slim tidak lagi menetapkan default_mimetype ke string kosong, jadi Anda harus menginstalnya sendiri di php.ini atau di aplikasi Anda menggunakan ini_set('default_mimetype', '') ;
  • Penangan permintaan aplikasi sekarang hanya menerima objek permintaan (dalam versi lama, itu menerima permintaan dan objek respons).

Bagaimana cara membuat aplikasi sekarang?


Di versi ketiga, membuat aplikasi tampak seperti ini:


 <?php use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Slim\App; require 'vendor/autoload.php'; $settings = [ 'addContentLengthHeader' => false, ]; $app = new App(['settings' => $settings]); $app->get('/hello/{name}', function (ServerRequestInterface $request, ResponseInterface $response, array $args) { $name = $args['name']; $response->getBody()->write("Hello, $name"); return $response; }); $app->run(); 

Sekarang konstruktor aplikasi menerima parameter berikut:


ParameterJenisWajibDeskripsi
$ responseFactoryPsr\Http\Message\ResponseFactoryInterfaceiyaPabrik permintaan http server PSR-17 yang kompatibel
$ wadah\Psr\Container\ContainerInterfacetidakWadah ketergantungan
$ callableResolver\Slim\Interfaces\CallableResolverInterfacetidakPenangan panggilan balik
$ routeCollector\Slim\Interfaces\RouteCollectorInterfacetidakRouter
$ routeResolver\Slim\Interfaces\RouteResolverInterfacetidakPenangan Hasil Routing

Juga sekarang Anda dapat menggunakan metode create statis dari pabrik aplikasi \Slim\Factory\AppFactory .
Metode ini menerima parameter yang sama dengan input, hanya semuanya opsional.


 <?php use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Slim\Factory\AppFactory; require 'vendor/autoload.php'; $app = AppFactory::create(); $app->get('/hello/{name}', function (ServerRequestInterface $request, ResponseInterface $response) { $name = $request->getAttribute('name'); $response->getBody()->write("Hello, $name"); return $response; }); $app->run(); 

Berikan saya 404 kesalahan kembali!


Jika kami mencoba membuka halaman yang tidak ada, kami mendapatkan kode respons 500 , bukan 404 . Agar kesalahan diproses dengan benar, Anda harus menghubungkan \Slim\Middleware\ErrorMiddleware


 <?php use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Slim\Factory\AppFactory; use Slim\Middleware\ErrorMiddleware; require 'vendor/autoload.php'; $app = AppFactory::create(); $middleware = new ErrorMiddleware( $app->getCallableResolver(), $app->getResponseFactory(), false, false, false ); $app->add($middleware); $app->get('/hello/{name}', function (ServerRequestInterface $request, ResponseInterface $response) { $name = $request->getAttribute('name'); $response->getBody()->write("Hello, $name"); return $response; }); $app->run(); 

Middleware


Middleware sekarang harus menjadi implementasi PSR-15. Sebagai pengecualian, Anda dapat melewati fungsi, tetapi tanda tangan harus cocok dengan metode process() dari antarmuka \Psr\Http\Server\MiddlewareInterface


 <?php use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Server\RequestHandlerInterface; use Slim\Factory\AppFactory; require 'vendor/autoload.php'; $app = AppFactory::create(); $app->add(function (ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $response = $handler->handle($request); return $response->withHeader('Content-Type', 'application/json'); }); // ...     $app->run(); 

Tanda tangan ($request, $response, $next) tidak lagi didukung


Bagaimana cara hidup tanpa pengaturan?


Anda dapat hidup tanpa pengaturan. Alat yang disediakan akan membantu kami dalam hal ini.


httpVersion dan responseChunkSize


httpVersion bertanggung jawab untuk menampilkan versi protokol dalam respons.
Pengaturan responseChunkSize menentukan ukuran setiap chunk yang dibaca dari badan respons ketika dikirim ke browser.


Sekarang fungsi-fungsi ini dapat ditugaskan untuk emitor dari jawabannya.


Menulis emitor


 <?php // /src/ResponseEmitter.php namespace App; use Psr\Http\Message\ResponseInterface; use Slim\ResponseEmitter as SlimResponseEmitter; class ResponseEmitter extends SlimResponseEmitter { private $protocolVersion; public function __construct(string $protocolVersion = '1.1', int $responseChunkSize = 4096) { $this->protocolVersion = $protocolVersion; parent::__construct($responseChunkSize); } public function emit(ResponseInterface $response) : void{ parent::emit($response->withProtocolVersion($this->protocolVersion)); } } 

Kami terhubung ke aplikasi


 <?php use App\ResponseEmitter; use Slim\Factory\AppFactory; require 'vendor/autoload.php'; $app = AppFactory::create(); $serverRequestFactory = \Slim\Factory\ServerRequestCreatorFactory::create(); $request = $serverRequestFactory->createServerRequestFromGlobals(); // ...     $response = $app->handle($request); $emitter = new ResponseEmitter('2.0', 4096); $emitter->emit($response); 

outputBuffering


Pengaturan ini memungkinkan menyalakan / mematikan buffering output. Nilai Pengaturan:


  • false - buffering dimatikan (semua panggilan untuk echo , pernyataan print diabaikan).
  • 'append' - semua panggilan ke echo , pernyataan print ditambahkan setelah badan tanggapan
  • 'prepend' - semua panggilan ke echo , pernyataan print ditambahkan sebelum badan respons

Pengembang \Slim\Middleware\OutputBufferingMiddleware mengusulkan untuk mengganti opsi ini dengan \Slim\Middleware\OutputBufferingMiddleware , ke dalam konstruktor di mana pabrik aliran yang kompatibel dengan PSR-17 dan mode yang dapat sama dengan append atau prepend


 <?php use Slim\Factory\AppFactory; use Slim\Factory\Psr17\SlimPsr17Factory; use Slim\Middleware\OutputBufferingMiddleware; require 'vendor/autoload.php'; $app = AppFactory::create(); $middleware = new OutputBufferingMiddleware(SlimPsr17Factory::getStreamFactory(), OutputBufferingMiddleware::APPEND); $app->add($middleware); // ...     $app->run(); 

determineRouteBeforeAppMiddleware


Pengaturan ini memungkinkan untuk mendapatkan rute saat ini dari objek permintaan di middleware


Pengganti disediakan \Slim\Middleware\RoutingMiddleware


 <?php use Slim\Factory\AppFactory; use Slim\Middleware\RoutingMiddleware; require 'vendor/autoload.php'; $app = AppFactory::create(); $middleware = new RoutingMiddleware($app->getRouteResolver()); $app->add($middleware); // ...     $app->run(); 

displayErrorDetails


Pengaturan diizinkan untuk menampilkan detail kesalahan. Saat debugging, itu membuat hidup lebih mudah.


Ingat \Slim\Middleware\ErrorMiddleware ? Ini dia akan membantu kita!


 <?php use Slim\Factory\AppFactory; use Slim\Middleware\ErrorMiddleware; require 'vendor/autoload.php'; $app = AppFactory::create(); $middleware = new ErrorMiddleware( $app->getCallableResolver(), $app->getResponseFactory(), true, //        false, //   false //    ); $app->add($middleware); // ...     $app->run(); 

addContentLengthHeader


Pengaturan ini diizinkan untuk mengaktifkan / menonaktifkan penambahan otomatis header Content-Length dengan nilai volume data di badan respons


Mengganti opsi middleware \Slim\Middleware\ContentLengthMiddleware


 <?php use Slim\Factory\AppFactory; use Slim\Middleware\ContentLengthMiddleware; require 'vendor/autoload.php'; $app = AppFactory::create(); $middleware = new ContentLengthMiddleware(); $app->add($middleware); // ...     $app->run(); 

routerCacheFile


Sekarang Anda dapat langsung menginstal file cache router


 <?php use Slim\Factory\AppFactory; require 'vendor/autoload.php'; $app = AppFactory::create(); $app->getRouteCollector()->setCacheFile('/path/to/cache/router.php'); // ...     $app->run(); 

Membuat aplikasi di Slim-4


Untuk melihat lebih dekat pada framework, kita akan menulis sebuah aplikasi kecil.


Aplikasi akan memiliki rute berikut:


  • /hello/{name} - halaman sambutan;
  • / - redirect ke halaman /hello/world
  • Rute lain akan mengembalikan halaman kustom dengan 404 kesalahan.

Logikanya ada di controller, kita akan me-render halaman melalui mesin template Twig
Sebagai bonus, tambahkan aplikasi konsol berdasarkan komponen Symfony Console dengan perintah yang menampilkan daftar rute


Langkah 0. Menginstal dependensi


Kami akan membutuhkan:



Saya memilih ultra-lite / wadah sebagai wadah ketergantungan, karena ringan, ringkas, dan sesuai dengan standar.
Pengembang PSR-7 dan PSR-17 Slim menyediakan slim / psr7 dalam satu paket. Kami akan menggunakannya


Diasumsikan bahwa manajer paket Komposer sudah diinstal.

Kami membuat folder untuk proyek ( /path/to/project akan digunakan sebagai contoh) dan pergi ke sana.


Tambahkan file composer.json ke proyek dengan konten berikut:


 { "require": { "php": ">=7.1", "slim/slim": "4.0.0-beta", "slim/psr7": "~0.3", "ultra-lite/container": "^6.2", "symfony/console": "^4.2", "twig/twig": "^2.10" }, "autoload": { "psr-4": { "App\\": "app" } } } 

dan jalankan perintah


 composer install 

Sekarang kita memiliki semua paket yang diperlukan dan autoloader kelas dikonfigurasi.


Jika kita bekerja dengan git , tambahkan file .gitignore dan tambahkan direktori vendor sana (dan direktori IDE Anda jika perlu)


 /.idea/* /vendor/* 

Saya menggunakan IDE PhpStorm dan bangga akan hal itu . Untuk perkembangan yang nyaman, saatnya berteman dengan wadah dan IDE.
Di root proyek, buat file .phpstorm.meta.php dan tulis kode berikut di sana:


 <?php // .phpstorm.meta.php namespace PHPSTORM_META { override( \Psr\Container\ContainerInterface::get(0), map([ '' => '@', ]) ); } 

Kode ini akan memberi tahu IDE bahwa untuk objek yang mengimplementasikan antarmuka \Psr\Container\ContainerInterface , metode get() akan mengembalikan objek kelas atau implementasi antarmuka yang namanya dilewatkan dalam parameter.


Langkah 1. Kerangka Aplikasi


Tambahkan direktori:


  • app - kode aplikasi. Kami akan menghubungkan namespace kami untuk autoloader kelas ke sana;
  • bin - direktori untuk utilitas konsol;
  • config - di sini akan ada file konfigurasi aplikasi;
  • public - direktori dibuka di web (titik masuk aplikasi, gaya, js, gambar, dll.);
  • template - direktori template ;
  • var adalah direktori untuk berbagai file. Log, cache, penyimpanan lokal, dll.

Dan file-file:


  • config/app.ini - konfigurasi aplikasi utama;
  • config/app.local.ini - config untuk lingkungan local ;
  • app/Support/CommandMap.php - pemetaan perintah aplikasi konsol untuk pemuatan malas.
  • app/Support/Config.php - Kelas konfigurasi (sehingga IDE tahu konfigurasi mana yang kita miliki).
  • app/Support/NotFoundHandler.php - 404 kelas penangan kesalahan.
  • app/Support/ServiceProviderInterface.php - Antarmuka penyedia layanan.
  • app/Provider/AppProvider.php - Penyedia utama aplikasi.
  • bootstrap.php - perakitan wadah;
  • bin/console - titik masuk aplikasi konsol;
  • public/index.php - titik masuk aplikasi web.

config / app.ini
 ;   slim.debug=Off ;   templates.dir=template ;   templates.cache=var/cache/template 

config / app.local.ini
 ;        .       ;        slim.debug=On ;       templates.cache= 

Oh ya, masih bagus untuk mengecualikan konfigurasi lingkungan dari repositori. Bagaimanapun, mungkin ada tampilan / kata sandi. Tembolok juga dikecualikan.


.gitignore
 /.idea/* /config/* /vendor/* /var/cache/* !/config/app.ini !/var/cache/.gitkeep 

app / Dukungan / CommandMap.php
 <?php // app/Support/CommandMap.php namespace App\Support; class CommandMap { /** *  .   =>    * @var string[] */ private $map = []; public function set(string $name, string $value) { $this->map[$name] = $value; } /** * @return string[] */ public function getMap() { return $this->map; } } 

app / Dukungan / Config.php
 <?php // app/Support/Config.php namespace App\Support; class Config { /** * @var string[] */ private $config = []; public function __construct(string $dir, string $env, string $root) { if (!is_dir($dir)) return; /* *    */ $config = (array)parse_ini_file($dir . DIRECTORY_SEPARATOR . 'app.ini', false); /* *      */ $environmentConfigFile = $dir . DIRECTORY_SEPARATOR . 'app.' . $env . '.ini'; if (is_readable($environmentConfigFile)) { $config = array_replace_recursive($config, (array)parse_ini_file($environmentConfigFile, false)); } /* * ,      */ $dirs = ['templates.dir', 'templates.cache']; foreach ($config as $name=>$value) { $this->config[$name] = $value; } /* *      */ foreach ($dirs as $parameter) { $value = $config[$parameter]; if (mb_strpos($value, '/') === 0) { continue; } if (empty($value)) { $this->config[$parameter] = null; continue; } $this->config[$parameter] = $root . DIRECTORY_SEPARATOR . $value; } } public function get(string $name) { return array_key_exists($name, $this->config) ? $this->config[$name] : null; } } 

app / Dukungan / NotFoundHandler.php
 <?php // app/Support/NotFoundHandler.php namespace App\Support; use Psr\Http\Message\ResponseFactoryInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\Interfaces\ErrorHandlerInterface; use Throwable; class NotFoundHandler implements ErrorHandlerInterface { private $factory; public function __construct(ResponseFactoryInterface $factory) { $this->factory = $factory; } /** * @param ServerRequestInterface $request * @param Throwable $exception * @param bool $displayErrorDetails * @param bool $logErrors * @param bool $logErrorDetails * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails): ResponseInterface { $response = $this->factory->createResponse(404); return $response; } } 

Sekarang Anda dapat mengajar PhpStorm untuk memahami kunci mana yang memiliki kunci dan jenisnya.


.phpstorm.meta.php
 <?php // .phpstorm.meta.php namespace PHPSTORM_META { override( \Psr\Container\ContainerInterface::get(0), map([ '' => '@', ]) ); override( \App\Support\Config::get(0), map([ 'slim.debug' => 'bool', 'templates.dir' => 'string|false', 'templates.cache' => 'string|false', ]) ); } 

app / Dukungan / ServiceProviderInterface.php
 <?php // app/Support/ServiceProviderInterface.php namespace App\Support; use UltraLite\Container\Container; interface ServiceProviderInterface { public function register(Container $container); } 

app / Provider / AppProvider.php
 <?php // app/Provider/AppProvider.php namespace App\Provider; use App\Support\CommandMap; use App\Support\Config; use App\Support\NotFoundHandler; use App\Support\ServiceProviderInterface; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseFactoryInterface; use Slim\CallableResolver; use Slim\Exception\HttpNotFoundException; use Slim\Interfaces\CallableResolverInterface; use Slim\Interfaces\RouteCollectorInterface; use Slim\Interfaces\RouteResolverInterface; use Slim\Middleware\ErrorMiddleware; use Slim\Middleware\RoutingMiddleware; use Slim\Psr7\Factory\ResponseFactory; use Slim\Routing\RouteCollector; use Slim\Routing\RouteResolver; use UltraLite\Container\Container; class AppProvider implements ServiceProviderInterface { public function register(Container $container) { /* *     */ $container->set(CommandMap::class, function () { return new CommandMap(); }); /* *   http- */ $container->set(ResponseFactory::class, function () { return new ResponseFactory(); }); /* *    http-   */ $container->set(ResponseFactoryInterface::class, function (ContainerInterface $container) { return $container->get(ResponseFactory::class); }); /* *     */ $container->set(CallableResolver::class, function (ContainerInterface $container) { return new CallableResolver($container); }); /* *        */ $container->set(CallableResolverInterface::class, function (ContainerInterface $container) { return $container->get(CallableResolver::class); }); /* *   */ $container->set(RouteCollector::class, function (ContainerInterface $container) { $router = new RouteCollector( $container->get(ResponseFactoryInterface::class), $container->get(CallableResolverInterface::class), $container ); return $router; }); /* *      */ $container->set(RouteCollectorInterface::class, function (ContainerInterface $container) { return $container->get(RouteCollector::class); }); /* *     */ $container->set(RouteResolver::class, function (ContainerInterface $container) { return new RouteResolver($container->get(RouteCollectorInterface::class)); }); /* *        */ $container->set(RouteResolverInterface::class, function (ContainerInterface $container) { return $container->get(RouteResolver::class); }); /* *    404 */ $container->set(NotFoundHandler::class, function (ContainerInterface $container) { return new NotFoundHandler($container->get(ResponseFactoryInterface::class)); }); /* *  middleware   */ $container->set(ErrorMiddleware::class, function (ContainerInterface $container) { $middleware = new ErrorMiddleware( $container->get(CallableResolverInterface::class), $container->get(ResponseFactoryInterface::class), $container->get(Config::class)->get('slim.debug'), true, true); $middleware->setErrorHandler(HttpNotFoundException::class, $container->get(NotFoundHandler::class)); return $middleware; }); /* *  middleware  */ $container->set(RoutingMiddleware::class, function (ContainerInterface $container) { return new RoutingMiddleware($container->get(RouteResolverInterface::class)); }); } } 

Kami memindahkan perutean ke wadah sehingga kami bisa bekerja dengannya tanpa menginisialisasi objek \Slim\App .


bootstrap.php
 <?php // bootstrap.php require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'; use App\Support\ServiceProviderInterface; use App\Provider\AppProvider; use App\Support\Config; use UltraLite\Container\Container; /* *   */ $env = getenv('APP_ENV'); if (!$env) $env = 'local'; /* *   */ $config = new Config(__DIR__ . DIRECTORY_SEPARATOR . 'config', $env, __DIR__); /* *  - */ $providers = [ AppProvider::class, ]; /* *    */ $container = new Container([ Config::class => function () use ($config) { return $config;}, ]); /* *   */ foreach ($providers as $className) { if (!class_exists($className)) { /** @noinspection PhpUnhandledExceptionInspection */ throw new Exception('Provider ' . $className . ' not found'); } $provider = new $className; if (!$provider instanceof ServiceProviderInterface) { /** @noinspection PhpUnhandledExceptionInspection */ throw new Exception($className . ' has not provider'); } $provider->register($container); } /* *   */ return $container; 

bin / konsol
 #!/usr/bin/env php <?php // bin/console use App\Support\CommandMap; use Psr\Container\ContainerInterface; use Symfony\Component\Console\Application; use Symfony\Component\Console\CommandLoader\ContainerCommandLoader; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Output\ConsoleOutput; /** @var ContainerInterface $container */ $container = require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'bootstrap.php'; $loader = new ContainerCommandLoader($container, $container->get(CommandMap::class)->getMap()); $app = new Application(); $app->setCommandLoader($loader); /** @noinspection PhpUnhandledExceptionInspection */ $app->run(new ArgvInput(), new ConsoleOutput()); 

Dianjurkan untuk memberikan izin file ini untuk dieksekusi


 chmod +x ./bin/console 

publik / index.php
 <?php // public/index.php use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseFactoryInterface; use Slim\App; use Slim\Interfaces\CallableResolverInterface; use Slim\Interfaces\RouteCollectorInterface; use Slim\Interfaces\RouteResolverInterface; use Slim\Middleware\ErrorMiddleware; use Slim\Middleware\RoutingMiddleware; use Slim\Psr7\Factory\ServerRequestFactory; /** @var ContainerInterface $container */ $container = require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'bootstrap.php'; $request = ServerRequestFactory::createFromGlobals(); Slim\Factory\AppFactory::create(); $app = new App( $container->get(ResponseFactoryInterface::class), $container, $container->get(CallableResolverInterface::class), $container->get(RouteCollectorInterface::class), $container->get(RouteResolverInterface::class) ); $app->add($container->get(RoutingMiddleware::class)); $app->add($container->get(ErrorMiddleware::class)); $app->run($request); 

Verifikasi
Luncurkan aplikasi konsol:


 ./bin/console 

Sebagai tanggapan, jendela selamat datang untuk komponen symfony/console akan muncul dengan dua perintah yang tersedia - help dan list .


 Console Tool Usage: command [options] [arguments] Options: -h, --help Display this help message -q, --quiet Do not output any message -V, --version Display this application version --ansi Force ANSI output --no-ansi Disable ANSI output -n, --no-interaction Do not ask any interactive question -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug Available commands: help Displays help for a command list Lists commands 

Sekarang mulai server web.


 php -S localhost:8080 -t public public/index.php 

Dan buka url apa pun di localhost: 8080.
Semua permintaan harus mengembalikan respons dengan kode 404 dan badan kosong.
Ini terjadi karena kami tidak memiliki rute yang terdaftar.


Tetap bagi kami untuk menghubungkan render, menulis templat, pengontrol dan mengatur rute.


Langkah 2. Render


Tambahkan template template/layout.twig . Ini adalah templat dasar untuk semua halaman.


template / layout.twig
 {# template/layout.twig #} <!DOCTYPE html> <html lang="en"> <head> <title>{% block title %}Slim demo{% endblock %}</title> </head> <body> {% block content %}{% endblock %} </body> </html> 

Tambahkan template/hello.twig halaman sambutan template/hello.twig


template / hello.twig
 {# template/hello.twig #} {% extends 'layout.twig' %} {% block title %}Slim demo::hello, {{ name }}{% endblock %} {% block content %} <h1>Welcome!</h1> <p>Hello, {{ name }}!</p> {% endblock %} 

Dan template/err404.twig halaman kesalahan template/err404.twig


template / err404.twig
 {# template/err404.twig #} {% extends 'layout.twig' %} {% block title %}Slim demo::not found{% endblock %} {% block content %} <h1>Error!</h1> <p>Page not found =(</p> {% endblock %} 

Tambahkan app/Provider/RenderProvider.php penyedia rendering app/Provider/RenderProvider.php


app / Provider / RenderProvider.php
 <?php // app/Provider/RenderProvider.php namespace App\Provider; use App\Support\Config; use App\Support\ServiceProviderInterface; use Psr\Container\ContainerInterface; use Twig\Environment; use Twig\Loader\FilesystemLoader; use UltraLite\Container\Container; class RenderProvider implements ServiceProviderInterface { public function register(Container $container) { $container->set(Environment::class, function (ContainerInterface $container) { $config = $container->get(Config::class); $loader = new FilesystemLoader($config->get('templates.dir')); $cache = $config->get('templates.cache'); $options = [ 'cache' => empty($cache) ? false : $cache, ]; $twig = new Environment($loader, $options); return $twig; }); } } 

Nyalakan penyedia di bootstrap


bootstrap.php
 <?php // bootstrap.php // ... use App\Provider\RenderProvider; // ... $providers = [ // ... RenderProvider::class, // ... ]; // ... 

Tambahkan render ke penangan kesalahan 404


app / Dukungan / NotFoundHandler.php (DIFF)
 --- a/app/Support/NotFoundHandler.php +++ b/app/Support/NotFoundHandler.php @@ -8,15 +8,22 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\Interfaces\ErrorHandlerInterface; use Throwable; +use Twig\Environment; +use Twig\Error\LoaderError; +use Twig\Error\RuntimeError; +use Twig\Error\SyntaxError; class NotFoundHandler implements ErrorHandlerInterface { private $factory; - public function __construct(ResponseFactoryInterface $factory) + private $render; + + public function __construct(ResponseFactoryInterface $factory, Environment $render) { $this->factory = $factory; + $this->render = $render; } /** @@ -26,10 +33,14 @@ class NotFoundHandler implements ErrorHandlerInterface * @param bool $logErrors * @param bool $logErrorDetails * @return ResponseInterface + * @throws LoaderError + * @throws RuntimeError + * @throws SyntaxError */ public function __invoke(ServerRequestInterface $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails): ResponseInterface { $response = $this->factory->createResponse(404); + $response->getBody()->write($this->render->render('err404.twig')); return $response; } } 

app / Provider / AppProvider.php (DIFF)
 --- a/app/Provider/AppProvider.php +++ b/app/Provider/AppProvider.php @@ -19,6 +19,7 @@ use Slim\Middleware\RoutingMiddleware; use Slim\Psr7\Factory\ResponseFactory; use Slim\Routing\RouteCollector; use Slim\Routing\RouteResolver; +use Twig\Environment; use UltraLite\Container\Container; class AppProvider implements ServiceProviderInterface @@ -99,7 +100,7 @@ class AppProvider implements ServiceProviderInterface *    404 */ $container->set(NotFoundHandler::class, function (ContainerInterface $container) { - return new NotFoundHandler($container->get(ResponseFactoryInterface::class)); + return new NotFoundHandler($container->get(ResponseFactoryInterface::class), $container->get(Environment::class)); }); /* 

404 .


3.



2:


  • app/Controller/HomeController.php
  • app/Controller/HelloController.php

( URL ), — ( html)


app/Controller/HomeController.php
 <?php // app/Controller/HomeController.php namespace App\Controller; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\Interfaces\RouteParserInterface; class HomeController { /** * @var RouteParserInterface */ private $router; public function __construct(RouteParserInterface $router) { $this->router = $router; } public function index(ServerRequestInterface $request, ResponseInterface $response) { $uri = $this->router->fullUrlFor($request->getUri(), 'hello', ['name' => 'world']); return $response ->withStatus(301) ->withHeader('location', $uri); } } 

app/Controller/HelloController.php
 <?php // app/Controller/HelloController.php namespace App\Controller; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Twig\Environment as Render; use Twig\Error\LoaderError; use Twig\Error\RuntimeError; use Twig\Error\SyntaxError; class HelloController { /** * @var Render */ private $render; public function __construct(Render $render) { $this->render = $render; } /** * @param ServerRequestInterface $request * @param ResponseInterface $response * @return ResponseInterface * @throws LoaderError * @throws RuntimeError * @throws SyntaxError */ public function show(ServerRequestInterface $request, ResponseInterface $response) { $response->getBody()->write($this->render->render('hello.twig', ['name' => $request->getAttribute('name')])); return $response; } } 

,


app/Provider/WebProvider.php
 <?php // app/Provider/WebProvider.php namespace App\Provider; use App\Controller\HelloController; use App\Controller\HomeController; use App\Support\ServiceProviderInterface; use Psr\Container\ContainerInterface; use Slim\Interfaces\RouteCollectorInterface; use Slim\Interfaces\RouteCollectorProxyInterface; use Twig\Environment; use UltraLite\Container\Container; class WebProvider implements ServiceProviderInterface { public function register(Container $container) { /* *   */ $container->set(HomeController::class, function (ContainerInterface $container) { return new HomeController($container->get(RouteCollectorInterface::class)->getRouteParser()); }); $container->set(HelloController::class, function (ContainerInterface $container) { return new HelloController($container->get(Environment::class)); }); /* *   */ $router = $container->get(RouteCollectorInterface::class); $router->group('/', function(RouteCollectorProxyInterface $router) { $router->get('', HomeController::class . ':index')->setName('index'); $router->get('hello/{name}', HelloController::class . ':show')->setName('hello'); }); } } 


bootstrap.php
 <?php // bootstrap.php // ... use App\Provider\WebProvider; // ... $providers = [ // ... WebProvider::class, // ... ]; // ... 

- ( )...


 php -S localhost:8080 -t public public/index.php 

http://localhost:8080 , http://localhost:8080/hello/world


world'.
http://localhost:8080/hello/ivan ivan'.


, , http://localhost:8080/helo/world 404 .


4.


route:list


app/Command/RouteListCommand.php
 <?php // app/Command/RouteListCommand.php namespace App\Command; use Slim\Interfaces\RouteCollectorInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; class RouteListCommand extends Command { /* *    ,        */ const NAME = 'route:list'; /** * @var RouteCollectorInterface */ private $router; public function __construct(RouteCollectorInterface $router) { $this->router = $router; parent::__construct(); } protected function configure() { $this->setName(self::NAME) ->setDescription('List of routes.') ->setHelp('List of routes.') ; } protected function execute(InputInterface $input, OutputInterface $output) { $io = new SymfonyStyle($input, $output); $io->title('Routes'); $rows = []; $routes = $this->router->getRoutes(); if (!$routes) { $io->text('Routes list is empty'); return 0; } foreach ($routes as $route) { $rows[] = [ 'path' => $route->getPattern(), 'methods' => implode(', ', $route->getMethods()), 'name' => $route->getName(), 'handler' => $route->getCallable(), ]; } $io->table( ['Route', 'Methods', 'Name', 'Handler'], $rows ); return 0; } } 

,


app/Provider/CommandProvider.php
 <?php // app/Provider/CommandProvider.php namespace App\Provider; use App\Command\RouteListCommand; use App\Support\CommandMap; use App\Support\ServiceProviderInterface; use Psr\Container\ContainerInterface; use Slim\Interfaces\RouteCollectorInterface; use UltraLite\Container\Container; class CommandProvider implements ServiceProviderInterface { public function register(Container $container) { /* *       */ $container->set(RouteListCommand::class, function (ContainerInterface $container) { return new RouteListCommand($container->get(RouteCollectorInterface::class)); }); /* *        */ $container->get(CommandMap::class)->set(RouteListCommand::NAME, RouteListCommand::class); } } 


bootstrap.php
 <?php // bootstrap.php // ... use App\Provider\CommandProvider; // ... $providers = [ // ... CommandProvider::class, // ... ]; // ... 

...


 ./bin/console route:list 

… :


 Routes ====== --------------- --------- ------- ------------------------------------- Route Methods Name Handler --------------- --------- ------- ------------------------------------- / GET index App\Controller\HomeController:index /hello/{name} GET hello App\Controller\HelloController:show --------------- --------- ------- ------------------------------------- 

, , !


, Slim — routes.php ( ), . — , , .


Source: https://habr.com/ru/post/id452834/


All Articles