From 03ce64a6f7510039b58e47583eabfa4b5a43b85b Mon Sep 17 00:00:00 2001 From: Maarten Bruna <14947039+ictbeheer@users.noreply.github.com> Date: Thu, 28 Aug 2025 14:59:34 +0200 Subject: [PATCH 1/2] (feat): termdata --- src/Attributes/Meta.php | 2 +- src/Attributes/Terms.php | 4 +-- src/PostData.php | 43 +++------------------------- src/TermData.php | 19 +++++++++---- src/Traits/HasMeta.php | 60 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 47 deletions(-) create mode 100644 src/Traits/HasMeta.php diff --git a/src/Attributes/Meta.php b/src/Attributes/Meta.php index 90d7adc..4a8b905 100644 --- a/src/Attributes/Meta.php +++ b/src/Attributes/Meta.php @@ -13,7 +13,7 @@ public function __construct(private ?string $metaKey = null) { } - public function getValue(int $postID, string $metaKey, string $prefix): mixed + public function getValue(string|int $postID, string $metaKey, string $prefix): mixed { if (isset($this->metaKey)) { if ($value = \get_field($this->metaKey, $postID)) { diff --git a/src/Attributes/Terms.php b/src/Attributes/Terms.php index db635fd..caba7c0 100644 --- a/src/Attributes/Terms.php +++ b/src/Attributes/Terms.php @@ -11,7 +11,7 @@ #[\Attribute(\Attribute::TARGET_PROPERTY)] class Terms { - public function __construct(private ?string $taxonomy = null) + public function __construct(private ?string $taxonomy = null, private string $dataClass = TermData::class) { } @@ -41,7 +41,7 @@ public function getValue(int $postID, string $taxonomy, string $prefix): mixed return null; } - return TermData::collect($terms, Collection::class); + return $this->dataClass::collect($terms, Collection::class); } } diff --git a/src/PostData.php b/src/PostData.php index a3fadd4..0726552 100644 --- a/src/PostData.php +++ b/src/PostData.php @@ -4,12 +4,10 @@ namespace Yard\Data; -use BackedEnum; use Carbon\CarbonImmutable; use Corcel\Model\Post; use Illuminate\Support\Collection; use ReflectionClass; -use ReflectionNamedType; use RuntimeException; use Spatie\LaravelData\Attributes\MapInputName; use Spatie\LaravelData\Attributes\WithCastable; @@ -20,18 +18,19 @@ use Spatie\LaravelData\Normalizers\ModelNormalizer; use Spatie\LaravelData\Normalizers\Normalizer; use Spatie\LaravelData\Normalizers\ObjectNormalizer; -use Yard\Data\Attributes\Meta; -use Yard\Data\Attributes\MetaPrefix; use Yard\Data\Attributes\TaxonomyPrefix; use Yard\Data\Attributes\Terms; use Yard\Data\Contracts\PostDataInterface; use Yard\Data\Enums\PostStatus; use Yard\Data\Mappers\PostPrefixMapper; use Yard\Data\Normalizers\WPPostNormalizer; +use Yard\Data\Traits\HasMeta; #[MapInputName(PostPrefixMapper::class)] class PostData extends Data implements PostDataInterface { + use HasMeta; + public function __construct( #[MapInputName('ID')] public ?int $id, @@ -49,7 +48,7 @@ public function __construct( public ?ImageData $thumbnail, ) { if (null !== $id) { - $this->loadMeta($id); + $this->loadMeta(); $this->loadTerms($id); } } @@ -116,40 +115,6 @@ private static function dataClass(string $postType): string return $classFQN; } - private function metaPrefix(): string - { - $reflectionClass = new ReflectionClass($this); - $metaPrefixAttribute = $reflectionClass->getAttributes(MetaPrefix::class)[0] ?? null; - - return $metaPrefixAttribute?->newInstance()->prefix ?? ''; - } - - private function loadMeta(int $id): void - { - $reflectionClass = new ReflectionClass($this); - $properties = $reflectionClass->getProperties(); - foreach ($properties as $property) { - $propertyType = $property->getType(); - $propertyTypeName = null; - if ($propertyType instanceof ReflectionNamedType) { - $propertyTypeName = $propertyType->getName(); - } - $metaAttributes = $property->getAttributes(Meta::class); - foreach ($metaAttributes as $metaAttribute) { - $meta = $metaAttribute->newInstance(); - $metaValue = $meta->getValue($id, $property->name, $this->metaPrefix()); - if (null !== $metaValue && null !== $propertyTypeName) { - if (is_a($propertyTypeName, Data::class, true)) { - $metaValue = $propertyTypeName::from($metaValue); - } elseif (is_a($propertyTypeName, BackedEnum::class, true) && (is_int($metaValue) || is_string($metaValue))) { - $metaValue = $propertyTypeName::from($metaValue); - } - $property->setValue($this, $metaValue); - } - } - } - } - private function taxonomyPrefix(): string { $reflectionClass = new ReflectionClass($this); diff --git a/src/TermData.php b/src/TermData.php index 3e4299d..06159eb 100644 --- a/src/TermData.php +++ b/src/TermData.php @@ -6,17 +6,26 @@ use Spatie\LaravelData\Attributes\MapInputName; use Spatie\LaravelData\Data; +use Yard\Data\Traits\HasMeta; class TermData extends Data { - #[MapInputName('term_id')] - public int $id; - public string $name; - public string $slug; + use HasMeta; + + public function __construct( + #[MapInputName('term_id')] + public int $id, + public string $name, + public string $slug, + public string $taxonomy, + public ?string $description = null, + ) { + $this->loadMeta(); + } public static function fromTerm(\WP_Term $term): TermData { - return self::from( + return static::from( $term->to_array() ); } diff --git a/src/Traits/HasMeta.php b/src/Traits/HasMeta.php new file mode 100644 index 0000000..a9023c0 --- /dev/null +++ b/src/Traits/HasMeta.php @@ -0,0 +1,60 @@ +getProperties(); + foreach ($properties as $property) { + $propertyType = $property->getType(); + $propertyTypeName = null; + if ($propertyType instanceof \ReflectionNamedType) { + $propertyTypeName = $propertyType->getName(); + } + $metaAttributes = $property->getAttributes(Meta::class); + foreach ($metaAttributes as $metaAttribute) { + $meta = $metaAttribute->newInstance(); + $metaValue = $meta->getValue($this->postID(), $property->name, $this->metaPrefix()); + if (null !== $metaValue && null !== $propertyTypeName) { + if (is_a($propertyTypeName, Data::class, true)) { + $metaValue = $propertyTypeName::from($metaValue); + } elseif (is_a($propertyTypeName, \BackedEnum::class, true) && (is_int($metaValue) || is_string($metaValue))) { + $metaValue = $propertyTypeName::from($metaValue); + } + $property->setValue($this, $metaValue); + } + } + } + } + + private function metaPrefix(): string + { + $reflectionClass = new \ReflectionClass($this); + $metaPrefixAttribute = $reflectionClass->getAttributes(MetaPrefix::class)[0] ?? null; + + return $metaPrefixAttribute?->newInstance()->prefix ?? ''; + } + + private function postID(): string|int + { + if (is_a($this, PostData::class)) { + return $this->id ?? 0; + } + if (is_a($this, TermData::class)) { + return $this->taxonomy . '_' . $this->id; + } + + return 0; + } +} From 762360feaeeed73763959118f2d7307782177d1b Mon Sep 17 00:00:00 2001 From: Maarten Bruna <14947039+ictbeheer@users.noreply.github.com> Date: Mon, 1 Sep 2025 11:39:45 +0200 Subject: [PATCH 2/2] (fix): review comments --- README.md | 39 +++++++++++++++++++++++++++++++++++++++ src/Attributes/Meta.php | 6 +++--- src/Traits/HasMeta.php | 4 ++-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 737f158..2f6189c 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,45 @@ $postData->locations->firstWhere('slug', 'utrecht')->name; // Utrecht $vacancyData->locations->implode('name', ', '), // Almere, Amsterdam, Utrecht ``` +#### Extending TermData + +You can add extra meta fields to taxonomies by extending the default TermData object + +```php +namespace App\Data; + +use Yard\Data\TermData; + +class TypeTermData extends TermData { + + #[Meta()] + public string $icon; +} + +``` + +In your PostData object you have to specify the data class used for a specific taxonomy: + +```php +namespace App\Data; + +use Illuminate\Support\Collection; +use Yard\Data\Attributes\TaxonomyPrefix; +use Yard\Data\Attributes\Terms; +use Yard\Data\PostData; + +class VacancyData extends PostData +{ + #[Terms(dataClass: TypeTermData::class)] + /** @var Collection */ + public Collection $type; +} +``` + +```php +$vacancyTypeIcon = $vacancyData->type->first()?->icon; +``` + ### UserData Create UserData from current user: diff --git a/src/Attributes/Meta.php b/src/Attributes/Meta.php index 4a8b905..08d0026 100644 --- a/src/Attributes/Meta.php +++ b/src/Attributes/Meta.php @@ -13,10 +13,10 @@ public function __construct(private ?string $metaKey = null) { } - public function getValue(string|int $postID, string $metaKey, string $prefix): mixed + public function getValue(string|int $objectID, string $metaKey, string $prefix): mixed { if (isset($this->metaKey)) { - if ($value = \get_field($this->metaKey, $postID)) { + if ($value = \get_field($this->metaKey, $objectID)) { return $value; } else { return null; @@ -31,7 +31,7 @@ public function getValue(string|int $postID, string $metaKey, string $prefix): m ]; foreach ($possibleKeys as $key) { - if ($value = \get_field($key, $postID)) { + if ($value = \get_field($key, $objectID)) { return $value; } } diff --git a/src/Traits/HasMeta.php b/src/Traits/HasMeta.php index a9023c0..a53591c 100644 --- a/src/Traits/HasMeta.php +++ b/src/Traits/HasMeta.php @@ -25,7 +25,7 @@ private function loadMeta(): void $metaAttributes = $property->getAttributes(Meta::class); foreach ($metaAttributes as $metaAttribute) { $meta = $metaAttribute->newInstance(); - $metaValue = $meta->getValue($this->postID(), $property->name, $this->metaPrefix()); + $metaValue = $meta->getValue($this->objectID(), $property->name, $this->metaPrefix()); if (null !== $metaValue && null !== $propertyTypeName) { if (is_a($propertyTypeName, Data::class, true)) { $metaValue = $propertyTypeName::from($metaValue); @@ -46,7 +46,7 @@ private function metaPrefix(): string return $metaPrefixAttribute?->newInstance()->prefix ?? ''; } - private function postID(): string|int + private function objectID(): string|int { if (is_a($this, PostData::class)) { return $this->id ?? 0;