baserCMSのアーキテクチャーは、CakePHP4の標準的なアーキテクチャーをベースにしており、さらに、ビジネスロジックをサービスに実装し、はDIコンテナを利用して注入する方針としています。
ビジネスロジックの実装は、テーブルクラスではなく、サービスクラスに実装し、コントローラーにおいては、テーブルクラスを直接利用することはせず、そのサービスクラスを利用します。
UsersService
)
Admin/UsersController
)
$this->set()
で引き渡すデータは、管理画面用のサービスクラスを作成し(例:UsersAdminService
)そのメソッドで一括で作成し、一括で引渡し、コントローラーが煩雑にならないようにするApi/UsersController
)
BcContainerTrait
を利用)
サービスクラスは、ユースケースを定義します。テーブルクラスと対になるクラスを用意してもよいですが、基本的には役割ごとに用意します。
最初は1つのクラスで実装を行い、肥大化に伴って、役割を分けクラスを分割します。
サービスクラスを作成する際は、まずインターフェイスを定義します。
// baser-core/src/Service/UsersServiceInterface.php
interface UsersServiceInterface
{
public function get(int $id): EntityInterface;
}
作成したインターフェイスを実装するようにサービスクラスを定義します。
// baser-core/src/Service/UsersService.php
class UsersService implements UsersServiceInterface
{
public function get(int $id): EntityInterface;
{
// 実装
}
}
なお、サービスクラスはできるだけ状態を持たないように実装します。
テーブルと対にしてサービスを提供する場合はエンティティの複数形にServiceを付け加えます。
User -> UsersService
利用するサービスはサービスプロバイダで定義します。
メンバー変数 provides
に利用するサービスのインターフェイスを定義し、services
メソッドにて、
DIコンテナを利用して、利用するサービスのインターフェイスごとに、実装するサービスクラスを追加します。
// baser-core/src/ServiceProvider/BcServiceProvider.php
class BcServiceProvider extends ServiceProvider
{
protected $provides = [
UsersServiceInterface::class
];
public function services($container): void
{
$container->add(UsersServiceInterface::class, UsersService::class);
}
}
コントローラーでは、引数に利用したいサービスのインターフェイスを定義すると、
サービスプロバイダで定義したサービスクラスを利用できます。
// baser-core/src/Controller/Admin/UsersController.php
class UsersController extends BcAdminAppController
{
public function index(UsersServiceInterface $service)
{
// 処理を記載
}
}
コントローラーではビジネスロジックをできるだけ実装せず、サービスクラスに実装して、それを利用します。
また、コントローラー内ではテーブルクラスを直接利用せつ、サービスクラスに利用する処理を実装し、そちらを利用するようにします。
コントローラーからビューに変数を引き渡す場合は、コントローラーの処理が煩雑とならないよう、管理画面用のサービスクラスを作成し、そこで一括で生成した上で、一括で $this->set()
に渡すようにします。
サービスに実装することで、引き渡す変数の明示化を行い、テスタブルなコードを目指します。
// /baser-core/src/Service/UsersAdminService.php
class UsersAdminService extends UsersService
{
public function getViewVarsForIndex()
{
return [
'users' => $this->getIndex()
];
}
}
// /baser-core/src/Controller/Admin/UsersController.php
class UsersController extends BcAdminAppController
{
public function index(UsersAdminService $service)
{
$this->set($service->getViewVarsForIndex());
}
}
ヘルパーについては、適宜必要となるサービスクラスを利用することもできます。
CakePHP4では、ヘルパでDIコンテナが利用できませんので、代替措置として BcContainerTrait
を利用します。
// baser-core/src/View/Helper/BcAdminUserHelper.php
class BcAdminUserHelper extends Helper
{
use \BaserCore\Utility\BcContainerTrait;
public $UsersService;
public function initialize(array $config)
{
parent::initialize($config);
$this->UsersService = $this->getService(UsersServiceInterface::class)
}
public function get($id)
{
$this->UsersService->get($id);
}
}
APIは、コントローラーからサービスクラスを呼び出し実装します。
BcAdminApiController
を継承することによりJWT認証がかかる仕様となっています。
// baser-core/src/Controller/Api/Admin/UsersController.php
class UsersController extends BcAdminApiController
{
public function index(UsersServiceInterface $users)
{
// 実装
}
}