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 90d7adc..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(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(int $postID, string $metaKey, string $prefix): mixed ]; foreach ($possibleKeys as $key) { - if ($value = \get_field($key, $postID)) { + if ($value = \get_field($key, $objectID)) { return $value; } } 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..a53591c --- /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->objectID(), $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 objectID(): 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; + } +}