unionofrad/li3_behaviors 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

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

unionofrad/li3_behaviors

Composer 安装命令:

composer require unionofrad/li3_behaviors

包简介

Model behaviors for the li₃ PHP framework

README 文档

README

This library provides base classes for implementing model behaviors. Model behaviors provide a simple way to extend models. This pattern allow common logic to be encapsulated inside behaviors for keeping models light and composed only by its own business logic.

Installation

The preferred installation method is via composer. You can add the library as a dependency via:

composer require unionofrad/li3_behaviors

li₃ plugins must be registered within your application bootstrap phase as they use a different (faster) autoloader.

Libraries::add('li3_behaviors')

The official manual has more information on how to register the plugin with the app or use alternative installation methods (i.e. via Git).

Usage

Managing and Loading Behaviors

First to add the ability of using behaviors in a model, use the behaviors trait in your model. After that define all behaviors you plan to use in the $_actsAs property of the model class.

// ...
class Posts extends \lithium\data\Model {

   use li3_behaviors\data\model\Behaviors;

   protected $_actsAs = [
       'Sluggable' => ['field' => 'slug', 'label' => 'title']
   ];
	
   // ...

The Behaviors trait also makes some static methods available in the model, which allows to manage behaviors as follows.

// Bind the sluggable behavior with configuration.
Posts::bindBehavior('Sluggable', ['field' => 'slug', 'label' => 'title']);

// Accessing configuration.
Posts::behavior('Sluggable')->config();
Posts::behavior('Sluggable')->config('field');

// Updating configuration.
Posts::behavior('Sluggable')->config('field', 'alt');

// Unbinding it again.
Posts::unbindBehavior('Sluggable');

Creating a Behavior

Now that we are able to load and manage behaviors we can create our own behavior which must extend the Behavior base class. In the following example we create a Sluggable behavior in extensions/data/behavior/Sluggable.php.

namespace app\extensions\data\behavior;

use lithium\util\Inflector;

class Sluggable extends \li3_behaviors\data\model\Behavior {

	protected static $_defaults = [
		'field' => 'slug',
		'label' => 'title'
	];

	protected static function _filters($model, $behavior) {
		Filters::apply($model, 'save', function($params, $next) use ($behavior) {
			$params['data'][$behavior->config('field')] = static::_generate(
				$params['data'][$behavior->config('label')]
			);
			return $next($params);
		});
	}

	protected static function _generate($value) {
		return strtolower(Inflector::slug($value));
	}
}

Behavior Configuration

The configuration of each behavior can be accessed from within the behavior via config(). By default configuration for the behavior will be set automatically using the user provided configuration from the $_actsAs property of the model and the defaults provided in the behavior as $_defaults.

The defaults are merged with the provided configuration using simple array addition ($config += $defaults). If you want to change the way configuration is merged read further.

Providing Custom Configuration Logic

Behaviors often come with different requirements towards configuration. In some cases just a 1-dimensional array needs to be merged in other cases nested multi-dimensional arrays must be merged or even normalized in a custom way.

That's why merging the defaults with the provided configuration can be controlled easily by yourself - the implementer. By default we do a simple one-dimensional merge adding defaults and configuration to eachother. To control configuration merging overwrite the _config() method of the base class.

In the following example we will normalize certain configuration options while merging with the behavior's defaults.

// ...

class Serializable extends \li3_behaviors\data\model\Behavior {

	protected static $_defaults = [
		'fields' => []
	];

	protected static function _config($model, $behavior, $config, $defaults) {
		$config += $defaults;
		$config['fields'] = Set::normalize($config['fields']);

		foreach ($config['fields'] as $field => &$pass) {
			if (!$pass) {
				$pass = 'json';
			}
		}
		return $config;
	}
	
