私は Doctrine の大ファンですが、これまでは主に自分のデータベースにアクセスするためのより簡単でオブジェクト指向の方法として Doctrine を使用していました。最近では、コードをよりセマンティックまたは論理的で使いやすいものにするために、モデルをもっと使いたいと思っていることに気付きました。
例として、スタック オーバーフローの質問と対応する回答を使用してみましょう。質問には、1 つ以上の回答を含めることができます。過去に、私はこのようなことをするかもしれません (以下はすべて sudo コードです):
/*
* METHOD ONE: Note that this is IMO not that semantic or OO
*/
Class QuestionController{
//.......
public function addAnswer($whichQuestionId, $answerTitle, $answerCopy, $answerAuthorId)
{
//Look, I'm validating stuff here in my controller action
if(!strlen($answerTitle) || !strlen($answerCopy) || !strlen($answerAuthorId))
throw new \Exception('Invalid answer stuff!!');
//Notice here I'm actually doing some DB quering with
$author = $entityManager->find('\StackOverflow\User', $answerAuthorId);
if($author->getIsBanned())
throw new \Exception('This is user can not post answer, they are banned!');
//OK, things are valid, now we're going to load then question and create a new answer
$question = $entityManager->find('\StackOverflow\Question', $whichQuestionId)
$answer = new \StackOverflow\Answer;
$answer->setAuthor($author);
$answer->setTitle($answerTitle);
$answer->setContent($answerCopy);
$question->addAnswer($answer);
//Let's pretend we persisted everything correctly...
//Done!
}
//.......
}
Class \StackOverflow\Answer{
//Normal auto generated stuff here
}
Class \StackOverflow\Qusetion{
//Normal auto generated stuff here
}
OK、コントローラーアクションですべての検証を行っていることに注意してください. この検証ロジックをある種の「ヘルパー」に入れることもできますが、それも特にオブジェクト指向ではないようです。
私はむしろこのようなことをしたいと思います(完全にうまくいくわけではありませんが、うまくいけばアイデアが得られます)
/*
* METHOD TWO: Hopefully a bit more OO...
*/
Class QuestionController{
public function addAnswer($whichQuestionId, $answerTitle, $answerCopy, $answerAuthorId)
{
$result = new \stdObject();
try{
$question = $entityManager->find('\StackOverflow\Question', $whichQuestionId);
$answer = new \StackOverflow\Answer;
$answer->setAuthor($author);
$answer->setTitle($answerTitle);
$answer->setContent($answerCopy);
//THIS IS NEW!
$answer->validate();
//note that perhaps to take this a step futher, in the \StackOverflow\Question class
//I might actually call the validate function, so it's a bit more transaparent
$question->addAnswer($answer);
//Let's pretend we persisted everything correctly...
//Done!
$result->success = true;
$result->message = 'New answer added!';
}
catch(Exception $e)
{
$result->success = false;
$result->message = $e->getMessage();
}
return json_encode($result);
}
}
Class \StackOverflow\Answer{
//ALL NORMAL AUTO GENERATED GETTERS/SETTERS/ETC HERE
//CUSTOM FUNCTION - perhaps called by one of the LifeCycle callback things that Doctrine has?
public function validate()
{
//Look, I'm validating stuff here in my controller action
if(!strlen($this->getTitle()) || !strlen($this->getContent()) || !strlen($this->getAuthor()))
throw new \Exception('Invalid answer stuff!!');
//Notice here I'm actually doing some DB quering INSIDE of another model
$author = $entityManager->find('\StackOverflow\User', $answerAuthorId);
if($author->getIsBanned())
throw new \Exception('This is user can not post answer, they are banned!');
}
}
Class \StackOverflow\Question{
//Normal auto generated stuff here
}
ですから、これはおそらくもう少し良いと思いますが、これは Doctrine で物事を行う正しい方法ですか? 既存のモデル内で他のモデルを呼び出したり、Doctrine Entity Manager をこのように使用しても問題ありませんか? これを行うよりクリーンな方法はありますか?
この特定の例は非常に単純ですが、実際にはこれに似た関係がありますが、「回答」にははるかに複雑で醜い検証があり、他のテーブルへのルックアップが必要で、検証のために「質問」に関する情報を取得する必要があります。たとえば、質問に新しい回答を追加すると、ユーザーの「QuestionsAnswered」値が更新される場合があります。私はむしろ、これが実際に起こっていることを知らなくても、透過的に起こることを望んでいます. 単純に質問に回答を追加したいのですが、すべての検証とカスケード変更が舞台裏で自動的に行われます。