Перейти к основному содержимому

Атрибуты

Speca использует PHP-атрибуты для управления правилами инстанцирования и сериализации полей объектов. Рассмотрим существующие атрибуты с позиции их целевого назначения.

Вспомогательная декларация

Set

Декларирует, что свойство является массивом элементов типа.

Аргументы

  • of указывает на целевой тип элемента массива. Если этот тип - Data, следующие аргументы не требуются.
  • parser является аналогом единичного атрибута ParseBy для элемента массива.
  • serializer является аналогом единичного атрибута SerializeBy для элемента массива.

Пример

Рассмотрим декларирование набора элементов для класса, не являющегося Data:

class CompositionTag {

public function __construct(
public string $id,
public string $name
)
{}
}
class Composition extends Data {
public function __construct(
#[Set(of: CompositionTag::class,
parser: CompositionTagParser::class,
serializer: CompositionTagSerializer::class)]
public array $tags
)
{}
}

class CompositionTagParser implements Transformer {
public function transform(mixed $value, Property $property): mixed {
return new CompositionTag(
id: $value['id'],
name: $value['name']
);
}
}
class CompositionTagSerializer implements Transformer {
public function transform(mixed $value, Property $property): mixed {
//Просто убедимся..
assert($value instanceof CompositionTag);
//И вернем массив
return [
'id' => $value->id,
'name' => $value->name
];
}
}

Много бойлерплейта, не так ли? Давайте упростим!

class CompositionTag extends Data {

public function __construct(
public string $id,
public string $name
)
{}
}
class Composition extends Data {
public function __construct(
#[Set(of: CompositionTag::class)]
public array $tags
)
{}
}

Это все - достаточно было использовать Data в классе CompositionTag. Благодаря этому массив будет собираться автоматически по тем правилам, которые опишет класс CompositionTag.

Парсинг

ParseBy

Назначает парсер свойств.

Пример

use Looqey\Speca\Data;
use Looqey\Speca\Attributes\ParseBy;

class User extends Data {

public function __construct(
#[ParseBy(NameArrayToStringParser::class)]
public string $name;
) 8
{}
}

use Looqey\Speca\Contracts\Transformer;
use Looqey\Speca\Core\Property;

class NameArrayToStringParser implements Transformer {
public function transform(mixed $value, Property $property): mixed {
return $value['first_name'] . ' ' . $value['surname'];
}
}
$data = [
'name' => [
'first_name' => 'John',
'surname' => 'Doe'
]
];
$it = User::from($data);
// $it->name = 'John Doe'

Частные случаи

Использование с конструктором без продвижения свойства

Пользовательский парсер будет применен к свойству ДО передачи его конструктору:

class User extends Data {
#[ParseBy(NameArrayToStringParser::class)]
public string $name;

public function __construct(string $name) {
// В $name мы получим "John Doe"!
$this->name = 'rough '.$name;
}
}

ParseFrom

Устанавливает для поля возможные источники для парсинга. Например:

use Looqey\Speca\Data;
use Looqey\Attributes\ParseFrom;

class Painting extends Data {

public function __construct(
#[ParseFrom('technique_description', 'techniqueDescription', 'technique')]
public string $techniqueDescription;
)
{}
}

При инстанцировании объекта методом from Speca возьмет первый существующий во входном наборе данных параметр (fallback-схема). При использовании этого атрибута на поле его изначальное имя не учитывается (не берется для того чтобы искать значение в источнике данных)

$data = [
//Это поле будет использовано для заполнения techniqueDescription по умолчанию
'technique_description' => 'Sfumato creates soft transitions, layered glazes add depth, light shapes form.',
//Если бы предыдущего поля не было - было бы использовано это поле
'techniqueDescription' => 'Fine hatching adds texture, layered washes create depth, contrast defines form.',
//..аналогично предыдущему полю
'technique' => 'Glazes build depth, soft blending smooths edges, light and shadow shape form.',
];

$it = Painting::from($data);

Взаимодействие

Возможно использовать атрибуты совместно. Происходить это будет по схеме:

  1. Получение действительного значения поля (ParseFrom)
  2. Парсинг значения поля (ParseTo)

Сериализация

SerializeBy

Назначает сериализатор свойств

use Looqey\Speca\Data;

class User extends Data {

public function __construct(
#[SerializeBy(NameSerializer::class)]
public string $name
)
{}
}

use Looqey\Speca\Contracts\Transformer;
use Looqey\Speca\Core\Property;
class NameSerializer implements Transformer {
public function transform(mixed $value, Property $property): mixed {
$parts = explode(' ', $value);
return ['first' => $parts[0], 'last' => $parts[1] ?? ''];
}
}


$data = [
'name' => 'John Doe'
];

$user = User::from($data);
$output = $user->toArray();
// $output['name'] будет массивом с ключами "first" и "last"