跳至正文

升级 Valinor

从 1.x 升级到 2.x

概括

消息/错误处理的更改

对消息和错误的处理方式进行了一些更改。

现在,当映射期间发生错误时,可以更轻松地获取消息:

try {
    (new \CuyZ\Valinor\MapperBuilder())->mapper()->map(/* … */);
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
    // Before (1.x):
    $messages = \CuyZ\Valinor\Mapper\Tree\Message\Messages::flattenFromNode(
        $error->node()
    );

    // After (2.x):
    $messages = $error->messages();
}

一些从消息中访问信息的方法已被移动:

// Before (1.x):
$name = $message->node()->name();
$path = $message->node()->path();
$type = $message->node()->type();
$type = $message->node()->sourceValue();

// After (2.x):
$name = $message->name();
$path = $message->path();
$type = $message->type();
$type = $message->sourceValue();

消息代码的更改

映射过程中可能抛出的所有消息的代码均已更改。他们现在更具表现力。以下是更改及其替换的详尽列表:

  • 1642183169 → cannot_find_object_builder器
  • 1632903281 → invalid_source
  • 1607027306 → cannot_resolve_type_from_union
  • 1654273010 → invalid_list_key
  • 1630678334 → invalid_value
  • 1630946163 → invalid_array_key
  • 1655449641 → missing_value
  • 1736015505 → value_is_empty_array
  • 1736015714 → value_is_empty_list
  • 1710263908 → value_is_not_null
  • 1618739163 → value_is_not_iterable
  • 1710262975 → too_many_resolved_types_from_union
  • 1655117782 → unexpected_keys
  • 1630686564 → cannot_parse_datetime_format

请注意,许多与无效标量值映射相关的错误消息现在都有一个特定的代码,而它以前是unknown 。

引入了NormalizerBuilder作为规范化器的主要入口

NormalizerBuilder类已经被引入,现在将成为实例化规范化器的主要入口。因此, MapperBuilder中用于配置和返回规范化器的方法已被删除。

此决定旨在明确区分映射器和规范化器配置 API,因为在使用这两种服务时可能会出现混淆。

NormalizerBuilder可以这样使用:

$normalizer = (new \CuyZ\Valinor\NormalizerBuilder())
    ->registerTransformer(
        fn (\DateTimeInterface $date) => $date->format('Y/m/d')
    )
    ->normalizer(\CuyZ\Valinor\Normalizer\Format::array())
    ->normalize($someData);

删除了简单缓存 (PSR-16) 处理

简单缓存 PSR 要求已从库中删除。这意味着外部 PSR 实现不能再与该库一起使用。

做出这个决定是因为缓存的条目总是生成 PHP 代码,这不是 PSR 的目的。当使用带有自定义实现的库时,这会导致混乱和不正确的行为。

该库现在使用自己的缓存接口,但提供的实现没有改变,因此升级应该非常简单。

提醒一下,这是在应用程序中注入缓存的方式:

$cache = new \CuyZ\Valinor\Cache\FileSystemCache('path/to/cache-directory');

if ($isApplicationInDevelopmentEnvironment) {
    $cache = new \CuyZ\Valinor\Cache\FileWatchingCache($cache);
}

(new \CuyZ\Valinor\MapperBuilder())
    ->withCache($cache)
    ->mapper()
    ->map(SomeClass::class, [/* … */]);

另请注意,此更改导致了重构,这应该会提高文件监视功能的信心:以前,当文件在开发过程中发生更改时,缓存条目有时不会正确失效。现在这应该更好了。

删除了MapperBuilder::enableFlexibleCasting()

该方法已被删除,取而代之的是三种不同的模式:

应使用上述方法来适应更具体的用例。

删除了MapperBuilder::alter()

此功能已被删除,以支持更灵活和更强大的映射器转换器。

请注意, MapperBuilder::alter()从未被真正记录过,因此很有可能只有少数用户在使用它。

将@pure标记添加到MapperBuilder和NormalizerBuilder方法

@pure注释在之前的提交中被删除,原因如下:

由于当前使 PHPStan 和 Psalm 使用纯功能所需的开销,这些要求已被删除。

不幸的是,由于 PHPStan 和 Psalm 无法自动检测提供给MapperBuilder可调用值是否是纯的,因此用户被迫手动添加@pure注释。

这一决定旨在在图书馆的严格性和用户体验之间取得公平的平衡。

在与@pure爱好者讨论后,决定重新引入它们。这次,通过使用该库提供的开箱即用的插件,可以轻松抑制 PHPStan 和 Psalm 报告的错误。

要在 PHPStan 中全局抑制这些错误,必须将以下行添加到phpstan.neon :

