ここ数日、より良いプログラマーになれるように、PHP の OOP と MVC に関する書籍や Web ページを幅広く読みました。MVC の理解に少し問題がありました。
どこに置くのmysql_query
ですか?
それをコントローラーに入れて、提供されたクエリに基づいてデータを返すモデルのメソッドを呼び出す必要がありますか? それとも、モデル自体に入れる必要がありますか?私が提供しているオプションは両方ともゴミですか?
ここ数日、より良いプログラマーになれるように、PHP の OOP と MVC に関する書籍や Web ページを幅広く読みました。MVC の理解に少し問題がありました。
どこに置くのmysql_query
ですか?
それをコントローラーに入れて、提供されたクエリに基づいてデータを返すモデルのメソッドを呼び出す必要がありますか? それとも、モデル自体に入れる必要がありますか?私が提供しているオプションは両方ともゴミですか?
MVC に触れているほとんどの (すべてではないにしても) php の本は間違っているため、読んでいた本をリストすることもできます。
より優れた開発者になりたい場合は、Marting Fowler の記事 - GUI Architecturesから始めることをお勧めします。続いて同じ著者の本「エンタープライズ アプリケーション アーキテクチャのパターン」。次のステップは、 SOLID の原則を研究し、デメテルの法則に従うコードの書き方を理解することです。これは基本をカバーする必要があります=]
あまり。少なくともSmalltalk 用に定義された従来の MVC ではありません。
代わりに、PHP には、同じ目標を目指す 4 つのパターンがあります。MVC Model2、MVP、MVVM、および HMVC です。繰り返しになりますが、違いについてもう一度書くのが面倒なので、私の古いコメントにリンクします。
最初に理解しなければならないことは、MVC のモデルはクラスでもオブジェクトでもないということです。多数のクラスを含むレイヤーです。基本的に、モデル レイヤーはすべてのレイヤーを組み合わせたものです (ただし、2 番目のレイヤーは「ドメイン モデル オブジェクト」を含むため、「ドメイン オブジェクト レイヤー」と呼ぶ必要があります)。モデル層の各部分に何が含まれているかについての簡単な要約を読みたい場合は、この古いコメントを読んでみてください(「補足」セクションにスキップしてください)。
この画像は、Fowler のサイトのService Layerの記事から引用したものです。
Controller は、MVC で 1 つの主要な役割を果たします (ここでは Model2 の実装について説明します)。
モデル レイヤー (サービスまたはドメイン オブジェクト) からの構造に対してコマンドを実行し、構造の状態を変更します。
通常、モデル層からビューに構造をバインド (または別の方法で渡す) という二次的な責任がありますが、SRPに従う場合、これは疑わしい慣行になります。
情報の保存と取得はデータ ソース レイヤーで処理され、通常はDataMapperとして実装されます(その名前を悪用する ORM と混同しないでください)。
これを単純化して使用すると、次のようになります。
$mapper = $this->mapperFactory->build(Model\Mappers\User::class);
$user = $this->entityFactory->build(Model\Entities\User::class);
$user->setId(42);
$mapper->fetch($user);
if ($user->isBanned() && $user->hasBannExpired()){
$user->setStatus(Model\Mappers\User::STATUS_ACTIVE);
}
$mapper->store($user);
ご覧のように、ドメイン オブジェクトは、そこからの情報が保存されたことをまったく認識していません。また、データをどこに置くかについても問題ではありません。MySQL、PostgreSQL、または一部の noSQL データベースに保存できます。または、リモート REST API にプッシュされる可能性があります。あるいは、マッパーがテスト用のモックだったのかもしれません。マッパーを置き換えるために必要なことは、このメソッドに別のファクトリを提供することだけです。
モデルクラスとエンティティクラスは、アプリケーションのデータとロジックを表します。これは多くの人がビジネスロジックと呼んでいます。通常、それは以下の責任があります:
これは、httpリクエスト中のフローを示すMVCシーケンス図です。
この場合、モデルは、データベースにアクセスするために作成されたコードを実装するのに最適な場所です。
mysql_query()
1 つには、家族を使用しないでください。それらは非推奨になっているため、PDO や mysqli についても学習することを検討してください。
モデルがデータ処理を担当します。情報を取得および/または保存するためのコントローラーへのインターフェースを提供します。したがって、これはデータベース アクションが行われる主要な場所になります。
アップデート
コメントでOPから尋ねられた質問に答えるには:「データベース全体の1つの一般的なモデルですか、それともテーブル/アクションごとのモデルですか?」
モデルは、個々のテーブルを抽象化することを目的としています (ただし、単一のテーブルのみを処理するモデルもあります)。たとえば、すべての記事を要求してから著者のユーザー名をクエリする代わりに、次のような 1 つの関数を使用します。
function getArticles()
{
// query article table and join with user table to get username
}
作成するモデルの数は、プロジェクトの規模とデータの相互関係によって大きく異なります。データの独立したグループを識別できる場合は、グループごとにモデルを作成する可能性があります。しかし、これは厳格なルールではありません。
読み取り専用モデルと書き込み専用モデルを明確に分離したい場合を除き、データ操作は同じモデルの一部にすることができます (これを保証する状況はわかりませんが、誰にもわかりません)。
モデルには、アプリケーションの状態を表すドメイン オブジェクトまたはデータ構造が含まれています。[ウィキペディア] . したがって、モデルはデータベース呼び出しを行う場所になります。
「クラシック」(より適切な単語 atm がない) MVC パターンでは、ビューはモデルから現在の状態を取得します。
モデルはデータベースにアクセスするためのものであると誤解しないでください。データベースにアクセスするだけではありません。
さらに、モデルにデータベース アクセス コードを含めないようにする必要があります。これは、モデル/ビュー/コントローラーの外部にある別のレイヤーに属します。これは永続レイヤーと呼ばれ、人気のあるPHP 用のDoctrine 2などのオブジェクト リレーショナル マッパーを使用して実装できます。
この方法では、(私の)SQL コードに触れることはありません。永続層がこれを処理します。Doctrine チュートリアルをご覧になることを強くお勧めします。これは、アプリケーションを作成するための本当に専門的な方法です。
データベースから読み込まれた生データを操作する代わりに、データを保持するオブジェクトとそれに関連付けられた動作を作成します。
たとえば、次のUser
ようなクラスがあるとします。
class User
{
protected $id;
protected $name;
protected $privileges;
public function setName($name) { ... }
public function getName() { ... }
public function addPrivilege(Privilege $privilege) { ... }
public function getPrivileges() { ... }
}
コントローラーはオブジェクトとのみ対話します。
class UserController
{
public function testAction()
{
// ...
$user = $em->getRepository('User')->find(123); // load User with id 123
$user->setName('John'); // work with your objects,
echo $user->getName(); // and don't worry about the db!
$em->flush(); // persist your changes
}
}
舞台裏では、ORM がSELECT
クエリの発行、オブジェクトのインスタンス化、オブジェクトへの変更の検出、必要なUPDATE
ステートメントの発行などの低レベルの作業をすべて処理します。