我试图给你一个非常基本的例子来说明我将如何实现这个架构;因为它真的很基础,而且我只是一个充满激情的开发人员,仅此而已,我可能违反了一些架构规则,所以请将其作为概念证明。
让我们开始快速使用控制器部分,您会收到一些请求。现在你需要一个负责干脏活的人。
正如您在此处看到的,我正在尝试通过构造函数传递所有“依赖项”。通过这些方式,您应该能够在测试时轻松地将其替换为 Mocks。
依赖注入是这里的概念之一。
现在模型(请记住模型是一个层而不是单个类)
我使用了“服务(或案例)”,它应该可以帮助您与参与此行为的所有参与者(类)组成一组行为。
识别服务(或案例)应该做的常见行为是这里的概念之一。
请记住,在开始之前,您应该有一个大局(或其他地方取决于项目),以尊重KISS、SOLID、DRY 等原则。
请注意方法命名,通常一个坏的或过长的名称(例如我的)表明该类具有多个责任或有不良设计的味道。
//App/Controllers/BlogController.php
namespace App\Controllers;
use App\Services\AuthServiceInterface;
use App\Services\BlogService;
use App\Http\Request;
use App\Http\Response;
class BlogController
{
protected $blogService;
public function __construct(AuthServiceInterface $authService, BlogService $blogService, Request $request)
{
$this->authService = $authService;
$this->blogService = $blogService;
$this->request = $request;
}
public function indexAction()
{
$data = array();
if ($this->authService->isAuthenticatedUser($this->request->getSomethingRelatedToTheUser())) {
$someData = $this->blogService->getSomeData();
$someOtherData = $this->request->iDontKnowWhatToDo();
$data = compact('someData', 'someOtherData');
}
return new Response($this->template, array('data' => $data), $status);
}
}
现在我们需要创建我们在控制器中使用的这个服务。如您所见,我们并没有直接与“存储或数据层”对话,而是调用了一个抽象层来为我们处理这些问题。
使用Repository Pattern 从数据层检索数据是这里的概念之一。
这样我们可以切换到任何存储库(内存中、其他存储等)来检索我们的数据,而无需更改控制器正在使用的接口、相同的方法调用但从另一个地方获取数据。
通过接口而非具体类进行设计是这里的概念之一。
//App/Services/BlogService.php
<?php
namespace App\Services;
use App\Model\Repositories\BlogRepository;
class BlogService
{
protected $blogRepository;
public function __construct(BlogRepositoryInterface $blogRepository)
{
$this->blogRepository = $blogRepository;
}
public function getSomeData()
{
// do something complex with your data, here's just simple ex
return $this->blogRepository->findOne();
}
}
此时,我们定义了包含持久性处理程序并了解我们的实体的存储库。
再次解耦存储持久化和实体的知识(例如“可以”与mysql表耦合的东西)是这里的概念之一。
//App/Model/Repositories/BlogRepository.php
<?php
namespace App\Models\Respositories;
use App\Models\Entities\BlogEntity;
use App\Models\Persistance\DbStorageInterface;
class DbBlogRepository extends EntityRepository implements BlogRepositoryInterface
{
protected $entity;
public function __construct(DbStorageInterface $dbStorage)
{
$this->dbStorage = $dbStorage;
$this->entity = new BlogEntity;
}
public function findOne()
{
$data = $this->dbStorage->select('*')->from($this->getEntityName());
// This should be part of a mapping logic outside of here
$this->entity->setPropA($data['some']);
return $this->entity;
}
public function getEntityName()
{
return str_replace('Entity', '', get_class($this->entity));
}
}
最后是一个带有 Setter 和 Getter 的简单实体:
//App/Model/Entities/BlogEntity.php
<?php
namespace App\Models\Entities;
class BlogEntity
{
protected $propA;
public function setPropA($dataA)
{
$this->propA = $dataA;
}
public function getPropA()
{
return $this->propA;
}
}
现在?如何注入这些作为依赖项传递的类?嗯,这是一个很长的答案。
指示性地,您可以使用依赖注入,就像我们在这里所做的那样,有一个 init/boot 文件,您可以在其中定义以下内容:
// Laravel Style
App::bind('BlogRepositoryInterface', 'App\Model\Repositories\DbBlogRepository');
App::bind('DbStorageInterface', 'App\Model\Persistence\PDOStorage');
或一些 config/service.yml 文件,例如:
// Not the same but close to Symfony Style
BlogService:
class: "Namespace\\ConcreteBlogServiceClass"
或者您可能觉得需要Container Class,您可以在其中询问您需要在控制器中使用的服务。
function indexAction ()
{
$blogService = $this->container->getService('BlogService');
....
fundo 中的 Dulcis 是一些有用的链接(您可以找到大量关于此的文档):