microframework ضئيلة

في 25 نيسان (أبريل) 2019 ، شهدت النسخة الجديدة alpha الرئيسية من الأعمال المصغرة " سليم" المصغرة ، النور ، وفي 18 أيار (مايو) ، أصبحت نسخة beta . أقترح عليك أن تتعرف على الإصدار الجديد.


تحت القطع:


  • حول ابتكارات الإطار
  • كتابة تطبيق بسيط على Slim-4
  • عن Slim و PhpStorm الصداقة

الجديد في Slim 4


الابتكارات الرئيسية مقارنة بالإصدار 3:


  • الحد الأدنى من إصدار PHP هو 7.1 ؛
  • دعم PSR-15 (البرامج الوسيطة) ؛
  • إزالة تنفيذ رسائل المتشعب. تثبيت أي مكتبة متوافقة PSR-7 واستخدامها ؛
  • إزالة التبعية البثرة . قم بتثبيت حاوية PSR-11 المتوافقة المفضلة لديك واستخدمها ؛
  • القدرة على استخدام جهاز التوجيه الخاص بك (سابقًا ، لم يكن من الممكن التخلي عن FastRoute ) ؛
  • تغيير تنفيذ معالجة الأخطاء ؛
  • تغيير تنفيذ مخرجات الاستجابة ؛
  • تمت إضافة مصنع لإنشاء مثيل للتطبيق ؛
  • الإعدادات التي تمت إزالتها
  • لم يعد Slim يعيّن default_mimetype إلى سلسلة فارغة ، لذلك تحتاج إلى تثبيته بنفسك في php.ini أو في تطبيقك باستخدام ini_set('default_mimetype', '') ؛
  • يقبل معالج طلب التطبيق الآن كائن الطلب فقط (في الإصدار القديم ، وافق على كائنات الطلب والاستجابة).

كيفية إنشاء تطبيق الآن؟


في الإصدار الثالث ، بدا إنشاء التطبيق مثل هذا:


 <?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(); 

الآن يقبل مُنشئ التطبيق المعلمات التالية:


معلمةنوعإلزاميوصف
$ استجابةالمصنعPsr\Http\Message\ResponseFactoryInterfaceنعمPSR-17 متوافق مع مصنع طلب خادم HTTP
حاوية $\Psr\Container\ContainerInterfaceلاحاوية التبعية
callableResolver $\Slim\Interfaces\CallableResolverInterfaceلارد الاتصال معالج
مسار الطريق\Slim\Interfaces\RouteCollectorInterfaceلاجهاز التوجيه
$ routeResolver\Slim\Interfaces\RouteResolverInterfaceلامعالج نتائج التوجيه

الآن يمكنك أيضًا استخدام طريقة create الثابتة لتطبيق factory \Slim\Factory\AppFactory .
تقبل هذه الطريقة نفس المعلمات كمدخلات ، وكلها فقط اختيارية.


 <?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(); 

أعطني 404 الأخطاء مرة أخرى!


إذا حاولنا فتح صفحة غير موجودة ، فسوف نحصل على رمز استجابة 500 ، وليس 404 . لكي تتم معالجة الأخطاء بشكل صحيح ، تحتاج إلى الاتصال \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(); 

الوسيطة


يجب أن تكون الوسيطة الآن تنفيذ PSR-15. كاستثناء ، يمكنك تمرير وظائف ، ولكن يجب أن يتطابق التوقيع مع الأسلوب process() الخاص \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(); 

التوقيع ($request, $response, $next) لم يعد مدعومًا


كيف تعيش من دون إعدادات؟


يمكنك العيش دون إعدادات. الأدوات المقدمة سوف تساعدنا في هذا.


httpVersion و responseChunkSize


كان httpVersion مسؤولاً عن إخراج إصدار البروتوكول في الاستجابة.
يحدد إعداد responseChunkSize حجم كل قطعة تتم قراءتها من نص الاستجابة عند إرسالها إلى المستعرض.


الآن يمكن تعيين هذه الوظائف إلى باعث الإجابة.


اكتب باعث


 <?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)); } } 

