digitalstate/platform-data-bundle
Installation:
composer require digitalstate/platform-data-bundle
Add to config/app.php under providers:
DigitalState\PlatformDataBundle\PlatformDataBundle::class,
First Use Case:
Resolve string representations (e.g., "user:1" or "role:admin") into actual objects (e.g., User model or Role enum).
Example in a controller:
use DigitalState\PlatformDataBundle\Resolver\DataResolverInterface;
public function show(DataResolverInterface $resolver, string $dataString)
{
$user = $resolver->resolve($dataString); // Returns User model or null
return view('user.show', compact('user'));
}
Configuration:
Check config/platform-data.php for default resolvers and customization points.
Override defaults via service container binding:
$this->app->bind(DataResolverInterface::class, CustomResolver::class);
String Resolution:
Use the DataResolverInterface to convert strings like "user:1" into objects.
Example with dependency injection:
public function __construct(private DataResolverInterface $resolver) {}
public function handle(string $dataString) {
$entity = $this->resolver->resolve($dataString);
// Use $entity...
}
Custom Resolvers:
Extend AbstractResolver or implement DataResolverInterface for domain-specific logic.
Example resolver for Role:
class RoleResolver extends AbstractResolver
{
protected function getType(): string { return 'role'; }
protected function resolveValue(string $value): ?Role
{
return Role::from($value); // Assuming Role is an enum
}
}
Register in config/platform-data.php:
'resolvers' => [
'role' => \App\Resolvers\RoleResolver::class,
],
Chaining Resolvers:
Combine multiple resolvers for complex strings (e.g., "user:1->posts:5").
Use CompositeResolver:
$compositeResolver = new CompositeResolver([
new UserResolver(),
new PostResolver(),
]);
Validation: Validate resolved data before use:
$resolved = $this->resolver->resolve($dataString);
if (!$resolved) {
throw new \InvalidArgumentException("Invalid data string: {$dataString}");
}
ModelResolver for automatic model resolution:
$resolver = new ModelResolver(User::class);
$user = $resolver->resolve('user:1');
public function update(Request $request, DataResolverInterface $resolver) {
$user = $resolver->resolve($request->input('user_data'));
// ...
}
public function handle() {
$data = $this->resolver->resolve($this->dataString);
// Process $data...
}
Resolver Order:
Resolvers are matched by type (e.g., "user:1" → user type).
Fix: Ensure custom resolvers are registered before generic ones in config/platform-data.php.
Circular Dependencies:
Resolving "user:1->posts:5" where Post depends on User may cause infinite loops.
Fix: Use CompositeResolver with depth limits or lazy resolution.
Null Returns:
Resolvers return null for invalid data. Always validate:
$data = $resolver->resolve($string) ?: throw new \RuntimeException("Resolution failed");
Case Sensitivity:
Type matching is case-sensitive (e.g., "User:1" ≠ "user:1").
Fix: Normalize types in resolvers:
protected function getType(): string { return strtolower(parent::getType()); }
Enable Logging:
Add to config/platform-data.php:
'debug' => env('APP_DEBUG', false),
Logs resolver calls to storage/logs/laravel.log.
Resolver Dump: List registered resolvers:
$resolver = app(DataResolverInterface::class);
dump($resolver->getRegisteredResolvers());
Custom Formats:
Extend AbstractResolver to support non-colon-separated formats (e.g., "user/1").
Override parseString():
protected function parseString(string $dataString): array {
return explode('/', $dataString);
}
Dynamic Resolvers: Register resolvers dynamically via events:
event(new RegisterResolverEvent(new CustomResolver()));
Caching: Cache resolved objects to avoid repeated DB queries:
$resolver = new CachedResolver(
new UserResolver(),
new \Illuminate\Cache\Repository(app('cache'))
);
Testing:
Mock DataResolverInterface in tests:
$mockResolver = Mockery::mock(DataResolverInterface::class);
$mockResolver->shouldReceive('resolve')
->with('user:1')
->andReturn(new User());
How can I help you explore Laravel packages today?