foothing/laravel-repository

此包为 Laravel 5 提供了仓库模式的实现。

0.9.0 2016-10-06 15:47 UTC

This package is auto-updated.

Last update: 2024-09-23 00:00:23 UTC


README

此包为 Laravel 5 提供了仓库模式的实现。

Composer 安装

composer require foothing/laravel-repository

基本用法

此包包含仓库接口定义和 Eloquent 实现。 EloquentRepository 已准备好使用。

// Make a repository instance manually
$repository = new EloquentRepository(new Post());

现在你已经准备好了

// Find first occurrence with matching field 'email'
$repository->findOneBy('email', 'test@example.com');

// Find first occurrence where id > 1
$repository->findOneBy('id', '1', '>');

// Find where title starts with 'foo'
$repository->findAllBy('title', 'foo%', 'like');

// Find all occurrences where id > 1
$repository->findAllBy('id', '1', '>');

// Returns all posts
$repository->all();

// Returns all post with Laravel pagination format
$repository->paginate();

// Return record count
$repository->filter('name', 'Homer')->count();

// Create, update and delete instances.
$model = new Post(Input::all());
$freshMoel = $repository->create($model);
$updatedModel = $repository->update($model);
$repository->delete($model);

如果你想通过自定义方法扩展基本实现,你需要扩展基本类,并定义一个构造函数,将 Eloquent 模型作为第一个参数。

class PostsRepository extends EloquentRepository {
	function __construct(Post $post) {
		// Call superclass constructor.
		parent::construct($post);
	}

	function customFancyMethod() {

	}
}

不要忘记调用超类构造函数,以启用所有开箱即用的功能。你还可以在重写基本构造函数时添加额外的依赖。

class PostsRepository extends AbstractEloquentRepository {
	function __construct(Post $post, AnotherDependency $dependency) {
		parent::construct($post);
		// Do whatever you like with your $dependency
	}
}

现在一切都准备好了。示例

// Use with a dependency injector

class PostsController {
	protected $posts;

	function __construct(PostsRepository $posts) {
		$this->posts = $posts;
	}

	function getIndex($id = null) {
		// Return one post by primary key
		return $this->posts->find($id);
	}
}

预加载关系

你可以使用 with 方法来预加载数据库关系

$posts = $repository->with(['author', 'comments'])->all();

Output:
[
	{
		"id": 1,
		"title": "Post title",
		"author": {
			"id": 1,
			"email": "test@example.com"
		},
		"comments": [
			{"id": 1, "text": "a comment"},
			{"id": 2, "text": "another comment"},
		],
	}
]

你可以将 with 方法链接到所有可用方法

$posts = $repository->with(['author', 'comments'])->findOneBy('name', 'foo');
$posts = $repository->with(['author', 'comments'])->all();
// And so on.

你通常会默认预加载数些关系。假设你有一个具有与 Role 模型多对多关系的 User 模型,并且你想要获取用户信息和角色。

Foothing\Resources\Resource 接口有三个方法,用于定义默认模型行为

  • findOne 操作默认预加载哪些关系
  • findMany 操作默认预加载哪些关系
  • 在保存时要跳过哪些字段
class User extends Model implements Foothing\Resources\Resource {
	/**
	 * Array of relations we want to eager-load when
	 * a single entity is being fetched.
	 *
	 * @return array
	 */
	function unitRelations() {
		return ['roles', 'posts'];
	}

	/**
	 * Array of relations we want to eager-load when
	 * a list of entities is being fetched.
	 *
	 * @return array
	 */
	function listRelations() {
		return ['roles'];
	}

	/**
	 * When the resource is sent in a json-encoded
	 * format it may happen to have relations fields
	 * populated. Since they would be set as stdClass
	 * objects we need to unset them before save.
	 *
	 * This method should return an array with all relations
	 * we want to be unset when processing the updates.
	 *
	 * @return array
	 */
	function skipOnSave() {
		return ['roles', 'posts'];
	}
}

这样,每次使用你的 UserRepository 时,以下行为将是默认的

$users->find($id); 		// will eager load *roles* and *posts*
$users->findOneBy($id); // will eager load *roles* and *posts*
$users->create();		// will eager load *roles* and *posts*
$users->update();		// will eager load *roles* and *posts*
$users->all(); 			// will eager load *roles*
$users->paginate(); 	// will eager load *roles*

如果你显式使用 with 方法,则将忽略此默认行为。

skipOnSave 方法在处理 JSON 对象时很有用,因为当你读取资源,然后在客户端上对其进行处理,然后将它发送回服务器时,它将包含关系属性。这些属性将被转换为 stdClass PHP 对象,从而破坏 Eloquent 保存方法。

条件

