Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Slimをオススメしてみる ControllerとContainer

gallu
April 13, 2023

Slimをオススメしてみる ControllerとContainer

gallu

April 13, 2023
Tweet

More Decks by gallu

Other Decks in Programming

Transcript

  1. Slimいいよ!!  https://www.slimframework.com/  Slim is a PHP micro framework

    that helps you quickly write simple yet powerful web applications and APIs.  Slim は、シンプルかつ強力な Web アプリケーションと API をすばやく作 成するのに役立つ PHP マイクロ フレームワークです。(Google)  Slimは、シンプルかつパワフルなWebアプリケーションやAPIを素早く作 成できるPHPマイクロフレームワークです。(DeepL)  Slimいいです!!  micro framework いいです!!  シンプルでいいです!!  っていう個人の感想と妄想を垂れ流してみます(笑
  2.  元 config/routes.php <?php declare(strict_types=1); use Psr¥Http¥Message¥ResponseInterface as Response; use

    Psr¥Http¥Message¥ServerRequestInterface as Request; // 初期に書いてあるルーティング $app->get('/hello/{name}', function (Request $request, Response $response, array $args) { $name = $args['name']; $response->getBody()->write("Hello, $name"); return $response; }); // 追加のルーティング $app->get('/', function (Request $request, Response $response, array $args) { $response->getBody()->write("Top Page"); return $response; });
  3.  config/routes.php <?php declare(strict_types=1); use Psr¥Http¥Message¥ResponseInterface as Response; use Psr¥Http¥Message¥ServerRequestInterface

    as Request; // 初期に書いてあるルーティング $app->get('/hello/{name}', ¥App¥Controller¥HelloController::class . ':index'); // 追加のルーティング $app->get('/', ¥App¥Controller¥HomeController::class);
  4.  app/Controller/HelloController.php <?php declare(strict_types=1); namespace App¥Controller; use Psr¥Http¥Message¥ServerRequestInterface as Request;

    use Psr¥Http¥Message¥ResponseInterface as Response; class HelloController { // 多分「よくある」系の書き方 public function index(Request $request, Response $response, $args) { $name = $args['name']; $response->getBody()->write("Hello, $name"); return $response; } }
  5.  app/Controller/HomeController.php <?php declare(strict_types=1); namespace App¥Controller; use Psr¥Http¥Message¥ServerRequestInterface as Request;

    use Psr¥Http¥Message¥ResponseInterface as Response; class HomeController { // 1クラスに「1つしかメソッドを書くつもりがない」場合、こういった書き方もできる public function __invoke(Request $request, Response $response, $args) { // 出力 $response->getBody()->write("Top Page"); return $response; } }
  6. Controllerとして許容される形式は?  https://www.slimframework.com/docs/v4/objects/routi ng.html#container-resolution 以降に大体書いてあるの ですが  $app->get('/', '¥HomeController:home'); 

    $app->get('/', ¥HomeController::class . ':home');  $app->get('/', [¥HomeController::class, 'home']);  $app->get('/', ¥HomeAction::class);  __invoke() メソッドがある場合  となります  あと実際には「関数」も通りますね
  7. その辺のコードをざっくり見てみましょう  vendor/slim/slim/Slim/CallableResolver.phpの超訳 private function resolveSlimNotation(string $toResolve): array { [$class,

    $method] = :で文字列をsplit(:なかったらmethodには null) if (containerがclassを持ってたら) { $instance = $this->container->get($class); インスタンスがobject以外なら例外を投げて終了 } else { if (クラスが存在していなかったら) { if (メソッドがnullじゃなければ) { $class .= '::' . $method . '()'; } $classないよ~、って例外をぶん投げて終了 } $instance = new $class($this->container); } return [$instance, $method]; }
  8. で……  vendor/slim/slim/Slim/CallableResolver.php public function resolve($toResolve): callable { $toResolve =

    $this->prepareToResolve($toResolve); if (is_callable($toResolve)) { return $this->bindToContainer($toResolve); } $resolved = $toResolve; if (is_string($toResolve)) { $resolved = $this->resolveSlimNotation($toResolve); $resolved[1] ??= '__invoke'; // 「メソッドなければnull」がここで効いてくる } $callable = $this->assertCallable($resolved, $toResolve); return $this->bindToContainer($callable); }
  9. Containerとは?  容器とか箱とか入れ物とか……じゃなくて「DIコンテナ」 の事です  $instance = new $class($this->container); 

    「何に使うか」は後回しにして、まずは「使える」ようにしま しょう  https://www.slimframework.com/docs/v4/concepts/di. html を参考に最低限書いてみる ……とエラーになるので必要なものを追加でinstall  Fatal error: Uncaught Error: Class "DI¥Container" not found  composer require php-di/slim-bridge
  10.  public/index.php <?php use Slim¥Factory¥AppFactory; use DI¥Container; require __DIR__ .

    '/../vendor/autoload.php'; // Create Container using PHP-DI $container = new Container(); // Set container to create App with on AppFactory AppFactory::setContainer($container); $app = AppFactory::create(); // ルーティングの読み込み require __DIR__ . '/../config/routes.php'; $app->run();
  11.  app/Controller/HomeController.php <?php declare(strict_types=1); namespace App¥Controller; use DI¥Container; use Psr¥Http¥Message¥ServerRequestInterface

    as Request; use Psr¥Http¥Message¥ResponseInterface as Response; class HomeController { public function __construct( private Container $container, ) { } // XXX 1クラスに「1つしかメソッドを書くつもりがない」場合、こういった書き方もできる public function __invoke(Request $request, Response $response, $args) { // 出力 var_dump($this->container ?? null); $response->getBody()->write("Top Page"); return $response; } }
  12.  app/Controller/HomeController.php <?php declare(strict_types=1); namespace App¥Controller; use Psr¥Http¥Message¥ServerRequestInterface as Request;

    use Psr¥Http¥Message¥ResponseInterface as Response; class HomeController extends BaseController { // XXX 1クラスに「1つしかメソッドを書くつもりがない」場合、こういった書き方もできる public function __invoke(Request $request, Response $response, $args) { // 出力 $response->getBody()->write("Top Page"); return $response; } }
  13. 余裕あったらおまけ  ところで、Slim-Skeleton、4.1.0から「Settings.php」とかっ てクラスが出来たんですねぇ。まぁ実装もシンプルだしこ れは便利かなぁ class Settings implements SettingsInterface {

    /** * @var array */ private $settings; /** * Settings constructor. * @param array $settings */ public function __construct(array $settings) { $this->settings = $settings; } /** * @param string $key * @return mixed */ public function get(string $key = '') { return (empty($key)) ? $this->settings : $this->settings[$key]; } }