🥰

ビジネスサイドからの要望、全部入り管理画面、クソデカクエリ、何も起きないはずがなく。。。。

2022/04/23に公開

こんにちは tyamahori です。

普段はLaravelを使ってサービス開発しています。
タイトルですが、よくある依頼じゃないですか。。。?

全部入り管理画面、便利ですよね。わかります。
クエリでJoinたくさんしてますよね?わかります。
え、Joinはあまり使わないですか?そうですか。。。

Eloquent使ってますか?わかります。
tyamahoriはQueryBuilderを使ってます。

LaravelのQueryBuilderでは返り値がstdClassだったり、stdClassのコレクションだったりします。
今回は、stdClassを引数に、いい感じのDTOクラスを作ってみました!stdClassを色んな場所で使いまわしてしまうと不幸なってしまうと思ってます。。。

twitterでのあれこれ

mpywさん、medyさんありがとうございます!

medyさんが勧めてくれたHasura、便利そうです!ただ、今回の状況を加味したとき、導入に手間がかかってしまうので、今回はmpywさんのアイディアを参考にDTOクラスを作る方向でいきたいと思います。

Hasura新規プロジェクトで内部向けの管理画面では非常に役立ちそうです!

https://hasura.io/

コードサンプル

PHP8.1で書いてみました。

<?php

declare(strict_types=1);

namespace Package\SomeSpecificApplication\Common;

use Closure;
use stdClass;

class SomeQueryDto
{
    /**
     * @param stdClass $record
     */
    public function __construct(
        private readonly stdClass $record
    ) {
    }

    /**
     * データソースをもとに生成する
     * @param stdClass $record
     * @return SomeQueryDto
     */
    public static function createFromDataSource(
        stdClass $record
    ): SomeQueryDto {

        $specifications = self::validateDataSourceSpecifications();
        foreach ($specifications as $property => $closure) {
            assert(property_exists($record, $property));
            assert(is_callable($closure));
            assert($closure($record->{$property}));
        }

        return new self($record);
    }

    /**
     * @return Closure[]
     */
    private static function validateDataSourceSpecifications(): array
    {
        return [
            'item' => fn(mixed $value) => is_string($value) || is_null($value),
            'uuid' => fn(mixed $value) => is_string($value),
            'age' => fn(mixed $value) => is_int($value),
        ];
    }

    /**
     * @return string|null
     */
    public function getItem(): ?string
    {
        return $this->record->item;
    }

    /**
     * @return string
     */
    public function getUuid(): string
    {
        return $this->record->uuid;
    }

    /**
     * @return int
     */
    public function getAge(): int
    {
        return $this->record->age;
    }
}

考えたことなど

DTOの中身をチェックしています。stdClassに格納されているプロパティーとその型を見ています。
validateDataSourceSpecificationsメソッドにてチェックしたいプロパティをkeyにして、それに対応するチェックをクロージャーを使って実装してみました。

コメント待ってます!

より良いアイディアなどありましたらお気軽にコメントくださいー!色々と改善していければなと思ってます!

Discussion