includes:
    - vendor/cuyz/valinor/qa/PHPStan/valinor-phpstan-suppress-pure-errors.php

要在 Psalm 中全局抑制这些错误,必须将以下行添加到psalm.xml中:

<xi:include href="qa/Psalm/valinor-psalm-suppress-pure-errors.xml"
            xmlns:xi="http://www.w3.org/2001/XInclude"/>

删除的类和接口

以下类/接口是初始版本的一部分,但库未使用。尽管没有人应该使用它们,但它们是公共 API 的一部分,因此删除它们是一项重大更改。

  • \CuyZ\Valinor\Mapper\Source\IdentifiableSource
  • \CuyZ\Valinor\Utility\Priority\HasPriority
  • \CuyZ\Valinor\Utility\Priority\PrioritizedList

标记为@internal类构造函数

一些构造函数已被标记为@internal ,以便通过允许在不破坏公共 API 的情况下更改这些方法来简化将来的维护。

此更改不应影响用户,因为无论如何他们都不应该直接使用这些。

受影响的构造函数列表:

  • \CuyZ\Valinor\Mapper\Tree\Message\Messages::__construct
  • \CuyZ\Valinor\Mapper\Tree\Message\NodeMessage::__construct
  • \CuyZ\Valinor\Normalizer\ArrayNormalizer::__construct
  • \CuyZ\Valinor\Normalizer\JsonNormalizer::__construct
  • \CuyZ\Valinor\Normalizer\StreamNormalizer::__construct

完整的不兼容变更列表

  • 删除了\Psr\SimpleCache\CacheInterface依赖项
  • 已删除 \CuyZ\Valinor\MapperBuilder::alter()
    • 使用\CuyZ\Valinor\MapperBuilder::registerConverter代替
  • 已删除 \CuyZ\Valinor\MapperBuilder::enableFlexibleCasting()
    • 请改用以下方法:
      • \CuyZ\Valinor\MapperBuilder::allowScalarValueCasting()
      • \CuyZ\Valinor\MapperBuilder::allowNonSequentialList()
      • \CuyZ\Valinor\MapperBuilder::allowUndefinedValues()
  • 已删除 \CuyZ\Valinor\MapperBuilder::registerTransformer()
    • 使用\CuyZ\Valinor\NormalizerBuilder代替
  • 已删除 \CuyZ\Valinor\MapperBuilder::normalizer()
    • 使用\CuyZ\Valinor\NormalizerBuilder代替
  • 将\CuyZ\Valinor\MapperBuilder::warmup()重命名为\CuyZ\Valinor\MapperBuilder::warmupCacheFor()
  • 已删除 \CuyZ\Valinor\Mapper\MappingError::node()
    • 使用\CuyZ\Valinor\Mapper\MappingError::messages()代替
  • 添加了\CuyZ\Valinor\Mapper\MappingError::type()
  • 添加了\CuyZ\Valinor\Mapper\MappingError::source()
  • 删除了\CuyZ\Valinor\Mapper\Tree\Node
  • 删除了\CuyZ\Valinor\Mapper\Tree\NodeTraverser
  • 删除了\CuyZ\Valinor\Mapper\Tree\Message\Messages::flattenFromNode()
  • 已删除 \CuyZ\Valinor\Mapper\Tree\Message\NodeMessage::node()
    • 请改用以下方法:
      • \CuyZ\Valinor\Mapper\Tree\Message\NodeMessage::name()
      • \CuyZ\Valinor\Mapper\Tree\Message\NodeMessage::path()
      • \CuyZ\Valinor\Mapper\Tree\Message\NodeMessage::type()
      • \CuyZ\Valinor\Mapper\Tree\Message\NodeMessage::sourceValue()
  • 更改了\CuyZ\Valinor\Mapper\Tree\Message\NodeMessage::__construct()签名
  • 删除了\CuyZ\Valinor\Mapper\Source\IdentifiableSource
  • 删除了\CuyZ\Valinor\Utility\Priority\HasPriority
  • 删除了\CuyZ\Valinor\Utility\Priority\PrioritizedList
  • 将\CuyZ\Valinor\Mapper\Tree\Message\Messages::__construct标记为@internal
  • 将\CuyZ\Valinor\Mapper\Tree\Message\NodeMessage::__construct为@internal
  • 将\CuyZ\Valinor\Normalizer\ArrayNormalizer::__construct标记为@internal
  • 将\CuyZ\Valinor\Normalizer\JsonNormalizer::__construct标记为@internal
  • 将\CuyZ\Valinor\Normalizer\StreamNormalizer::__construct标记为@internal