본격적으로 Laravel을 이용하여 각 계층을 어떤 식으로 사용하는지 실습해보려 한다.
기본적인 예제만 다룰 예정이므로 회원 정보를 조회하는 로직을 예제로 사용한다.
필자는 아래와 같은 방법으로 사용했다.
(파일명과 파일경로는 자유이므로 꼭 필자의 경로와 같이 사용하지 않아도 무방하다.)
app
ㄴ Http
ㄴ Controllers
ㄴ Models
ㄴ Services
ㄴ Repositoies
ㄴ Interfaces
작업은 가장 먼저 제일 많이 사용되는 매서드 들을 추상화 시킬 예정이다.
app/Interfaces/BaseInterface.php
<?php
namespace App\Interfaces\Interfaces;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
interface BaseInterface
{
/**
* @return Collection
*/
public function all(): Collection;
/**
* @param int $id
* @return Model
*/
public function findId(int $id): Model;
/**
* @param array $data
* @return Model
*/
public function create(array $data = []): Model;
/**
* @param array $data
* @return bool
*/
public function update(array $data = []): bool;
/**
* @param array $data
* @return bool
*/
public function delete(array $data = []): bool;
}
해당 내용은 가장 기본적으로 사용되는 ORM
의 매서드를 추상화 시키는 과정이다.
해당 패턴에 관련해서는 디자인 패턴(Factory Method Pattern)을 공부하는 걸 추천한다.
다음은 구현 클래스를 작성할 차례다.
app/Repositories/BaseRepository.php
<?php
namespace App\Repositories;
use App\Interfaces\BaseInterface;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
class BaseRepository implements BaseInterface
{
private Model $model;
public function __construct(Model $model)
{
$this->model = $model;
}
/**
* @param array $columns
* @param array $relations
* @return : Collection
*/
public function all(array $columns = ['*'], array $relations = []): Collection
{
return $this->model->get($columns);
}
/**
* @param int $id
* @param array $columns
* @return Model
*/
public function findId(int $id, array $columns = ['*'], array $relations = []): Model
{
return $this->model->find($id, $columns);
}
/**
* @param array $data
* @return Model
*/
public function create(array $data = []): Model
{
return $this->model->create($data);
}
/**
* @param array $data
* @return bool
*/
public function update(array $data = []): bool
{
return $this->model->update($data);
}
/**
* @param array $data
* @return bool
*/
public function delete(array $data = []): bool
{
return $this->model->delete($data);
}
}
해당 BaseRepository는 BaseInterface를 다중 상속(implements) 하고 있다.
이러한 경우 추상화되어있는 부모의 메소드를 반드시 재정의(Override) 해야 한다.
구현체에 매서드를 사용하기 위해서는 인터페이스를 바인딩 해야 한다. Laravel의 컨테이너를 이용하면 인터페이스와 구현체를 쉽게 인스턴스화 할 수 있다.
필자는 관리 중인 Repository를 한 파일에서 관리하기 위해 따로 파일을 생성할 예정이다.
php artisan make:provider RepositoryServiceProvider
Config/app.php
'providers' => [
App\Providers\RepositoryServiceProvider::class,
]
까지 등록을 해준다. 그리고 생성된 파일에 인터페이스를 바인딩 한다.
app/Providers/RepositoryServiceProvider.php
<?php
namespace App\Providers;
use App\Repositories\Eloquent\BaseRepository;
use App\Repositories\Interfaces\BaseInterface;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
$this->app->bind(BaseInterface::class, BaseRepository::class);
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
//
}
}
기본적인 추상화 과정은 끝났다. 다음 포스팅에서는 해당 매서드들과 추가적인 매서드를 통해서 회원 조회를 하는 로직을 완성해보자.
참고 자료
https://vuxy.tistory.com/entry/Laravel-8-%EC%97%90%EC%84%9C-Repository-%ED%8C%A8%ED%84%B4-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
https://blog.decorus.io/php/2018/07/04/laravel-dependency-injection-container.html