跳至正文

更新日志 0.4.0 — 2022 年 1 月 7 日

重要变更

允许映射到任何类型

以前, TreeMapper::map方法仅允许映射到对象。现在可以映射到库处理的任何类型。

例如,可以映射到对象数组:

$objects = (new MapperBuilder())->mapper()->map(
    'array<' . SomeClass::class . '>',
    [/* … */]
);

对于简单的用例,可以使用数组形状:

$array = (new MapperBuilder())->mapper()->map(
    'array{foo: string, bar: int}',
    [/* … */]
);

echo $array['foo'];
echo $array['bar'] * 2;

这个新功能改变了映射器可能的行为,这意味着静态分析工具需要帮助才能正确理解类型。现在提供了 PHPStan 的扩展和 Psalm 的插件,可以将它们包含在项目中以自动增加类型覆盖率。


更好地处理消息

处理消息时,自定义消息内容有时会很有用 - 例如翻译它。

辅助类\CuyZ\Valinor\Mapper\Tree\Message\Formatter\MessageMapFormatter可用于提供新格式列表。它可以用一个数组实例化,其中每个键代表:

  • 要替换的消息的代码
  • 需要替换的消息内容
  • 要替换的消息的类名

如果没有找到这些内容,消息的内容将保持不变,除非为类提供了默认内容。

如果找到这些键之一,则将使用数组条目来替换消息的内容。该条目可以是纯文本,也可以是可调用的,将消息作为参数并返回字符串;例如,建议在使用翻译服务的情况下使用可调用函数 - 以避免无用的贪婪操作。

在任何情况下,内容都可以包含占位符,这些占位符将按顺序自动替换为:

  1. 消息的原始代码
  2. 消息的原始内容
  3. 节点类型的字符串表示形式
  4. 节点名称
  5. 节点的路径
try {
    (new \CuyZ\Valinor\MapperBuilder())
        ->mapper()
        ->map(SomeClass::class, [/* … */]);
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
    $node = $error->node();
    $messages = new \CuyZ\Valinor\Mapper\Tree\Message\MessagesFlattener($node);

    $formatter = (new MessageMapFormatter([
        // Will match if the given message has this exact code
        'some_code' => 'new content / previous code was: %1$s',

        // Will match if the given message has this exact content
        'Some message content' => 'new content / previous message: %2$s',

        // Will match if the given message is an instance of `SomeError`
        SomeError::class => '
            - Original code of the message: %1$s
            - Original content of the message: %2$s
            - Node type: %3$s
            - Node name: %4$s
            - Node path: %5$s
        ',

        // A callback can be used to get access to the message instance
        OtherError::class => function (NodeMessage $message): string {
            if ((string)$message->type() === 'string|int') {
                // …
            }

            return 'Some message content';
        },

        // For greedy operation, it is advised to use a lazy-callback
        'bar' => fn () => $this->translator->translate('foo.bar'),
    ]))
        ->defaultsTo('some default message')
        // …or…
        ->defaultsTo(fn () => $this->translator->translate('default_message'));

    foreach ($messages as $message) {
        echo $formatter->format($message);    
    }
}

在映射过程中自动推断对象并集

当映射器需要将源映射到对象的联合时,它将根据对象所需的参数以及源中包含的值尝试猜测它将映射到哪个对象。

final class UnionOfObjects
{
    public readonly SomeFooObject|SomeBarObject $object;
}

final class SomeFooObject
{
    public readonly string $foo;
}

final class SomeBarObject
{
    public readonly string $bar;
}

// Will map to an instance of `SomeFooObject`
(new \CuyZ\Valinor\MapperBuilder())
    ->mapper()
    ->map(UnionOfObjects::class, ['foo' => 'foo']);

// Will map to an instance of `SomeBarObject`
(new \CuyZ\Valinor\MapperBuilder())
    ->mapper()
    ->map(UnionOfObjects::class, ['bar' => 'bar']);

⚠ 重大变更

  • 映射期间发生错误时添加对根节点的访问( 54f608 )
  • 允许映射到任何类型( b2e810 )
  • 允许对象构建器在没有源的情况下生成参数( 8a7414 )
  • 将节点消息包装在适当的类中( a805ba )

新功能

  • 在映射期间引入对象推断的自动联合( 79d7c2 )
  • 引入辅助类MessageMapFormatter ( ddf69e )
  • 引入辅助类MessagesFlattener ( a97b40 )
  • 引入助手NodeTraverser用于节点上的递归操作 ( cc1bc6 )

错误修复

  • 处理嵌套特性编译( d2795b )
  • 将禁止的混合类型视为无效类型( 36bd36 )
  • 将联合类型解析错误视为消息 ( e834cd )
  • 使用锁定的软件包版本进行质量保证工作流程 ( 626f13 )

其他

  • 忽略 git 导出中的更新日志配置文件 ( 85a6a4 )
  • 提升 PHPStan 版本 ( 0144bf )