蝴蝶刀刀
注意:这是对此事的一般看法,适用于任何基于 MVC 的应用程序,而不仅仅是 Laravel。一个基于MVC模式的应用程序应该由三部分组成:交付机制:UI逻辑(用户请求处理和服务器响应创建),服务层:应用程序逻辑,领域模型:业务逻辑。以下是一些图形表示(我自己制作的):如上所示(并在下面的资源中详细描述),控制器和视图是交付机制的一部分。它们应该仅通过服务层对象(服务)与领域模型交互。因此,他们不应该了解域模型组件(实体 - 也称为域对象、数据映射器、存储库等)。更重要的是,控制器应该只有一项职责:将用户请求的值传递给服务层,以便它更新模型。所以,回答你的第一个问题:不,控制器不应该能够创建域模型元素的任何实例(因此你所谓的“模型”的实例 - 就 Laravel 的Active Record而言),甚至不能传递这些对象到其他组件(如存储库、服务等)。相反,控制器应该只将请求的值(例如,用户 id )传递给相应的服务。然后,这些服务将创建适当的域模型对象并使用适当的存储库、数据映射器等,以便保存到数据库或从数据库获取。至于第二个问题(如果我理解正确的话):存储库被视为实体的集合- 它们是域模型组件。因此,元素(例如实体实例)可以被获取、存储、更改或从其中删除。因此,根据定义,实体必须与存储库分开定义/使用。对于 Laravel,同样适用:“模型”应与存储库分开定义/使用。“通用”MVC 实现(为了更清楚):控制器:<?phpnamespace MyApp\UI\Web\Controller\Users;use MyApp\Domain\Service\Users;use Psr\Http\Message\ServerRequestInterface;/** * Add a user. */class AddUser { /** * User service. * * @var Users */ private $userService; /** * * @param Users $userService User service. */ public function __construct(Users $userService) { $this->userService = $userService; } /** * Invoke. * * @param ServerRequestInterface $request Request. * @return void */ public function __invoke(ServerRequestInterface $request) { // Read request values. $username = $request->getParsedBody()['username']; // Call the corresponding service. $this->userService->addUser($username); }}服务:<?phpnamespace MyApp\Domain\Service;use MyApp\Domain\Model\User\User;use MyApp\Domain\Model\User\UserCollection;use MyApp\Domain\Service\Exception\UserExists;/** * Service for handling the users. */class Users { /** * User collection (a repository). * * @var UserCollection */ private $userCollection; /** * * @param UserCollection $userCollection User collection. */ public function __construct(UserCollection $userCollection) { $this->userCollection = $userCollection; } /** * Find a user by id. * * @param int $id User id. * @return User|null User. */ public function findUserById(int $id) { return $this->userCollection->findUserById($id); } /** * Find all users. * * @return User[] User list. */ public function findAllUsers() { return $this->userCollection->findAllUsers(); } /** * Add a user. * * @param string $username Username. * @return User User. */ public function addUser(string $username) { $user = $this->createUser($username); return $this->storeUser($user); } /** * Create a user. * * @param string $username Username. * @return User User. */ private function createUser(string $username) { $user = new User(); $user->setUsername($username); return $user; } /** * Store a user. * * @param User $user User. * @return User User. */ private function storeUser(User $user) { if ($this->userCollection->userExists($user)) { throw new UserExists('Username "' . $user->getUsername() . '" already used'); } return $this->userCollection->storeUser($user); }}存储库:<?phpnamespace MyApp\Domain\Infrastructure\Repository\User;use MyApp\Domain\Model\User\User;use MyApp\Domain\Infrastructure\Mapper\User\UserMapper;use MyApp\Domain\Model\User\UserCollection as UserCollectionInterface;/** * User collection. */class UserCollection implements UserCollectionInterface { /** * User mapper (a data mapper). * * @var UserMapper */ private $userMapper; /** * * @param UserMapper $userMapper User mapper. */ public function __construct(UserMapper $userMapper) { $this->userMapper = $userMapper; } /** * Find a user by id. * * @param int $id User id. * @return User|null User. */ public function findUserById(int $id) { return $this->userMapper->fetchUserById($id); } /** * Find all users. * * @return User[] User list. */ public function findAllUsers() { return $this->userMapper->fetchAllUsers(); } /** * Store a user. * * @param User $user User. * @return User User. */ public function storeUser(User $user) { return $this->userMapper->saveUser($user); } /** * Check if the given user exists. * * @param User $user User. * @return bool True if user exists, false otherwise. */ public function userExists(User $user) { return $this->userMapper->userExists($user); }}实体:<?phpnamespace MyApp\Domain\Model\User;/** * User. */class User { /** * Id. * * @var int */ private $id; /** * Username. * * @var string */ private $username; /** * Get id. * * @return int */ public function getId() { return $this->id; } /** * Set id. * * @param int $id Id. * @return $this */ public function setId(int $id) { $this->id = $id; return $this; } /** * Get username. * * @return string */ public function getUsername() { return $this->username; } /** * Set username. * * @param string $username Username. * @return $this */ public function setUsername(string $username) { $this->username = $username; return $this; }}数据映射器:<?phpnamespace MyApp\Domain\Infrastructure\Mapper\User;use PDO;use MyApp\Domain\Model\User\User;use MyApp\Domain\Infrastructure\Mapper\User\UserMapper;/** * PDO user mapper. */class PdoUserMapper implements UserMapper { /** * Database connection. * * @var PDO */ private $connection; /** * * @param PDO $connection Database connection. */ public function __construct(PDO $connection) { $this->connection = $connection; } /** * Fetch a user by id. * * Note: PDOStatement::fetch returns FALSE if no record is found. * * @param int $id User id. * @return User|null User. */ public function fetchUserById(int $id) { $sql = 'SELECT * FROM users WHERE id = :id LIMIT 1'; $statement = $this->connection->prepare($sql); $statement->execute([ 'id' => $id, ]); $data = $statement->fetch(PDO::FETCH_ASSOC); return ($data === false) ? null : $this->convertDataToUser($data); } /** * Fetch all users. * * @return User[] User list. */ public function fetchAllUsers() { $sql = 'SELECT * FROM users'; $statement = $this->connection->prepare($sql); $statement->execute(); $data = $statement->fetchAll(PDO::FETCH_ASSOC); return $this->convertDataToUserList($data); } /** * Check if a user exists. * * Note: PDOStatement::fetch returns FALSE if no record is found. * * @param User $user User. * @return bool True if the user exists, false otherwise. */ public function userExists(User $user) { $sql = 'SELECT COUNT(*) as cnt FROM users WHERE username = :username'; $statement = $this->connection->prepare($sql); $statement->execute([ ':username' => $user->getUsername(), ]); $data = $statement->fetch(PDO::FETCH_ASSOC); return ($data['cnt'] > 0) ? true : false; } /** * Save a user. * * @param User $user User. * @return User User. */ public function saveUser(User $user) { return $this->insertUser($user); } /** * Insert a user. * * @param User $user User. * @return User User. */ private function insertUser(User $user) { $sql = 'INSERT INTO users (username) VALUES (:username)'; $statement = $this->connection->prepare($sql); $statement->execute([ ':username' => $user->getUsername(), ]); $user->setId($this->connection->lastInsertId()); return $user; } /** * Update a user. * * @param User $user User. * @return User User. */ private function updateUser(User $user) { $sql = 'UPDATE users SET username = :username WHERE id = :id'; $statement = $this->connection->prepare($sql); $statement->execute([ ':username' => $user->getUsername(), ':id' => $user->getId(), ]); return $user; } /** * Convert the given data to a user. * * @param array $data Data. * @return User User. */ private function convertDataToUser(array $data) { $user = new User(); $user ->setId($data['id']) ->setUsername($data['username']) ; return $user; } /** * Convert the given data to a list of users. * * @param array $data Data. * @return User[] User list. */ private function convertDataToUserList(array $data) { $userList = []; foreach ($data as $item) { $userList[] = $this->convertDataToUser($item); } return $userList; }}看法:<?phpnamespace MyApp\UI\Web\View\Users;use MyApp\UI\Web\View\View;use MyApp\Domain\Service\Users;use MyLib\Template\TemplateInterface;use Psr\Http\Message\ResponseInterface;use Psr\Http\Message\ResponseFactoryInterface;/** * Add a user. */class AddUser extends View { /** * User service. * * @var Users */ private $userService; /** * * @param ResponseFactoryInterface $responseFactory Response factory. * @param TemplateInterface $template Template. * @param Users $userService User service. */ public function __construct(ResponseFactoryInterface $responseFactory, TemplateInterface $template, Users $userService) { parent::__construct($responseFactory, $template); $this->userService = $userService; } /** * Display a form for adding a user. * * @return ResponseInterface Response. */ public function index() { $body = $this->template->render('@Template/Users/add-user.html.twig', [ 'activeMainMenuItem' => 'addUser', 'action' => '', ]); $response = $this->responseFactory->createResponse(); $response->getBody()->write($body); return $response; } /** * Add a user. * * @return ResponseInterface Response. */ public function addUser() { $body = $this->template->render('@Template/Users/add-user.html.twig', [ 'activeMainMenuItem' => 'addUser', 'message' => 'User successfully added.', ]); $response = $this->responseFactory->createResponse(); $response->getBody()->write($body); return $response; }}