リクエストオブジェクトに、パラメータを値オブジェクトに変換するメソッドを追加する。

このようなコーディングを実現します。値オブジェクトの生成をコントローラーに書く必要がなくなります。

<?php
$startDate = $request->dateParam('startData');

PHPだと、HTTPリクエストのインターフェースはPSR-7で決まっています。

PSR-7: HTTP message interfaces - PHP-FIG

必要最低限しかメソッドがないため、私は独自にヘルパーメソッドを追加しています。今回使用するベースクラスはzendframework/zend-diactorosのServerRequestクラスです。

<?php
declare(strict_types=1);

use Zend\Diactoros\ServerRequest;

final class MyServerRequest extends ServerRequest
{
    public function param(string $name, $default = null)
    {
        return $this->getParsedBody()[$name] ??
            $this->getQueryParams()[$name] ??
            $default;
    }

    public function hasParam(string $name) : bool
    {
        return isset($this->getParsedBody()[$name]) || isset($this->getQueryParams()[$name]);
    }

    public function intParam(string $name): ?int
    {
        if (!$this->hasParam($name)) {
            return null;
        }
        return is_int($this->param($name));
    }

    public function boolParam(string $name): bool
    {
        $value = $this->param($name);
        $trues = [true, 1, '1', 'true', 'yes', 'ok'];
        return in_array($value, $trues, true);
    }
}

HTTPリクエストがGETかPOSTを気にせず取得できるparamメソッドを用意しました。このメソッドをラップして、戻り値の型を変換して返すヘルパーメソッドも用意しています。

boolParamを使えば、truthyな値をboolに変換できます。プロジェクトの立ち上げ時なら、値は[true, 1, ...]ではなく、1つに統一すれば良いかもしれません。boolParamが後付なら、このように色々な値をboolに統一していくことができます。

この値の統一ですが、プリミティブ値以外に値オブジェクトを返すヘルパーメソッドを用意すると、さらに便利だなと思いました。

<?php

public function dateParam(string $name, string $defaultDate = null): ?Carbon
{
    $value = $this->param($name);
    if (empty($value)) {
        if (is_null($defaultDate)) {
            return null;
        }
        $value = $defaultDate;
    }

    // a:「全角」英数字を「半角」に変換(コロンも対象)
    // s:「全角」スペースを「半角」に変換(U+3000 -> U+0020)
    $value = mb_convert_kana($value, 'as');
    $value = str_replace('', '-', $value);
    try {
        return new Carbon($value);
    } catch (UnexpectedValueException $e) {
        return null;
    } catch (InvalidDateException $e) {
        return null;
    } catch (Exception $e) {
        return null;
    }
}

public function pageParam(): Page
{
    $value = $this->intParam('page') ?: 1;
    if ($value < 1) {
        $value = 1;
    }
    return new Page($value);
    }
}

Pageはページ数の値オブジェクトです。引数でkeyを渡すをやめて、メソッド内でハードコードすれば全体で統一できます。

コントローラを増やしていくたびに、徐々に追加していくとスッキリするでしょう。特定ページでしか使わない固有の値は、paramメソッドでその場で生成すれば良いと思います。

param系のメソッドは数が多くなると思うのでトレイトでまとめておくと良いかもしれません。