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

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

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for gallu gallu
April 13, 2023

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

Avatar for gallu

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]; } }