Installation:
composer require ashleydawson/class-meta
Add to composer.json autoload if not auto-discovered:
"autoload": {
"files": ["vendor/ashleydawson/class-meta/Annotation/AnnotationRegistry.php"]
}
Run composer dump-autoload.
First Use Case: Annotate a class/constant with metadata (see README example) and retrieve it via the manager:
$manager = new \AshleyDawson\ClassMeta\ClassMetaManager();
$meta = $manager->getClassMeta(\Acme\Enum\InvoiceStatus::class);
Key Files:
Annotation/Meta.php (annotation definition)ClassMetaManager.php (core retrieval logic)AnnotationRegistry.php (annotation autoloader)Enum/Constant Metadata:
// Define
class UserRole {
/** @Meta(data={"permission": ["create", "read"]}) */
const ADMIN = 'admin';
}
// Use
$roleMeta = $manager->getConstantMeta(UserRole::ADMIN);
$permissions = $roleMeta->getData()['permission'];
Dynamic Lookups:
// Cache metadata in a service provider
public function boot() {
$this->app->singleton('role.metadata', function() {
return collect([
UserRole::ADMIN => $manager->getConstantMeta(UserRole::ADMIN),
// ...
]);
});
}
Validation Integration:
// Validate against metadata
$validPermissions = $manager->getConstantMeta(UserRole::ADMIN)->getData()['permission'];
if (!in_array('create', $validPermissions)) {
abort(403);
}
API Responses:
// Serialize metadata for API
return response()->json([
'statuses' => array_map(function($constant) {
return [
'value' => $constant,
'label' => $manager->getConstantMeta($constant)->getData()['name']
];
}, InvoiceStatus::getConstants())
]);
Laravel Service Provider: Bind the manager to the container for dependency injection:
$this->app->singleton(ClassMetaManager::class);
Annotation Parsing:
Use AnnotationRegistry::registerLoader() to customize annotation parsing (e.g., for PHPDoc parsing libraries like phpDocumentor).
Caching: Cache metadata in a service provider or use Laravel’s cache:
$meta = Cache::remember("meta.{$class}", now()->addHours(1), function() use ($manager, $class) {
return $manager->getClassMeta($class);
});
Annotation Parsing:
@ or incorrect spacing).AnnotationRegistry::registerLoader() with a custom loader or validate annotations with a regex:
if (!preg_match('/@Meta\(data={"([^"]*)"}\)/', $docComment)) {
throw new \InvalidArgumentException("Invalid Meta annotation");
}
Performance:
// In a service provider
$manager->getClassMeta(\Acme\Enum\InvoiceStatus::class); // Pre-load
Namespace Sensitivity:
\Acme\Enum\InvoiceStatus instead of InvoiceStatus).Data Serialization:
data attribute is stored as a string (e.g., {"key":"value"}), requiring manual JSON decoding:
$data = json_decode($meta->getData(), true);
Meta annotation to support typed data (e.g., arrays directly).Verify Annotations:
Use ClassMetaManager::getClassMeta() with a non-existent class to check for parsing errors:
try {
$manager->getClassMeta(\NonExistentClass::class);
} catch (\Exception $e) {
// Debug annotation parsing
}
Check Autoloading:
Ensure AnnotationRegistry.php is autoloaded. Run:
composer dump-autoload --optimize
Custom Metadata Storage:
Extend ClassMetaManager to store metadata in a database or Redis:
class DatabaseMetaManager extends ClassMetaManager {
public function getClassMeta($class) {
$cached = Cache::get("meta.{$class}");
if (!$cached) {
$cached = parent::getClassMeta($class);
Cache::put("meta.{$class}", $cached);
}
return $cached;
}
}
Annotation Validation:
Add validation rules to the Meta annotation:
use AshleyDawson\ClassMeta\Annotation\Meta;
/**
* @Meta(data={"required": ["name"], "type": "object"})
*/
class ValidatedEnum { ... }
Laravel Blade Directives: Create a Blade directive to output metadata in views:
Blade::directive('meta', function($expression) {
$class = $expression;
return "<?php echo \$manager->getClassMeta({$class})->getData()['name'] ?? ''; ?>";
});
Usage:
@meta(\Acme\Enum\InvoiceStatus::class)
Testing:
Mock the ClassMetaManager in tests:
$manager = Mockery::mock(ClassMetaManager::class);
$manager->shouldReceive('getClassMeta')
->with(\Acme\Enum\InvoiceStatus::class)
->andReturn((object) ['data' => json_encode(['name' => 'Test'])]);
How can I help you explore Laravel packages today?