データベース アクセスを別のクラスに移動すると、いくつかの利点が得られます。まず第一に、データベース アクセスを残りのロジックから分離しておくと、データベース アクセスの実装をより簡単に置き換えることができます。何らかの理由で Doctrine DBAL を削除したい場合は、すべてのコードがデータベースに直接クエリするのではなく、リポジトリへのインターフェイスを参照しているだけで十分です。
2 つ目の大きな利点は、データベース アクセス ロジックを分離してアプリケーション ロジックをテストできることです。UserService 内にユーザー用のリポジトリを挿入すると、テストでこれをモックして、実際のアプリケーション ロジックに問題がある場合にのみ失敗することを確認できます。
あなたができることの小さな例
インターフェイスは、コードベース全体で参照するのに便利です。コードは実装を参照せず、インターフェイスのみを参照します。そうすれば、使用されているすべての場所に触れることなく、インターフェイスの実装を簡単に置き換えることができます。
interface IUserRepository
{
/**
* @return User
*/
public function getUserById($userId);
}
もちろん、上記のインターフェースの実装が必要です。これは、UserService に注入するものです。これは、いつかインターフェイスの別の実装に置き換える可能性があるものです。
class DoctrineDBALUserRepository implements IUserRepository
{
/**
* @return User
*/
public function getUserById($userId)
{
//implementation specific for Doctrine DBAL
}
}
UserService はインターフェースのみを認識し、自由に使用できます。コード内の多くの場所に UserRepository を挿入する必要がないように、便利なビルド メソッドを作成できます。インターフェイスを参照するコンストラクターと、そのインターフェイスの実装を注入するビルド メソッドに注意してください。
class UserService
{
private $UserRepository;
public static build()
{
return new UserService(new DoctrineDBALUserRepository());
}
public function __construct(IUserRepository $UserRepository)
{
$this->UserRepository = $UserRepository;
}
public function getUserById($userId)
{
if ($User = $this->UserRepository->getUserById($userId) {
return $User;
}
throw new RuntimeException('O noes, we messed up');
}
これにより、ビジネス ロジックのテストを記述できます (保存に失敗した場合に例外をスローするなど)。
public function UserServiceTest extends PHPUnit_Framework_TestCase
{
public function testGetUserById_whenRetrievingFails_shouldThrowAnException()
{
$RepositoryStub = $this->getMock('IUserRepository');
$RepositoryStub->expects($this->any())->method('getUserById')->will($this->returnValue(false);
$UserService = new UserService($RepositoryStub);
$this->setExpectedException('RuntimeException');
$UserService->getUserById(1);
}
}
まだ単体テストを行っていないのであれば、コードの最後の部分に慣れていないことは想像に難くありません。私はあなたがそうであることを願っています。そうでない場合でも、それについても読むことをお勧めします:DIは、答えの完全性のために、何があってもそれを含めることは良いことだと考えました.