你可以使用 CriteriaInterface 应用筛选器和排序约束,该接口也包含一个 Eloquent 实现。

用法

$criteria = new \Foothing\Repository\Eloquent\EloquentCriteria();
$criteria->filter('name', 'Homer');
$criteria->filter('lastName', 'Simpson');

// Chain methods
$criteria->order('name')->sort('asc');
$repository->criteria($criteria)->paginate();

仓库提供了可以在链中使用的快捷方法。以下示例产生的效果与上一个示例相同。

$repository
	->filter('name', 'Homer')
	->filter('lastName', 'Simpson')
	->order('name')
	->sort('asc')
	->paginate();

可用筛选器

// Defaults to '='
$criteria->filter('name', 'Homer');

$criteria->filter('name', 'Home%', 'like');
$criteria->filter('id', 1, '>');
$criteria->filter('id', 1', '>=');
$criteria->filter('id', 1, '<');
$criteria->filter('id', 1, '<=');
$criteria->filter('id', 1, '!=');
$criteria->filter('lastName', 'Simpson,Nahasapeemapetilon', 'in');

你可以使用逗号分隔的值列表或值数组与 in 操作符一起使用。

$criteria->filter('lastName', 'Simpson,Nahasapeemapetilon', 'in');
$criteria->filter('lastName', ['Simpson', 'Nahasapeemapetilon'], 'in');

嵌套筛选器

你也可以查询模型关系。假设你的 Eloquent 模型定义了一个类似这样的 children 关系

class Foo extends Model {
	protected $table = 'foo';

	public function children() {
		return $this->hasMany('Bar');
	}
}

在这种情况下,你将被允许查询 children

$criteria->filter('children.name', 'Bar');

请注意,受条件限制的方法是所有获取多个记录的方法。

多对多关联的附加和分离

给定以下 Model

class Homer extends Model {

	public function roles() {
		return $this->hasMany('Role');
	}

}

你可以使用 attach()detach() 方法将关联附加到/从关联中分离。

$homer = Homer::find(1);
$foodCritic = Role::find(1);
$repository->attach($homer, 'roles', $foodCritic);
$repository->detach($homer, 'roles', $foodCritic);

作用域

你可以使用 scope() 方法插入你的模型作用域。

// Model
class Person extends Model {

	public function scopeMale($query) {
		return $query->where('sex', 'male');
	}
}

// Usage in Repository
$malePeople = $repository->scope('male')->all();
$malePeople = $repository->scope('male')->filter('name', 'Bart')->all();
$malePeople = $repository->scope('male')->paginate();
$malePeople = $repository->scope('male')->findAllBy('name', 'John');

作用域只应用于读取方法。

全局作用域

你可以为每个仓库实现定义一个全局作用域,这可能会在全局范围内限制记录访问。

只需在你的仓库中设置

protected $globalScope = 'whatever';

全局作用域必须与 Eloquent 作用域匹配。请注意,如果你使用显式作用域,即 $repository->scope('male'),则将忽略全局作用域。

仓库 API

<?php namespace Foothing\Repository;

interface RepositoryInterface {

    //
    //
    //	Crud.
    //
    //

    public function find($id);
    public function findOneBy($field, $arg1, $arg2 = null);
    public function findAllBy($field, $arg1, $arg2 = null);
    public function all();
    public function paginate($limit = null, $offset = null);
    public function count();

    public function create($entity);
    public function update($entity);
    public function delete($entity);

    //
    //
    //	Eager loading.
    //
    //

    public function with(array $relations);

    //
    //
    //	Relations.
    //
    //

    /**
     * Attach $relatedEntity and $entity in a many-to-many relation.
     *
     * @param Model $entity
     * @param string $relation
     * @param Model $relatedEntity
     *
     * @return Model the updated $entity
     */
    public function attach($entity, $relation, $relatedEntity);

    /**
     * Detach $entity and $relatedEntity in a many-to-many relation.
     *
     * @param Model $entity
     * @param string $relation
     * @param Model $relatedEntity
     *
     * @return Model the updated $entity
     */
    public function detach($entity, $relation, $relatedEntity);

    //
    //
    //	Criteria shortcuts.
    //
    //

    public function criteria(CriteriaInterface $criteria);
    public function filter($field, $value, $operator = '=');
    public function order($field, $sort = null);
    public function sort($direction);

    //
    //
    //	Scopes.
    //
    //

    public function scope($scope);

    //
    //
    //	Helpers.
    //
    //

    /**
     * Forces the next read query to skip cached values.
     * @return self
     */
    public function refresh();

    /**
     * Reset the refresh flag.
     * @return self
     */
    public function reset();
}

远程查询

更多信息即将推出。

许可

MIT