tacddd/tacddd

ProjectICKX Tactical DDD library

0.0.20 2023-12-28 11:12 UTC

This package is auto-updated.

Last update: 2024-04-28 11:47:07 UTC


README

TacDDD(タックディー)は戦術的DDDの迅速な立ち上げを支援するためのPHPテンプレートパッケージです。

対象となるバージョンはPHP8.2.0以上です。

collections

兎に角に何もせずコレクションから有用な値を引き出す事に特化した特性を用意しています。

entity collection

次の特性を使う事により、容易に任意の階層構造として値を取り出すことができます。

use tacddd\collections\objects\traits\ObjectCollectionInterface;
use tacddd\collections\objects\traits\ObjectCollectionTrait;

// 仮にエンティティのコレクションとする
final class EntityCollection implements ObjectCollectionInterface
{
    use ObjectCollectionTrait;

    // このコレクションが受け入れるクラスやインターフェースの設定
    public static function getAllowedClass(): string
    {
        return Entity::class;
    }

    // 受け入れた値(オブジェクト)からユニークなキーを返す
    public static function createUniqueId(mixed $value): string|int
    {
        return $value->getId();
    }
}

対象が値オブジェクトを持ちgetterから取得した値から直接string|intを引けない場合は、次のnormalizeKeyも追加してください。

   /**
     * キーがstring|intではなかった場合に調整して返します。
     *
     * @param  mixed       $key        キー
     * @param  null|string $access_key アクセスキー
     * @return string|int  調整済みキー
     */
    public static function normalizeKey(mixed $key, ?string $access_key = null): string|int
    {
        // 値オブジェクトが仮にpublic readonly string $value;を持つ場合
        if (\is_object($key)) {
            return $key->value;
        }
    }

Entityクラスが次のインターフェースを持っていた場合、その後に続くデータアクセスが可能となります。

final class Entity
{
    public function __construct(
        private int $id,
        private string $group,
        private string $name,
    )
    {}

    public function getId()
    {
        return $this->id;
    }

    public function getGroup()
    {
        return $this->group;
    }

    public function getName()
    {
        return $this->name;
    }
}
$entityCollection = new EntityCollection();

$alpha  = new Entity(1, 'alpha', 'いろは');
$entityCollection->add($alpha);

$bravo  = new Entity(2, 'bravo', 'にほへ');
$entityCollection->add($bravo);

$charley    = new Entity(3, 'bravo', 'とちり');
$entityCollection->add($charley);

$entityCollection->find(1); // $alphaを取得できる

$entityCollection->findBy(['name' => 'bravo']); // [$bravo, $charley]を取得できる

グルーピングした結果を取得したい場合は、toMapメソッドを利用してください。

$entityCollection->toMap(['group', 'name', 'id']); // 次の形式の配列を取得できる
/*
[
    'alpha' => [
        'いろは'    => [
            1   => [
                $alpha
            ],
        ]
    ],
    'bravo' => [
        'にほへ'    => [
            2   => [
                $bravo
            ],
        ],
        'とちり'    => [
            3   => [
                $charley
            ],
        ],
    ],
]
*/

末端が単一要素なグルーピングした結果を取得したい場合は、toOneMapメソッドを利用してください。

$entityCollection->toOneMap(['group', 'name', 'id']); // 次の形式の配列を取得できる
/*
[
    'alpha' => [
        'いろは'    => [
            1   => $alpha,
        ]
    ],
    'bravo' => [
        'にほへ'    => [
            2   => $bravo,
        ],
        'とちり'    => [
            3   => $charley,
        ],
    ],
]
*/

値だけの配列としてグルーピングした結果を取得したい場合は、toArrayMapメソッドを利用してください。

$entityCollection->toArrayMap(['group', 'name', 'id']); // 次の形式の配列を取得できる
/*
[
    'alpha' => [
        'いろは'    => [
            1   => [
                [
                    'group' => 'alpha',
                    'name'  => 'いろは',
                    'id'    => 1,
                ],
            ],
        ]
    ],
    'bravo' => [
        'にほへ'    => [
            2   => [
                [
                    'group' => 'bravo',
                    'name'  => 'にほへ',
                    'id'    => 2,
                ],
            ],
        ],
        'とちり'    => [
            3   => [
                [
                    'group' => 'bravo',
                    'name'  => 'とちり',
                    'id'    => 3,
                ],
            ],
        ],
    ],
]
*/

値だけの配列として第一要素だけをグルーピングした結果を取得したい場合は、toArrayOneMapメソッドを利用してください。

$entityCollection->toArrayOneMap(['group', 'name', 'id']); // 次の形式の配列を取得できる
/*
[
    'alpha' => [
        'いろは'    => [
            1   => [
                'group' => 'alpha',
                'name'  => 'いろは',
                'id'    => 1,
            ],
        ]
    ],
    'bravo' => [
        'にほへ'    => [
            2   => [
                'group' => 'bravo',
                'name'  => 'にほへ',
                'id'    => 2,
            ],
        ],
        'とちり'    => [
            3   => [
                'group' => 'bravo',
                'name'  => 'とちり',
                'id'    => 3,
            ],
        ],
    ],
]
*/

値だけのマップとしてグルーピングした結果を取得したい場合は、getArrayMapメソッドを利用してください。

$entityCollection->getArrayMap(['id']); // 次の形式の配列を取得できる
/*
[
    1   => 1,
    2   => 2,
    3   => 3,
]
*/

第二引数を利用することで値を変更することもできます。

