定制 foothing/laravel-repository 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

foothing/laravel-repository

Composer 安装命令:

composer require foothing/laravel-repository

包简介

This package provides an implementation of the repository pattern for Laravel 5.

README 文档

README

This package provides an implementation of the repository pattern for Laravel 5.

Composer installation

composer require foothing/laravel-repository

Basic usage

This package ships with a repository interface definition and an Eloquent implementation. The EloquentRepository is ready to use.

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

You are now ready to go:

// 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);

If you want to extend the base implementation with your custom methods all you need to do is extend the base class and define a constructor with the Eloquent model as the first argument.

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

	function customFancyMethod() {

	}
}

Don't forget to call the superclass constructor in order to enable all the features that are delivered out of the box. You can also add additional dependencies while overriding the base constructor.

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

and you are all set. Examples:

// 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);
	}
}

Eager load relations

You can eager load relations using the with method:

$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"},
		],
	}
]

You can chain the with method to all available methods:

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

You'll often want to eager load some relations by default. Let's assume you have an User model with a many-to-many relation with its Role models, and you want to fetch both the user info and the roles.

The Foothing\Resources\Resource interface has three methods which define the default Model behaviour:

  • which relations to eager load by default for a findOne operation
  • which relations to eager load by default for a findMany operation
  • which fields to skip upon save
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'];
	}
}

In this way, each time you will use your UserRepository the following would be the default behaviour:

$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*

This default behaviour will be ignored if you use the with method explicitly.

The skipOnSave method comes handy when dealing with JSON object, since when you read a resource, then process it on the client side, then send it back to the server, it will contain the relation properties. This properties will be converted to stdClass PHP object breaking the Eloquent save method.

Criteria

You can apply filters and order constraints using the CriteriaInterface, which also ships with an Eloquent implementation.

Usage:

$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();

The repository provides shortcut methods you can use in your chains. The following example produces the same effect as the previous one.

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

Available filters:

// 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');

You can use the in operator with a comma separated list of values or with an array of values.

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

Nested filters

It's also possible to query a Model relation. Assume your Eloquent Model defines a children relation like so:

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

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

In this case you'll be allowed to query children values:

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

Keep in mind that the methods subject to criteria restrictions are all those fetching more than one record.

Attach and detach many-to-many

Given the following Model:

class Homer extends Model {

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

}

you can use the attach() and detach() methods to attach and detach to / from relation.

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

Scopes

You can plug-in your Model scopes using the scope() method.

// 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');

Scopes only apply on read methods.

Global Scopes

You can define a global scope for each repository implementation, which might come handy to restrict records access globally.

Just set

protected $globalScope = 'whatever';

in your repository. The global scope must match an Eloquent scope. Note that if you use explicit scopes, i.e. $repository->scope('male'), your global scope will be ignored.

Repository 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();
}

RemoteQuery

More info coming soon.

License

MIT

foothing/laravel-repository 适用场景与选型建议

foothing/laravel-repository 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 2.3k 次下载、GitHub Stars 达 4, 最近一次更新时间为 2015 年 10 月 29 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「repository」 「laravel」 「eloquent」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 foothing/laravel-repository 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 foothing/laravel-repository 我们能提供哪些服务?
定制开发 / 二次开发

基于 foothing/laravel-repository 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 2.3k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 4
  • 点击次数: 12
  • 依赖项目数: 6
  • 推荐数: 0

GitHub 信息

  • Stars: 4
  • Watchers: 3
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2015-10-29