laragear/meta
Helper utilities for Laravel package developers. Simplifies service provider bootstrapping with publishable migrations, scheduled tasks, middleware declarations (groups, aliases, priority), plus optional meta-testing helpers and class discovery tools.
Installation:
composer require laragear/meta
Add to your package's composer.json under require (not require-dev).
First Use Case:
In your package's ServiceProvider (e.g., MyPackageServiceProvider.php), leverage the fluent helpers in the boot() method:
use Laragear\Meta\Meta;
public function boot()
{
$this->withPublishableMigrations(__DIR__.'/../migrations')
->withSchedule(fn($schedule) => $schedule->command('my-package:cleanup')->daily());
}
Key Entry Points:
withPublishableMigrations()withSchedule()withMiddleware()Attr::of()ExtendsBuilder traitPattern: Centralize migration publishing and registration.
// Register and publish migrations from a subdirectory
$this->withPublishableMigrations(__DIR__.'/../database/migrations');
// Later, in your tests (if using meta-testing):
$this->assertPublishMigrations();
Workflow:
withPublishableMigrations() to auto-publish and register migrations from a specified path.laragear/discover to dynamically discover migrations based on naming conventions.Pattern: Declarative middleware setup with priority control.
// Register middleware globally with an alias and priority
$this->withMiddleware(MyMiddleware::class)
->as('my.middleware')
->globally()
->first(); // Ensures it runs first in the stack
Integration Tips:
inGroup('web') to attach middleware to specific groups.->shared()->last()).meta-testing helpers:
$this->assertMiddlewareRegistered(MyMiddleware::class);
Pattern: Extend query builders in global scopes.
class ActiveScope implements Scope
{
use ExtendsBuilder;
public function apply(Builder $builder, Model $model)
{
$builder->where('active', true);
}
// Extend builder with custom methods
protected static function extendWhereVerified($builder)
{
return $builder->where('verified_at', '>', now());
}
}
// Usage in queries:
Model::query()->verified(); // Calls extendWhereVerified()
Workflow:
extend (e.g., extendWhereX()).$builder->getModel() if needed.Pattern: Inspect class/object attributes dynamically.
#[MyAttribute(key: 'value')]
class User {}
$value = Attr::of(User::class)->get(MyAttribute::class, 'key'); // 'value'
Use Cases:
laragear/discover to scan classes for attributes:
$classes = Discover::classes()
->in(__DIR__.'/../src')
->withAttribute(MyAttribute::class)
->get();
Pattern: Modify .env files in commands.
use Laragear\Meta\Console\Commands\WithEnvironmentFile;
class SetApiKey extends Command
{
use WithEnvironmentFile;
public function handle()
{
$this->putEnvKey('API_KEY', $this->argument('key'));
// Automatically writes to .env
}
}
Workflow:
.env file handling in tests or CLI tools.Pattern: Assert package behavior in tests.
// In your package's tests
$this->assertPublishMigrations();
$this->assertMiddlewareRegistered(MyMiddleware::class);
$this->assertValidationPasses(['email' => '[email protected]'], 'email');
Integration:
composer require --dev laragear/meta-testing.Middleware Priority:
first()/last() must be called after globally() or inGroup().$this->withMiddleware(MyMiddleware::class)
->first() // Won't work; priority ignored
->globally();
globally() before first()/last().Attribute Extraction:
Attr::of() requires reflection on the target class/object.->get() with a default value:
Attr::of($obj)->get(MyAttribute::class, 'key', null);
Octane Compatibility:
ExtendsBuilder with static properties (initialized once per scope).Migration Publishing:
withPublishableMigrations() overwrites existing migrations.prefix_migration_table) to avoid conflicts.Middleware Not Registering:
boot() method runs (check ServiceProvider registration).php artisan route:list to confirm middleware is attached.Builder Extensions Not Working:
extend.Attribute Extraction Failing:
Attr::of()->has(MyAttribute::class) to debug presence.Custom Middleware Declaration:
Extend MiddlewareDeclaration to add package-specific logic:
$declaration = $this->withMiddleware(MyMiddleware::class);
$declaration->extend(fn($declaration) => $declaration->withProperty('custom_key', 'value'));
Dynamic Attribute Filters:
Combine Attr with Discover to build metadata systems:
$classes = Discover::classes()
->withAttribute(Deprecated::class)
->get();
Environment File Hooks:
Extend WithEnvironmentFile to validate/modify keys:
protected function modifyEnvKey(string $key, $value): void
{
if ($key === 'API_KEY') {
$this->validateApiKey($value);
}
}
Publishable Migrations:
ServiceProvider is registered in config/app.php under providers.Testing Helpers:
meta-testing assertions require the package to be published first.Artisan::call() to publish before assertions:
$this->artisan('vendor:publish', ['--provider' => 'MyPackageServiceProvider']);
$this->assertPublishMigrations();
PHP Version:
Attr::of()->get(..., null) to avoid warnings.How can I help you explore Laravel packages today?