	// ...

The _config() method gets the configuration and the defaults as defined in $_defaults as the 3rd and 4th parameters. The method must finally return the configuration that should be used for the behavior instance.

Exposing Static Methods to the Model

Any public static method present in the behavior is automically exposed on the model. This allows for adding methods to the model easily. Each static method that is exposed gets the name of the current model class as its first and the instance of the behavior as a second parameter.

This is useful if you i.e. need to query the model for results or when you want to retrieve configuration from the behavior.

The example below shows how we expose a token generation method to the model.

// ...

class TokenGenerator extends \li3_behaviors\data\model\Behavior {

	protected static $_defaults = [
		'short' => false
	];

	// Generates a random token either short (8 chars) or long (16 chars) and
	// returns it. Default expiration is one year.
	public static function token($model, $behavior) {
		$token = substr(md5(Random::generate(32)), 0, $behavior->config('short') ? 8 : 16);
		$expires = date('Y-m-d H:i:s', strtotime('+1 year'));

		return compact('token', 'expires');
	}
	
	// ...

Exposing Instance Methods to the Model

Analog to exposing static methods, instance methods can also be exposed to the model easily. Any concrete method implemented in the behavior will be exposed. Each behavior method will in addition to the $entity parameter also receive the name of the model and an instance of the behavior as a second parameter i.e. to access configuration.

// ...

class Publishable extends \li3_behaviors\data\model\Behavior {

	protected static $_defaults = [
		'field' => 'is_published'
	];

	public function publish($model, $behavior, $entity) {
		$field = $behavior->config('field');
		$entity->{$field} = true;
	}

	// ...

Dynamically Adding Model Instance Methods

Sometimes you need to dynamically add methods to a model instance. I.e. when a field name of a behavior is user configurable and needs to be added as a method on the entity.

This can be achived by overwriting the _methods() method and returning an array of methods keyed by their alias on the model instance.

// ...

class Taggable extends \li3_behaviors\data\model\Behavior {
    // ...

	protected static function _methods($model, $behavior) {
		return [
			$behavior->config('field') => function() { /* ... */  }
		]
	}

	// ...

The above exemplaric behavior would then enable the following methods on each entity returned from the model.

Posts::bindBehavior('Taggable', ['field' => 'taxonomy']);
$item = Posts::create();
$item->taxonomy();

Attaching Filters to the Model

To modify existing model methods, filters should be used. If your behavior needs to use filters a good place to attach them is the behavior's _filters() method. Overwrite it to attach filters to the model during initialization phase.

// ...

class Timestamp extends \li3_behaviors\data\model\Behavior {
	// ...

	protected static function _filters($model, $behavior) {
		Filters::apply($model, 'save', function($params, $next) use ($behavior) {
			$params['data'] = static::_timestamp($behavior, $params['entity'], $params['data']);

			return $next($params);
		});
	}

	protected static function _timestamp($behavior, $entity, $data) {
		// ...
	}

	// ...

Attaching Finders to the Model

To add finders to the model's find method, finders should be used. If your behavior needs to use finders a good place to attach them is the behavior's _finders() method. Overwrite it to add finders to the model during initialization phase.

// ...

class Taggable extends \li3_behaviors\data\model\Behavior {
	// ...

	protected static function _finders($model, $behavior) {
		$model::finder('tag', function($params, $next) use ($behavior) {
			// ...
			return $next($params);
		});
	}

	// ...

Copyright & License

Copyright 2010 Union of RAD. All rights reserved. This library is distributed under the terms of the BSD 3-Clause License. The full license text can be found in the LICENSE.txt file.

Credits for previous Implementations

unionofrad/li3_behaviors 适用场景与选型建议

unionofrad/li3_behaviors 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.01k 次下载、GitHub Stars 达 4, 最近一次更新时间为 2017 年 03 月 26 日, 在 PHP 生态内属于活跃度较高的组件。

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

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

围绕 unionofrad/li3_behaviors 我们能提供哪些服务?
定制开发 / 二次开发

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

BUG 修复 & 性能优化

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

项目外包 & 长期维护

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

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

统计信息

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

GitHub 信息

  • Stars: 4
  • Watchers: 7
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: BSD-3-Clause
  • 更新时间: 2017-03-26