$entityCollection->getArrayMap(['group', 'name', 'id'], 'name'); // 次の形式の配列を取得できる
/*
[
    'alpha' => [
        'いろは'    => [
            1   => 'いろは',
        ]
    ],
    'bravo' => [
        'にほへ'    => [
            2   => 'にほへ',
        ],
        'とちり'    => [
            3   => 'とちり',
        ],
    ],
]
*/

第二引数にコールバックを指定することで様々な変更も実施できます。

$entityCollection->getArrayMap(['group', 'name', 'id'], function (
    Entity $entity,
    array $access_key_cache,
): int|string {
    return $entity->getName();
}); // 次の形式の配列を取得できる
/*
[
    'alpha' => [
        'いろは'    => [
            1   => 'いろは',
        ]
    ],
    'bravo' => [
        'にほへ'    => [
            2   => 'にほへ',
        ],
        'とちり'    => [
            3   => 'とちり',
        ],
    ],
]
*/

magical access entity collection

次の特性を追加する事により、メソッドとして自明的なアクセスも可能になります。

use tacddd\collections\objects\traits\ObjectCollectionInterface;
use tacddd\collections\objects\traits\ObjectCollectionTrait;
use tacddd\collections\objects\traits\magical_accesser\ObjectCollectionMagicalAccessorInterface;
use tacddd\collections\objects\traits\magical_accesser\ObjectCollectionMagicalAccessorTrait;

final class MagicalEntityCollection implements
    ObjectCollectionInterface,
    ObjectCollectionMagicalAccessorInterface
{
    use ObjectCollectionTrait;
    use ObjectCollectionMagicalAccessorTrait;

    // このコレクションが受け入れるクラスやインターフェースの設定
    public static function getAllowedClass(): string
    {
        return Entity::class;
    }

    // 受け入れたオブジェクトからユニークなキーを返す
    public static function createUniqueId(mixed $value): string|int
    {
        return $value->getId();
    }
}

次のように引数に引きずられる事なくアクセスができます。

$entityCollection = new EntityCollection();

$alpha  = new Entity(1, 'alpha', 'いろは');
$entityCollection->add($alpha);

$bravo  = new Entity(2, 'bravo', 'にほへ');
$entityCollection->add($bravo);

$charley    = new Entity(3, 'bravo', 'とちり');
$entityCollection->add($charley);

$entityCollection->findOneByName('alpha'); // $alphaを取得できる

$entityCollection->findByName('bravo'); // [$bravo, $charley]を取得できる

$entityCollection->toMapInGroupInNameInId(); // 次の形式の配列を取得できる
/*
[
    'alpha' => [
        'いろは'    => [
            1   => [
                $alpha
            ],
        ]
    ],
    'bravo' => [
        'にほへ'    => [
            2   => [
                $bravo
            ],
        ],
        'とちり'    => [
            3   => [
                $charley
            ],
        ],
    ],
]
*/

$entityCollection->toOneMapInGroupInNameInId(); // 次の形式の配列を取得できる
/*
[
    'alpha' => [
        'いろは'    => [
            1   => $alpha,
        ]
    ],
    'bravo' => [
        'にほへ'    => [
            2   => $bravo,
        ],
        'とちり'    => [
            3   => $charley,
        ],
    ],
]
*/

その他、前述のメソッドは次の形で代替できます。

// 次の二つは等価
$entityCollection->toArrayMap(['group', 'name', 'id']);
$entityCollection->toArrayMapOfGroupAndNameAndId();

// 次の二つは等価
$entityCollection->toArrayOneMap(['group', 'name', 'id']);
$entityCollection->toArrayOneMapOfGroupAndNameAndId();

// 次の二つは等価
$entityCollection->getArrayMap(['id']);
$entityCollection->getArrayMapOfId();

// 次の二つは等価
$entityCollection->getArrayMap(['group', 'name', 'id'], 'name');
$entityCollection->getArrayMapOfGroupAndNameAndId('name');

// 次の二つは等価
$entityCollection->getArrayMap(['group', 'name', 'id'], function (
    Entity $entity,
    array $access_key_cache,
): int|string {
    return $entity->getName();
});
$entityCollection->getArrayMapOfGroupAndNameAndId(function (
    Entity $entity,
    array $access_key_cache,
): int|string {
    return $entity->getName();
});

collection factory

コレクションクラスを作るのが手間。わかります。

ファクトリ経由の無名クラスとしてコレクションの生成が可能です。

受け入れ可能クラスとユニークIDの指定のみは流石に記述が必要です。

use tacddd\collections\CollectionFactory;

$collection = CollectionFactory::createForObject(
    class           : Entity::class,
    createUniqueId  : function(mixed $value): string|int {
        return $value->getId();
    },
    objects         : [
        new Entity(1, 'alpha', 'いろは'),
        new Entity(2, 'bravo', 'にほへ'),
    ]
);

クロージャだと要求が明確にならないので不安という方はUniqueIdFactoryInterfaceをご利用ください。

use tacddd\collections\CollectionFactory;
use tacddd\collections\interfaces\UniqueIdFactoryInterface;

$collection = CollectionFactory::createForObject(
    class           : Entity::class,
    createUniqueId  : new class() implements UniqueIdFactoryInterface {
        public static function createUniqueId(mixed $value): string|int
        {
            return $value->getId();
        }
    },
    objects         : [
        new Entity(1, 'alpha', 'いろは'),
        new Entity(2, 'bravo', 'にほへ'),
    ],
);

tips

とりあえずuniqueも何も関係なくオブジェクトを投入したい場合は、ユニークIDの抽出にspl_object_idを利用してみてください。

        public static function createUniqueId(mixed $value): string|int
        {
            return \spl_object_id($value);
        }