liutec/cfgtokenlib

PHP 配置令牌解析器和注入库

v1.1.25 2020-10-08 07:51 UTC

README

Build Status Scrutinizer Code Quality Code Coverage

ConfigToken 库提供以下类来帮助进行令牌解析、值格式化和注入

  • TokenParser:可配置的字符串解析类,用于提取令牌集合。
  • TokenCollection:与特定令牌解析器实例结合使用的通用令牌集合类,用于将令牌解析为值并应用给定的过滤器。
  • TokenInjector:提供了一种方法,将解析后的令牌值集合注入到原始字符串中。

一组接口和工厂,用于创建自定义解析器和过滤器

  • TokenResolverInterface:用于创建自定义令牌值解析器的接口;
  • TokenFilterInterface:用于创建自定义令牌值过滤器的接口;
  • TokenFilterFactory:用于保留和注册令牌值过滤器的工厂类。

以及基类,用于扩展和自定义最常见的两种用例

  • RegisteredTokenResolver:根据给定的单维关联数组(令牌名称 > 值)解析令牌值。
  • ScopeTokenResolver:根据给定的多维关联数组解析令牌值。

令牌解析器

令牌解析器可用于解析字符串并根据可配置的正则表达式提取令牌集合。

$tokenParser = new TokenParser();
$tokens = $tokenParser->parseString($input);

或显式设置令牌分隔符和过滤器分隔符

$tokenParser = new TokenParser('|', null, '[[', ']]');

// also possible via setters
$tokenParser
  ->setFilterDelimiter('|')
  ->setTokenPrefix('[[')
  ->setTokenSuffix(']]')
;

$tokens = $tokenParser->parseString($input);

或显式设置令牌正则表达式和过滤器分隔符

$tokenParser = new TokenParser('|', '/\[\[s+(.*?)\]\]/');

// also possible via setters
$tokenParser
    ->setFilterDelimiter('|')
    ->setTokenRegex('/\[\[s+(.*?)\]\]/')
;

$tokens = $tokenParser->parseString($input);

示例输入

The [[attribute|lower]] [[color]] [[mammal|upper]] jumps over the [[target]].\n
The [[mammal]] is [[attribute]].

已识别的令牌

[[attribute|lower]]
  token name: "attribute"
  filters: ["lower"]
  offsets: [4]

[[color]]
  token name: "color"
  offsets: [24]

[[mammal|upper]]
  token name: "mammal"
  filters: ["upper"]
  offsets: [34]

[[target]]
  token name: "target"
  offsets: [66]

[[mammal]]
  token name: "mammal"
  offsets: [82]

[[attribute]]
  token name: "attribute"
  offsets: [96]

提取的令牌可以通过设置它们的值直接解析。

$mammal = $tokens->findByName('mammal');
foreach ($mammal as $token) {
  $token
    ->setUnfilteredTokenValue('Fox')
    ->applyFilters()
  ;
}
$output = TokenInjector::injectString($input, $tokens);
The [[attribute|lower]] [[color]] FOX jumps over the [[target]].\n
The Fox is [[attribute]].

或使用预定义或自定义的 TokenResolver。

$resolver = new RegisteredTokenResolver(
  array(
    'attribute' => 'QUICK',
    'color' => 'brown',
    'target' => 'lazy dog',
  )
);
$tokens->resolve($resolver);
$output = TokenInjector::injectString($output, $tokens);
The quick brown FOX jumps over the lazy dog.\n
The Fox is QUICK.

可以在不重新解析令牌的情况下对结果字符串进行多步注入。

无论通过哪种方法解析令牌值,都可以在注入之前应用自定义或预定义的值过滤器。

树编译器

树编译器可用于通过类似于继承的模式合并多个结构。为了使其成为可能,所有结构都必须符合预定的模式。

树编译器使用示例

$treeCompiler = new TreeCompiler();
$result = $treeCompiler->compileLocalFile('example.json');
$treeCompiler->save($result, 'result.json');

phrase.json

{
  "phrase": {
    "line1": "The [[attribute|lower]] [[color]] [[mammal|upper]] jumps over the [[target]].",
    "remove_me": "This line must be removed",
    "line2": "The [[mammal]] is [[attribute]]."
  }
}

example.json

{
  "include": {
    "a": {
      "type": "file",
      "src": "./phrase.json"
      "resolve": [
        {
          "type": "registered",
          "values": {
            "attribute": "QUICK",
            "color": "brown",
            "target": "lazy dog"
          }
        }
      ]
    }
  },
  "remove": {
    "phrase": {
      "remove_me": null
    }
  },
  "add": {
    "phrase": {
      "line3": "The end."
    }
  }
}

result.json

{
  "phrase": {
    "line1": "The quick brown FOX jumps over the lazy dog.",
	"line2": "The Fox is QUICK.",
    "line3": "The end."
  }
}

