絶賛炎上プロジェクトで毎日ひぃひぃ言ってるゆきねこです。
現在、会社ではDBの操作をリポジトリパターンで書いているのですが、開発する中でミスったなと感じたり汚いなと感じることがあったので、どうしたら綺麗に開発していけるか考えたので書いていきたいと思います。
問題点
そもそも、今までORマッパーを使った開発ってしたことなかったんですよね。
独自FWでSQLは生で書いてたり、NoSQLだけだったり…
そんなわけで、最初どのぐらいの粒度で関数を作成したらわかんなかったんですよね。
なるべく共通化するべきか、それとも用途ごとに関数を作成した方がいいのか。
解決策
悶々と考えていて、結構こうしたらいいなって考えがまとまったので、紹介しようと思います。
まず、ベースのトレイトに共通で使用できる関数を記載していきます。
そして、各リポジトリはトレイトを使用して、各レポジトリ独自の関数はリポジトリに書いていきます。
こうすることで基本的なfindやupdateなどの関数をまとめます。
baseトレイト
実際にコードを書くと以下のような感じです。
trait baseRepositoryTrait
{
public function find($id)
{
return $this->model->find($id);
}
public function findOrFail($id)
{
return $this->model->findOrFail($id);
}
public function first(array $params)
{
$model = $this->model;
foreach ($params as $key => $value) {
$model = $model->where($key, $value);
}
return $model->first();
}
public function firstOrFail(array $params)
{
$model = $this->model;
foreach ($params as $key => $value) {
$model = $model->where($key, $value);
}
return $model->firstOrFail();
}
public function search(array $params)
{
$model = $this->model;
foreach ($params as $key => $value) {
$model = $model->where($key, $value);
}
return $model->firstOrFail();
}
}
データをIDで取得する際にはfindとfindOrFailのメソッドがありますが、詳細画面などで使用する際にはfindOrFail、ロジックなどでデータを取得する場合はなくてもいい場合はfindなど、それぞれの用途があるのでそのまま描いていきます。
firstとfirstOrFailは一対多のデータモデルで条件で絞り込んで1件だけ取得したい際に使います。
そのため、条件によって絞り込みたいので配列で渡された値をforeach文絞り込みます。
こんな感じでinsertやupdate、deleteを書いていきます。
個別のリポジトリ
次は個別のリポジトリを書いていきます。
取りあえすユーザで書いてみました。
class userRepository
{
use baseRipositoryTrait;
private $model;
private function __construct(User $model)
{
$this->model = $model;
}
public function findWithOrganization(int $id)
{
return $this->model->with('organization')->find($id);
}
}
リレーションなどは共通化出来ないので個別リポジトリに描いていきます。
あと、関数名はユースケースで書くよりも関数の説明で書く方が使い回しができるので、その方がいいですかね。
ベースリポジトリを継承する方法を記載していましたが、実装してみたら動かなかったのでtraitを使うように修正しました。
0件のコメント