unionofrad/li3_behaviors

li₃ PHP 框架的模型行为

安装次数: 1,005

依赖项: 4

建议者: 0

安全: 0

星标: 4

关注者: 9

分支: 1

开放问题: 0

类型:lithium-library

v2.2.3 2019-09-16 07:50 UTC

README

这个库提供了实现模型行为的基类。模型行为提供了一种简单的方式来扩展模型。这种模式允许将常见逻辑封装在行为中,以保持模型轻量级,并由其自身的业务逻辑组成。

安装

首选的安装方法是使用 composer。您可以通过以下方式将库作为依赖项添加:

composer require unionofrad/li3_behaviors

li₃ 插件必须在您的应用程序引导阶段注册,因为它们使用不同的(更快)自动加载器。

Libraries::add('li3_behaviors')

官方手册提供了有关如何注册插件以及使用替代安装方法(例如,通过 Git)的更多信息。

使用

管理和加载行为

首先,要在模型中添加使用行为的能力,请在您的模型中使用行为特性。之后,在模型类的 $_actsAs 属性中定义您计划使用的所有行为。

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

   use li3_behaviors\data\model\Behaviors;

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

Behaviors 特性还在模型中提供了一些静态方法,允许按以下方式管理行为。

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

创建行为

现在,我们已经能够加载和管理行为,可以创建自己的行为,它必须扩展 Behavior 基类。在以下示例中,我们在 extensions/data/behavior/Sluggable.php 中创建了一个 Sluggable 行为。

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

行为配置

可以通过行为内的 config() 访问每个行为的配置。默认情况下,将自动使用用户提供的配置(来自模型类的 $_actsAs 属性)和行为提供的默认值(作为 $_defaults)设置行为的默认配置。

默认值将使用简单的数组添加($config += $defaults)与提供的配置合并。如果您想更改配置合并的方式,请继续阅读。

提供自定义配置逻辑

行为通常对配置有不同的要求。在某些情况下,只需要合并一个一维数组,在其他情况下,必须合并或以自定义方式归一化嵌套的多维数组。

这就是为什么可以很容易地由自己(实现者)控制默认值与提供的配置的合并 - 默认情况下,我们执行简单的单维合并,将默认值和配置相加。要控制配置合并,请覆盖基类中的 _config() 方法。

在以下示例中,我们将合并行为默认值时归一化某些配置选项。

// ...

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

_config() 方法接收配置和 $_defaults 中定义的默认值作为第三个和第四个参数。该方法必须最终返回应用于行为实例的配置。

将静态方法公开给模型

行为中存在的任何公共静态方法都会自动公开在模型上。这允许轻松地向模型添加方法。每个公开的静态方法都将其当前模型类名称作为第一个参数,将行为实例作为第二个参数。

如果您需要查询模型以获取结果或想从行为中检索配置,这将很有用。

以下示例显示了如何将令牌生成方法公开给模型。

// ...

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

将实例方法公开给模型

类似于公开静态方法,实例方法也可以轻松公开给模型。行为中实现的所有具体方法都将被公开。除了$entity参数外,每个行为方法还将接收模型的名称和行为实例作为第二个参数,即用于访问配置。

// ...

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

	// ...

动态添加模型实例方法

有时您需要动态地向模型实例添加方法。例如,当行为字段的名称是用户可配置的,并需要将其作为方法添加到实体上时。

这可以通过覆盖_methods()方法并返回一个按模型实例上的别名键控的方法数组来实现。

// ...

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

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

	// ...

上述示例行为将使模型返回的每个实体都启用以下方法。

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

将过滤器附加到模型上

要修改现有的模型方法,应使用过滤器。如果您的行为需要使用过滤器,一个好的地方是在行为体的_filters()方法中附加它们。覆盖它以在初始化阶段将过滤器附加到模型。

// ...

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) {
		// ...
	}

	// ...

将查找器附加到模型上

要向模型的查找方法添加查找器,应使用查找器。如果您的行为需要使用查找器,一个好的地方是在行为体的_finders()方法中附加它们。覆盖它以在初始化阶段将查找器添加到模型。

// ...

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

	// ...

版权 & 许可

版权 2010 Union of RAD。保留所有权利。本库根据BSD 3-Clause License分发。完整的许可文本可以在LICENSE.txt文件中找到。

前版实现致谢