导入带格式的数据源(JSON、YAML 等)¶
可以使用Source帮助程序从格式化源导入数据,该帮助程序会在映射发生之前将数据转换为纯 PHP 结构。
该库为 JSON、YAML 和文件提供原生转换支持:
$source = \CuyZ\Valinor\Mapper\Source\Source::json($jsonString);
// or…
$source = \CuyZ\Valinor\Mapper\Source\Source::yaml($yamlString);
// or…
// File containing valid Json or Yaml content and with valid extension
$source = \CuyZ\Valinor\Mapper\Source\Source::file(
new SplFileObject('path/to/my/file.json')
);
(new \CuyZ\Valinor\MapperBuilder())
->mapper()
->map(SomeClass::class, $source);
提供给源的 JSON 或 YAML 可能无效,在这种情况下,可以捕获和操作异常。
try {
$source = \CuyZ\Valinor\Mapper\Source\Source::json('invalid JSON');
} catch (\CuyZ\Valinor\Mapper\Source\Exception\InvalidSource $exception) {
// Let the application handle the exception in the desired way.
// It is possible to get the original source with `$exception->source()`
}
修饰符¶
有时,源的格式和/或组织方式与值对象不同。修饰符可用于在映射发生之前更改源。
警告
将来可能会删除以下修饰符,以支持映射器转换器,应尽可能使用映射器转换器。修饰符仍然可用于向后兼容。
路径映射¶
此修饰符可用于使用点表示法更改源数据中的路径。
该映射是使用路径映射的关联数组来完成的。该数组必须以源路径作为键,以目标路径作为值。
源路径使用点符号(例如A.B.C ),并且可以包含一个*表示数组路径(例如A.B.*.C )。
final readonly class Country
{
/** @var non-empty-string */
public string $name;
/** @var list<City> */
public array $cities;
}
final readonly class City
{
/** @var non-empty-string */
public string $name;
public DateTimeZone $timeZone;
}
$source = \CuyZ\Valinor\Mapper\Source\Source::array([
'identification' => 'France',
'towns' => [
[
'label' => 'Paris',
'timeZone' => 'Europe/Paris',
],
[
'label' => 'Lyon',
'timeZone' => 'Europe/Paris',
],
],
])->map([
'identification' => 'name',
'towns' => 'cities',
'towns.*.label' => 'name',
]);
// After modification this is what the source will look like:
// [
// 'name' => 'France',
// 'cities' => [
// [
// 'name' => 'Paris',
// 'timeZone' => 'Europe/Paris',
// ],
// [
// 'name' => 'Lyon',
// 'timeZone' => 'Europe/Paris',
// ],
// ],
// ];
(new \CuyZ\Valinor\MapperBuilder())->mapper()->map(Country::class, $source);
自定义源¶
源只是一个可迭代的,因此很容易创建自定义源。它甚至可以与提供的构建器结合使用。
final readonly class AcmeSource implements IteratorAggregate
{
private iterable $source;
public function __construct(iterable $source)
{
$this->source = $this->doSomething($source);
}
private function doSomething(iterable $source): iterable
{
// Do something with $source
return $source;
}
public function getIterator()
{
yield from $this->source;
}
}
$source = \CuyZ\Valinor\Mapper\Source\Source::iterable(
new AcmeSource([
'valueA' => 'foo',
'valueB' => 'bar',
])
)->camelCaseKeys();
(new \CuyZ\Valinor\MapperBuilder())
->mapper()
->map(SomeClass::class, $source);