输入结构模式(关联数组)

  • include:可选。如果存在,则首先处理。描述包含的外部引用和包含组的关联数组;
    • xref:必需。描述包含的外部结构的关联数组;

      • <xref name>:必需。字符串。外部引用的本地声明名称;
        • type:必需。字符串。外部引用的类型。可能的值有
          • file:本地文件外部
            • <file path>:本地文件的路径;可以是绝对路径(/)或相对于当前文件(./)的相对路径。
          • url:URL 外部引用;
            • <url>:HTTP 可访问的远程文件的 URL。如果响应 Content-Type 与已知的 XrefResolver 不匹配,则 URL 路径中的文件扩展名将用于确定适当的反序列化器。
          • inline:具有相同结构模式的内联数据。
          • <custom>:通过 XrefResolverFactory 注册的自定义外部引用处理类;
        • src:如果类型不是内联,则必需。描述 xref 位置的字符串,根据 type 格式化(参见上述内容);
        • resolve:可选。按顺序排列的解析器设置列表。此键描述了令牌解析器及其用于替换从外部引用获取的结构中令牌的值。如果有多个,则将按给定顺序使用解析器。
          • 未命名的解析器设置:必需。描述令牌解析器配置的关联数组。

            • type:必需。字符串。标识令牌解析器类的类型。可能的值有

              • 已注册|扩展RegisteredTokenResolver的自定义解析器
              • 作用域|扩展ScopeTokenResolver的自定义解析器
            • options:字符串。要在TokenResolverClass上设置的选项。所有解析器都通用的选项有

              • ignore-unknown-tokens:布尔值。默认 true。如果 false,解析器遇到未知令牌时将引发编译错误。对于链式解析器,此值必须对所有解析器(最后一个除外)为 true
              • ignore-unknown-filters:布尔值。默认 true。如果 false,解析器遇到未知令牌值过滤器时将引发编译错误。
              • token-regex:字符串。默认 "/\[\[+(.*?)\]\]/"。用于识别令牌的正则表达式。如果指定,解析器将忽略 token-prefixtoken-suffix
              • token-prefix:可选。字符串。默认 "[["。默认正则表达式的令牌前缀。对于不需要覆盖 token-regex 但需要更改开始定界符的简单令牌。
              • token-suffix:可选。字符串。默认 "]]"。默认正则表达式的令牌后缀。对于不需要覆盖 token-regex 但需要更改结束定界符的简单令牌。
              • token-filter-delimiter:字符串。默认 "|"。用于在令牌名称中分隔多个令牌值过滤器的字符/字符串(例如,[[token_name|lower|dot]]

              以下选项适用于扩展 ScopeTokenResolver 基类的基础令牌解析器

              • scope-token-name:必需。字符串。用于标识解析器作用域的令牌名称。(例如,对于 scope-token-name = json-a,[[json-a:object.value]]
              • scope-token-name-delimiter:可选。字符串。默认 ":"。用于从作用域令牌名称到作用域值路径的定界符。
              • scope-token-level-delimiter:可选。字符串。默认 "."。用于在作用域值路径中分隔级别的字符/字符串。(例如,如果设置为 "->",则以下将匹配 [[json:object->value]]

              *注意,令牌内部使用的所有定界符都必须不同。

            以下键中只需一个(如果两个都存在,编译器将引发语法错误)

            • values:包含形成令牌解析器作用域的名称-值对的关联数组。
            • values-xref:描述包含形成令牌解析器作用域的名称-值对的外部引用的类型和来源的关联数组。
              • type:必需。字符串。外部引用的类型。(参见上述内容)
              • src:必需。描述xref位置的字符串,根据 type 格式化(参见上述内容);

            作用域值仅适用于作用域令牌解析器。

    • main:外部引用名称的有序列表,如果未请求特定包含组。如果 include 部分中只有一个Xref,则可以省略此组。

    • <include group name>:由外部引用名称的有序列表表示的命名包含组;

  • remove:可选。如果存在,则为第二个要处理的。描述要从合并的结构中获得的结果中删除的键的关联数组。
  • add(添加): 可选。如果存在,则最后处理。关联数组,描述要添加或覆盖的键,这些键将用于合并包含的结构得到的结果;

如果结构的第一级中缺少 include(包含)、remove(移除)和 add(添加)键,则认为所有键都属于 add(添加)键之下。

{
  "include": {
    "xref": {
      "<xref name>": {
        "type": "file|url|git|<custom>",
        "src": "<file path>|<url>|[<git file>|<git file url>]",
        "resolve": [
          {
            "type": "registered|custom",
            "options": {
              "ignore-unknown-tokens": true,
              "ignore-unknown-filters": true,
              "token-regex": "/\[\[+(.*?)\]\]/",
              "token-prefix": "[[",
              "token-suffix": "]]",
              "token-filter-delimiter": "|"
            },
            "values": {
              "<token name 1>": "<token value 1>",
              "<token name n>": "<token value n>"
            },
            "values-xref": {
              "type": "file|url|git|<custom>",
              "src": "<file path>|<url>|[<git file>|<git file url>]"
            }
          }, {
            "type": "scope|custom",
            "options": {
              "ignore-unknown-tokens": true,
              "ignore-unknown-filters": true,
              "token-regex": "/\[\[+(.*?)\]\]/",
              "token-prefix": "[[",
              "token-suffix": "]]",
              "token-filter-delimiter": "|",
              "scope-token-name": "<token name>",
              "scope-token-name-delimiter": ":",
              "scope-token-level-delimiter": "."
            },
            "values": {
              "<token name 1>": "<token value 1>",
              "<token name 2>": {
                "<token level 2>": {
                  "<token leven n>": "<token value @level n>"
                },
              },
              "<token name n>": "<token value n>"
            },
            "values-xref": {
              "type": "...",
              "src": "...",
            }
          }
        ]
      }
    },
    "main": [
      "<xref name 1>",
      "<xref name n>"
    ],
    "<include group name>": [
      "<xref name 1>",
      "<xref name n>"
    ]
  },
  "remove": {
  },
  "add": {
  }
}