نحن نتصل بالتطبيق


 <?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


سمح هذا الإعداد تشغيل / إيقاف التخزين المؤقت الإخراج. تحديد القيم:


  • false - تم إيقاف تشغيل التخزين المؤقت (يتم تجاهل جميع المكالمات إلى echo ، يتم تجاهل عبارات print ).
  • 'append' - تتم إضافة جميع المكالمات إلى echo ، وتضاف بيانات print بعد هيئة الاستجابة
  • 'prepend' - جميع المكالمات إلى echo ، تتم إضافة بيانات print قبل هيئة الاستجابة

يقترح مطورو \Slim\Middleware\OutputBufferingMiddleware استبدال هذا الخيار \Slim\Middleware\OutputBufferingMiddleware ، في مُنشئ مُنشأة مصنع دفق متوافق مع PSR-17 ووضع يمكن أن يكون مساوياً prepend أو 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


أتاح هذا الإعداد الحصول على المسار الحالي من كائن الطلب في البرنامج الوسيط


يتم توفير بديل \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


يسمح الإعداد لعرض تفاصيل الخطأ. عند تصحيح الأخطاء ، فإنه يجعل الحياة أسهل.


تذكر \Slim\Middleware\ErrorMiddleware ؟ هنا سوف يساعدنا!


 <?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


يسمح هذا الإعداد بتمكين / تعطيل الإضافة التلقائية لرأس Content-Length مع قيمة حجم البيانات في نص الاستجابة


يستبدل خيار الوسيطة \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


يمكنك الآن تثبيت ملف ذاكرة التخزين المؤقت لجهاز التوجيه مباشرةً


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

إنشاء تطبيق على Slim-4


لإلقاء نظرة فاحصة على الإطار ، سنقوم بكتابة طلب صغير.


سيكون للتطبيق الطرق التالية:


  • /hello/{name} - صفحة الترحيب ؛
  • / - إعادة توجيه إلى الصفحة /hello/world
  • ستُرجع المسارات الأخرى صفحة مخصصة بها 404 أخطاء.

سيكون المنطق في وحدات التحكم ، وسوف نقدم الصفحة من خلال محرك قالب غصين
كمكافأة ، قم بإضافة تطبيق وحدة التحكم استنادًا إلى مكون Symfony Console باستخدام أمر يعرض قائمة من المسارات


الخطوة 0. تثبيت التبعيات


سنحتاج:



لقد اخترت فائقة الحاوية / الحاوية كحاوية تبعية ، وخفيفة الوزن وموجزة ومتوافقة مع المعيار.
يوفر مطورو PSR-7 و PSR-Slim ضئيلة / ضئيلة psr7 في حزمة واحدة. سوف نستخدمها


من المفترض أن مدير حزمة Composer مثبت بالفعل.

نقوم بإنشاء مجلد للمشروع (سيتم استخدام /path/to/project كمثال) وانتقل إليه.


أضف ملف composer.json إلى المشروع بالمحتويات التالية:


 { "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" } } } 

وتنفيذ الأمر


 composer install 

الآن لدينا جميع الحزم اللازمة ويتم تكوين autoloader الطبقة.


