underpin/decision-list-loader

Underpin 的决策列表加载器

1.0.0 2021-05-06 00:44 UTC

This package is auto-updated.

Last update: 2024-09-11 23:13:45 UTC


README

助助于向 WordPress 网站添加决策列表的加载器。

安装

使用 Composer

composer require underpin/decision-list-loader

手动

此插件使用内置的自动加载器,因此只要它在 Underpin 之前被要求,就应该按预期工作。

require_once(__DIR__ . '/underpin-decision-lists/decision-lists.php');

设置

  1. 安装 Underpin。请参阅 Underpin 文档
  2. 根据需要注册新的决策列表。

决策列表

通常,WordPress 插件仅依赖 WordPress 钩子来确定扩展逻辑。这对于简单解决方案来说是可以的,但一旦几个插件试图相互覆盖,就会变得非常麻烦。最大的问题是确定决策的实际逻辑是 分散的。由于没有单一的真实来源来规定逻辑的顺序,更不用说实际的 选择是什么,因此您没有简单的方法来理解 为什么 插件决定这样做。

决策列表旨在通过将所有扩展集中在一个注册表中来使工作更容易。当启用 WP_DEBUG 时,此注册表会导出到 Underpin 控制台,因此可以清楚地了解此网站的逻辑层次结构。

如果您正在调试实时站点,可以使用 PHP 控制台工具(如调试栏控制台)输出决策列表。

var_dump(plugin_name_replace_me()->decision_lists()->get('email'));

设置

本质上,决策列表不过是一个加载器类,可以以相同的方式处理。

假设我们想要创建一个决策列表,允许人们覆盖插件中的电子邮件地址。这需要检查电子邮件地址的选项值,并回退到硬编码的地址。它还需要可能由其他插件覆盖此值。

在传统的 WordPress 中,您可能会看到在函数末尾使用 apply_filters 来完成此操作,如下所示

function get_email_address(){
 
 return apply_filters('plugin_name_replace_me_email_address',get_option('email_address', 'admin@webmaster.com'));
}

然而,使用决策列表,这被放在一个类中,并且该类可以被扩展。如下所示

/**
 * Class Email To
 * Class Email to list
 *
 * @since   1.1.0
 * @package DFS_Monitor\Factories
 */
class Email_To extends Decision_List {

	public $dedecision listion = 'Determines which email address this plugin should use.';
	public $name = 'Email Address';

	/**
	 * @inheritDoc
	 */
	protected function set_default_items() {

		$this->add( 'option', new class extends Integration_Frequency_Decision {

			public $id = 'option';
			public $name = 'Option Value';
			public $dedecision listion = 'Uses the value of the db option, if it is set.';
			public $priority = 100;


			public function is_valid( $params = [] ) {
				if(!is_email(get_option('email_address'))){
				  return plugin_name_replace_me()->logger()->log(
				    'notice',
                    'email_address_option_invalid',
                    'A decision tree did not use the option value because it is not set.'
                  );
                } else{
                  return true;  
              }             
			}

			/**
			 * @inheritDoc
			 */
			public function valid_actions( $params = [] ) {
				return get_option('email_address');
			}
		} );


		$this->add( 'hard_coded', new class extends Integration_Frequency_Decision {

			public $id = 'hard_coded';
			public $name = 'Hard coded email';
			public $dedecision listion = 'Uses a hard-coded email address for this site.';
			public $priority = 1000;

			public function is_valid( $params = [] ) {
				return true;
			}

			public function valid_actions( $params = [] ) {
				return 'admin@webmaster.com';
			}
		} );
	}
}

请注意,我这里使用匿名类只是为了将所有内容保持在单个文件中。您绝对 不需要 使用匿名类。事实上,在大多数情况下您不应该这样做。如果您将类引用作为字符串传递,它将不会实例化类,除非它被显式调用。这节省了资源并使事物保持快速。

每个类内部的 $priority 值告诉决策树首先尝试使用哪个选项。如果它返回一个 WP_Error,则将其移动到下一个。一旦找到返回 true 的选项,它就会从 valid_actions 方法获取值,然后继续。

像自定义记录器类一样,需要在 Service_Locator 中注册。

	/**
	 * Set up active loader classes.
	 *
	 * This is where you can add anything that needs "registered" to WordPress,
	 * such as shortcodes, rest endpoints, blocks, and cron jobs.
	 *
	 * All supported loaders come pre-packaged with this plugin, they just need un-commented here
	 * to begin using.
	 *
	 * @since 1.0.0
	 */
	protected function _setup() {
      plugin_name_replace_me()->decision_lists()->add('email', '\Plugin_Name_Replace_Me\Decision_Lists\Email_To');
	}

最后,我们可以在我们的 get_email_address 函数中直接使用此决策列表

function get_email_address(){
 
 // Decide which action we should take.
 $decide = plugin_name_replace_me()->decision_lists()->get('email')->decide();

 // Return the valid decision.
 if(!is_wp_error($decide) && $decide['decision'] instanceof Decision){
   return $decide['decision']->valid_actions();
 }

 // Bubble up the error, otherwise.
 return $decide;
}

现在我们已经设置了,它可以由其他插件使用 add 方法扩展。下面的示例将强制决策列表在运行其他任何选项之前运行。

plugin_name_replace_me()->decision_lists()->get('email')->add('custom_option',new class extends \Underpin\Abstracts\Decision{

  // Force this to run before all other options
  public $priority = 50;
  public $name = 'Custom Option Name';
  public $dedecision listion = 'This custom name is used in an extension, and overrides the default';

  public function is_valid($params = []){
    // TODO: Implement is_valid() method.
  }

  public function valid_actions($params = []){
  // TODO: Implement valid_actions() method.
  }


});

示例

一个非常基本的例子可能看起来像这样。

\Underpin\underpin()->decision_lists()->add( 'example_decision_list', [
	// Decision one
	[
		'valid_callback'         => '__return_true',
		'valid_actions_callback' => '__return_empty_string',
		'name'                   => 'Test Decision',
		'description'            => 'A single decision',
		'priority'               => 500,
	],

	// Decision two
	[
		'valid_callback'         => '__return_true',
		'valid_actions_callback' => '__return_empty_array',
		'name'                   => 'Test Decision Two',
		'description'            => 'A single decision',
		'priority'               => 1000,
	],
] );

或者,您可以直接扩展 决策列表 并直接引用扩展的类,如下所示

underpin()->decision_lists()->add('key','Namespace\To\Class');

这对于使用决策列表特别有用,因为它们往往很长且嵌套很深。

获取决策结果

当决策列表确定一个操作时,它会做三件事

  1. 按照优先级对所有决策进行排序,数值越小优先级越高。
  2. 遍历每个项目,并在第一个通过相应测试的决定处停止。
  3. 返回决定的 valid_actions 回调的结果。

上面的示例将返回 '',因为第一个通过的项目将是具有最低优先级并通过的项目。

underpin()->decision_lists()->decide('example_decision_list', [] );

第二个参数,$params 是一个数组,包含传递给 valid_callbackvalid_actions_callback 的参数。