删除文件 docs/docs/framework_architecture-repository.md

This commit is contained in:
唐永川
2026-06-26 13:36:19 +00:00
committed by Gitee
parent 28d5bdf0c8
commit 67cfe41359

View File

@@ -1,339 +0,0 @@
---
url: framework_architecture-repository
---
# Repository
> **使用 Repository 辅助 Model**<br />
若将数据库逻辑都写在 model会造成 model 的肥大而难以维护,基于 SOLID 原则,我们应该使用 Repository 模式辅助 model将相关的数据库逻辑封装在不同的 repository方便中大型项目的维护。
<a name="c101406b"></a>
## 数据库逻辑
在 CRUD 中CUD 比较稳定,但 R 的部分则千变万化大部分的数据库逻辑都在描述R 的部分,若将数据库逻辑写在 controller 或 model 都不适当,会造成 controller 与 model 肥大,造成日后难以维护。
<a name="Model"></a>
## Model
如果使用 Eloquent ORM 来实现 Repository 模式,需要修改 model 不要包含数据库逻辑,仅保留以下部分:
- Property : 如$table$fillable…等。
- Mutator: 包括 mutator 與 accessor。
- Method : relation 類的 method如使用 hasMany() 與 belongsTo()。
简化后的Eloquent 的 model 类我们可以称之为`Eloquent Class`,由于继承了`Illuminate\Database\Eloquent\Model` 类,所以`Eloquent Class`仍然有很多方法可以操作数据库。
Eloquent Class 代码结构如下:
```php
namespace MyBlog;
use Illuminate\Database\Eloquent\Model;
/**
* MyBlog\User
*
*/
class User extends Model {
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name', 'email', 'password'];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = ['password', 'remember_token'];
}
```
而在 ECShopX 中,由于我们采用了 Doctrine ORM其自带Repository模式。在 Doctrine ORM 中也有简化的 model 类: `Entity Class`
相比 `Eloquent Class` `Entity Class` 更简单,其只包含 `protected``private`的属性和`getter``setter` 方法(在 JAVA 中,这种对象成为值对象)。
Entity Class 代码结构如下:
```php
<?php
namespace MyBlog;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="users")
*/
class User
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*/
protected $id;
/**
* @ORM\Column(type="string")
*/
protected $name;
/**
* @ORM\Column(type="string")
*/
protected $email;
/**
* @ORM\Column(type="string")
*/
protected $password;
/**
* @ORM\Column(type="string")
*/
protected $remember_token;
// .. (other code getter setter )
}
```
<a name="Repository"></a>
## Repository
初学者常会在 controller 直接调用 model 写数据库逻辑:
```php
public function index()
{
$users = User::where('age', '>', 20)
->orderBy('age')
->get();
return view('users.index', compact('users'));
}
```
数据库逻辑是`获取 20 岁以上的用户`
在中大型项目中,会有几个问题 :
- 将数据库逻辑写在 controller造成 controller 的肥大难以维护。
- 违反 SOLID 的单一职责原则 : 数据库逻辑不应该写在 controller。
- controller 直接相依于model使得我们无法对 controller 做单元测试。
比较好的方式是使用 repository :
- 将 model 依赖注入到 repository。
- 将数据库逻辑写在 repository。
- 将 repository 依赖注入到 service。
以此原则,我们看下,采用 Eloquent ORM 如何使用 Repository 模式。
UserRepository.php
```php
namespace MyBlog\Repositories;
use Doctrine\Common\Collections\Collection;
use MyBlog\User;
class UserRepository
{
/** @var User 注入的User model */
protected $user;
/**
* UserRepository constructor.
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* 返回年龄大于$age的用户
* @param integer $age
* @return Collection
*/
public function getAgeLargerThan($age)
{
return $this->user
->where('age', '>', $age)
->orderBy('age')
->get();
}
}
```
第 8 行
```php
/** @var User 注入的User model */
protected $user;
/**
* UserRepository constructor.
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
```
将依赖的 User model 依赖注入到 UserRepository。
UserController.php
```php
<?php
namespace App\Http\Controllers;
use App\Http\Requests;
use MyBlog\Repositories\UserRepository;
class UserController extends Controller
{
/** @var UserRepository 注入的UserRepository */
protected $userRepository;
/**
* UserController constructor.
*
* @param UserRepository $userRepository
*/
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$users = $this->userRepository
->getAgeLargerThan(20);
return view('users.index', compact('users'));
}
}
```
将依赖的 UserRepository 依赖注入到 UserController。
26行
```php
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$users = $this->userRepository
->getAgeLargerThan(20);
return view('users.index', compact('users'));
}
```
从原本直接依赖 User model改成依赖注入的 UserRepository。
改用这种写法,有几个优点:
- 将数据库逻辑写在存储库中,解决控制器肥大问题。
- 符合SOLID的单一职责原则数据库逻辑写在repository没写在controller。
- 符合SOLID的依赖转换原则controller 并非直接相依于存储库而是将存储库依赖注入进controller。
>
**实际上建议repository仅依赖注入于service而不要直接注入在controller本范例因为还没介绍到servie模式以便简化起见所以直接注入于controller**。<br />
<br />
>
**是否该建立存储库接口?**<br />
理论上使用依赖注入时应该使用接口不过接口目的在于通过抽象化方便在后期更换接口的具体实现以便让程序达到开放封闭的要求但是实际上要更换存储库的机会不高除非你有更换资料库的需求如从MySQL抽换到MongoDB此时就该建立存储库接口。
不过由于我们使用了依赖注入将来要从类改成interface也很方便只要在构造方法的类型提示改成interface即可维护成本很低所以在此大可使用的存储库类用接口反而会造成设计过度等真正需求来时再重构成接口即可。
采用 Doctrine ORM 如何使用 Repository 模式。
由于 Doctrine ORM 自带 Repository 模式,所以直接使用即可。
UserRepository.php
```php
<?php
namespace App\Repositories;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository {
/**
* 返回年龄大于$age的用户
* @param integer $age
* @return Collection
*/
public function getAgeLargerThan($age)
{
return $this->user
->where('age', '>', $age)
->orderBy('age')
->get();
}
}
```
UserController.php
```php
namespace App\Http\Controllers;
use App\Http\Requests;
use MyBlog\Repositories\UserRepository;
class UserController extends Controller
{
/** @var UserRepository 注入的UserRepository */
protected $userRepository;
/**
* UserController constructor.
*
* @param UserRepository $userRepository
*/
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$users = $this->userRepository
->getAgeLargerThan(20);
return view('users.index', compact('users'));
}
}
```