إذا عملنا مع git ، فأضف ملف .gitignore وأضف دليل vendor هناك (ودليل IDE الخاص بك إذا لزم الأمر)


 /.idea/* /vendor/* 

أنا أستخدم IDE PhpStorm و فخور به . لتطوير مريح ، حان الوقت لتكوين صداقات مع الحاوية و IDE.
في جذر المشروع ، قم بإنشاء ملف .phpstorm.meta.php واكتب التعليمة البرمجية التالية هناك:


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

\Psr\Container\ContainerInterface هذا الرمز IDE بأنه بالنسبة لكائن يقوم بتطبيق \Psr\Container\ContainerInterface ، ستُرجع طريقة get() كائن فئة أو تطبيق واجهة يتم تمرير اسمه في المعلمة.


الخطوة 1. إطار التطبيق


أضف الدلائل:


  • app - رمز التطبيق. سنقوم بتوصيل مساحة الاسم الخاصة بنا إلى autoloader الخاصة بها ؛
  • bin - دليل الأداة المساعدة وحدة التحكم؛
  • config - هنا ستكون ملفات تكوين التطبيق ؛
  • public - دليل تم فتحه على الويب (نقطة إدخال التطبيق ، الأنماط ، js ، الصور ، إلخ) ؛
  • دليل template ؛
  • var هو الدليل لمختلف الملفات. السجلات ، ذاكرة التخزين المؤقت ، التخزين المحلي ، إلخ.

والملفات:


  • config/app.ini - تهيئة التطبيق الرئيسية ؛
  • config/app.local.ini - التكوين للبيئة local ؛
  • app/Support/CommandMap.php - تعيين أوامر تطبيق وحدة التحكم للتحميل الكسول.
  • app/Support/Config.php - فئة التكوين (حتى يعرف IDE التكوينات التي لدينا).
  • app/Support/NotFoundHandler.php - 404 فئة معالج الأخطاء.
  • app/Support/ServiceProviderInterface.php - واجهة مزود الخدمة.
  • app/Provider/AppProvider.php - المزود الرئيسي للتطبيق.
  • bootstrap.php - تجميع الحاوية ؛
  • bin/console - نقطة الدخول لتطبيق وحدة التحكم ؛
  • public/index.php - نقطة إدخال تطبيق الويب.

التكوين / app.ini
 ;   slim.debug=Off ;   templates.dir=template ;   templates.cache=var/cache/template 

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

أوه نعم ، لا يزال من الجيد استبعاد تكوينات البيئة من المستودع. بعد كل شيء ، قد يكون هناك مظاهر / كلمات المرور. يتم استبعاد ذاكرة التخزين المؤقت أيضًا.


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

التطبيق / الدعم / 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; } } 

التطبيق / الدعم / 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; } } 

التطبيق / الدعم / 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; } } 

الآن يمكنك تعليم PhpStorm لفهم المفاتيح التي تحتوي على المفاتيح ونوعها.


.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', ]) ); } 

التطبيق / الدعم / ServiceProviderInterface.php
 <?php // app/Support/ServiceProviderInterface.php namespace App\Support; use UltraLite\Container\Container; interface ServiceProviderInterface { public function register(Container $container); } 

التطبيق / مقدم / 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)); }); } } 

لقد نقلنا التوجيه إلى الحاوية حتى نتمكن من العمل معها دون تهيئة الكائن \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; 

بن / وحدة التحكم
 #!/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()); 

من المستحسن إعطاء هذا الملف حقوق التنفيذ


 chmod +x ./bin/console 

public / 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); 

تحقق.
قم بتشغيل تطبيق وحدة التحكم:


 ./bin/console 

استجابة لذلك ، يجب أن تظهر نافذة الترحيب الخاصة بمكون symfony/console مع أمرين متاحين - help 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 

الآن ابدأ خادم الويب.


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

وفتح أي رابط على المضيف المحلي: 8080.
يجب أن ترجع جميع الطلبات استجابة بالكود 404 فارغ.
يحدث هذا لأنه ليس لدينا طرق مدرجة.


يبقى لنا أن نربط التقديم ، وكتابة القوالب ، وأجهزة التحكم وتحديد الطرق.


الخطوة 2. تقديم


أضف قالب template/layout.twig . هذا هو القالب الأساسي لجميع الصفحات.


القالب / 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> 

إضافة template/hello.twig صفحة الترحيب template/hello.twig


القالب / 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 %} 

template/err404.twig صفحة خطأ template/err404.twig


القالب / 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 %} 

أضف app/Provider/RenderProvider.php موفر التقديم app/Provider/RenderProvider.php


التطبيق / مقدم / 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; }); } } 

قم بتشغيل الموفر في bootstrap


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

أضف تجسيدًا إلى معالج الأخطاء 404


التطبيق / الدعم / NotFoundHandler.php (مهرجان دبي السينمائي الدولي)
 --- 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; } } 

التطبيق / المزود / AppProvider.php (مهرجان دبي السينمائي الدولي)
 --- 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/ar452834/


All Articles