저는 Laravel 4를 사용하여 대규모 프로젝트를 마무리하고 있으며 지금 당장 질문하는 모든 질문에 답해야했습니다. Leanpub에서 사용 가능한 모든 Laravel 책과 수많은 인터넷 검색을 읽은 후 다음 구조를 생각해 냈습니다.
- 데이터 가능한 테이블 당 하나의 Eloquent 모델 클래스
- Eloquent 모델 당 하나의 리포지토리 클래스
- 여러 저장소 클래스간에 통신 할 수있는 서비스 클래스입니다.
그래서 제가 영화 데이터베이스를 만들고 있다고 가정 해 봅시다. 최소한 다음과 같은 Eloquent Model 클래스가 있습니다.
저장소 클래스는 각 Eloquent Model 클래스를 캡슐화하고 데이터베이스에서 CRUD 작업을 담당합니다. 저장소 클래스는 다음과 같습니다.
- MovieRepository
- StudioRepository
- DirectorRepository
- ActorRepository
- ReviewRepository
각 저장소 클래스는 다음 인터페이스를 구현하는 BaseRepository 클래스를 확장합니다.
interface BaseRepositoryInterface
{
public function errors();
public function all(array $related = null);
public function get($id, array $related = null);
public function getWhere($column, $value, array $related = null);
public function getRecent($limit, array $related = null);
public function create(array $data);
public function update(array $data);
public function delete($id);
public function deleteWhere($column, $value);
}
서비스 클래스는 여러 저장소를 함께 연결하는 데 사용되며 응용 프로그램의 실제 "비즈니스 논리"를 포함합니다. 컨트롤러 는 만들기, 업데이트 및 삭제 작업을 위해 서비스 클래스와 만 통신합니다.
따라서 데이터베이스에 새 Movie 레코드를 만들려면 MovieController 클래스에 다음 메서드가있을 수 있습니다.
public function __construct(MovieRepositoryInterface $movieRepository, MovieServiceInterface $movieService)
{
$this->movieRepository = $movieRepository;
$this->movieService = $movieService;
}
public function postCreate()
{
if( ! $this->movieService->create(Input::all()))
{
return Redirect::back()->withErrors($this->movieService->errors())->withInput();
}
// New movie was saved successfully. Do whatever you need to do here.
}
컨트롤러에 데이터를 POST하는 방법은 사용자가 결정하지만 postCreate () 메서드에서 Input :: all ()이 반환 한 데이터가 다음과 같다고 가정 해 보겠습니다.
$data = array(
'movie' => array(
'title' => 'Iron Eagle',
'year' => '1986',
'synopsis' => 'When Doug\'s father, an Air Force Pilot, is shot down by MiGs belonging to a radical Middle Eastern state, no one seems able to get him out. Doug finds Chappy, an Air Force Colonel who is intrigued by the idea of sending in two fighters piloted by himself and Doug to rescue Doug\'s father after bombing the MiG base.'
),
'actors' => array(
0 => 'Louis Gossett Jr.',
1 => 'Jason Gedrick',
2 => 'Larry B. Scott'
),
'director' => 'Sidney J. Furie',
'studio' => 'TriStar Pictures'
)
MovieRepository는 데이터베이스에서 Actor, Director 또는 Studio 레코드를 생성하는 방법을 몰라 야하므로 MovieService 클래스를 사용할 것입니다. 다음과 같은 모습 일 수 있습니다.
public function __construct(MovieRepositoryInterface $movieRepository, ActorRepositoryInterface $actorRepository, DirectorRepositoryInterface $directorRepository, StudioRepositoryInterface $studioRepository)
{
$this->movieRepository = $movieRepository;
$this->actorRepository = $actorRepository;
$this->directorRepository = $directorRepository;
$this->studioRepository = $studioRepository;
}
public function create(array $input)
{
$movieData = $input['movie'];
$actorsData = $input['actors'];
$directorData = $input['director'];
$studioData = $input['studio'];
// In a more complete example you would probably want to implement database transactions and perform input validation using the Laravel Validator class here.
// Create the new movie record
$movie = $this->movieRepository->create($movieData);
// Create the new actor records and associate them with the movie record
foreach($actors as $actor)
{
$actorModel = $this->actorRepository->create($actor);
$movie->actors()->save($actorModel);
}
// Create the director record and associate it with the movie record
$director = $this->directorRepository->create($directorData);
$director->movies()->associate($movie);
// Create the studio record and associate it with the movie record
$studio = $this->studioRepository->create($studioData);
$studio->movies()->associate($movie);
// Assume everything worked. In the real world you'll need to implement checks.
return true;
}
그래서 우리가 남긴 것은 멋지고 현명한 관심사 분리입니다. 리포지토리는 데이터베이스에서 삽입하고 검색하는 Eloquent 모델 만 인식합니다. 컨트롤러는 리포지토리에 신경 쓰지 않고 사용자로부터 수집 한 데이터를 전달하여 적절한 서비스에 전달합니다. 서비스는 수신 한 데이터가 데이터베이스에 저장되는 방식을 신경 쓰지 않고 컨트롤러가 제공 한 관련 데이터를 적절한 저장소로 넘깁니다.