grithin/record

管理网页资源的包含

0.1 2021-07-22 00:17 UTC

This package is auto-updated.

Last update: 2024-09-22 07:07:39 UTC


README

一个任意深度的数组,用于跟踪更改、触发事件,

旨在成为一个与数据库记录匹配的可观察者,允许像数组一样处理记录,跟踪更改,处理深层数据结构,并允许监听器对更改事件做出反应。

(类似于SplSubject,但由于SplSubject使用无用的SplObserver,因此未实现)

composer require grithin/record

使用

基本

跟踪任意深度的结构

$data = [
	'id' => 1,
	'name' => 'bob',
	'children' => [
		['name' => 'sue']
	]
];

$record = new \Grithin\Record($data);
$record['name'] = 'bill';

$record->changes(); #> ['name'=>'bill']

$record->apply(); # or alias $record->save();

$record->changes(); #> []

$record['children'][] = ['name'=>'jan'];
$record->changes();
/*>
{"children": {
        "1": {
            "name": "jan"}}}
*/
unset($record['children'][0]);
$record->changes();
/*>
{"children": [
        {"_class": "Grithin\\MissingValue"},
        {"name": "jan"}]}
*/

获取器、设置器和事件

# Lets make a mock database
$database_records = [
	1=>[
		'id'=>1,
		'name'=>'bob',
		'children' => '[{"name":"sue"}]'
]];

#+ make the getter and setter methods {
$get_from_db = function($Record) use ($database_records){
	return $database_records[$Record->id];
};
$set_to_db = function($Record, $changes) use ($database_records){
	$record_data = $database_records[$Record->id];
	$record_data= \Grithin\Dictionary::diff_apply($record_data, $changes);
	$database_records[$Record->id] = $record_data;
	return $record_data;
};
#+ }

# initialize the record, using the 'id' option
$record = new \Grithin\Record(false, $get_from_db, $set_to_db, ['id'=>1]);
$record->get();

# let's capitalize the name when we set it
$capitalize_name = function($Record, $diff){
	if(isset($diff['name'])){
		$diff['name'] = strtoupper($diff['name']);
	}
};
$record->before_change($capitalize_name);

$record['name'] = 'bill';
# the name will become capitalized because of the event listener
$record['name']; #> BILL


# the children key points to a JSON string
$record['children']; #> '[{"name":"sue"}]'

# We can make it so JSON is automatically encoded and decoded when moving between the database
$jsonify = function($Record, $diff){
	if(isset($diff['children'])){
		$diff['children'] = json_encode($diff['children']);
	}
};
$unjsonify = function($Record){
	if(isset($Record['children'])){
		$Record->record['children'] = json_decode($Record->record['children'], true);
	}
};

$record->after_get($unjsonify);
$record->before_update($jsonify);

$record->get();

# now can access the full structure
$record['children'][0]['name']; #> sue
$record['children'][0]['name'] = 'jan';
$record->save(); # will encode the json for the db, then decode it for regular access

$record['children'][0]['name']; #> 'jan'

var_export($database_records);
/* >
array (
  1 =>
  array (
    'id' => 1,
    'name' => 'bob',
    'children' => '[{"name":"sue"}]',
  ),
)
*/

以上的一些额外亮点。

after_get函数unjsonify中,使用$Record->record['children']以避免触发更多事件。如果你不介意before_changeafter_change被运行,可以使用$Record['children']

当以$Record['name'] = 'bob'的方式设置记录时,每次赋值都会触发两个事件。可能更倾向于进行批量更改,这将允许多个东西更改,并且只会触发两个事件。这可以在本地副本和源代码中完成

# update local copy
$Record->local_update(['name'=>'bill', 'age'=>1]);

# update both
$Record->update(['name'=>'bill', 'age'=>1]);

概述

事件、观察者

类型

  • EVENT_AFTER_GET : 调用getter函数后立即。这可以用于解码JSON
  • EVENT_CHANGE_BEFORE
  • EVENT_CHANGE_AFTER
  • EVENT_UPDATE_BEFORE : 在更新源之前。这可以用于重新编码JSON
  • EVENT_UPDATE_AFTER

便捷函数after_getbefore_changeafter_changebefore_updateafter_update将在对应的事件上调用参数函数,参数为($this, $details),其中在$details中是一个表示更改的数组对象。

Events

(EVENT_UPDATE_AFTER在EVENT_AFTER_GET之后运行,因为它可能需要通过EVENT_AFTER_GET重新格式化数据)

更新和更改事件只有在有更改时才会触发。

提供给事件观察者的diff参数是一个ArrayObject,该对象在将diff应用于记录时使用。因此,在“before”事件观察者内部修改diff将影响结果记录。如果diff计数变为0,则不会应用更改。

观察者的潜在用途

  • 修改特定列(将时间戳转换为日期时间格式)
  • 检查记录状态的有效性。如果状态不良,则抛出异常或清除diff
  • 创建组合列。例如:total_cost = cost1 + cost2
  • 记录特定更改