woohoolabs/yin
PSR-7–compatible PHP framework for building JSON:API servers. Provides documents, resources, hydrators, request/response validation, pagination, relationship handling, content negotiation, middleware support, and custom serialization/deserialization.
Install via Composer:
composer require woohoolabs/yin
Publish the config (optional):
php artisan vendor:publish --provider="Woohoolabs\Yin\YinServiceProvider"
First Use Case: Validate and hydrate a domain object from incoming request data:
use Woohoolabs\Yin\Hydrator;
use App\Domain\Objects\User;
$hydrator = app(Hydrator::class);
$user = $hydrator->hydrate(User::class, $request->all(), [
'validate' => true, // New in 4.3.0: Enables validation of hydrated object
]);
Key files to review:
config/yin.php (for configuration options like omitDataWhenNotIncluded)app/Domain/Objects/ (your domain objects with validation rules)Hydration with Validation (New in 4.3.0):
$hydrator->hydrate(User::class, $data, [
'validate' => true, // Triggers validation via domain object rules
'omitDataWhenNotIncluded' => true, // Preserves existing behavior
]);
use Illuminate\Contracts\Validation\Validatable).API Response Handling:
$responseData = $hydrator->hydrate(User::class, $data, [
'omitDataWhenNotIncluded' => true, // Fixes #103: Ensures omitted fields don't appear in response
])->toArray();
Integration with Laravel Controllers:
public function store(Request $request, Hydrator $hydrator) {
$user = $hydrator->hydrate(User::class, $request->validated(), [
'validate' => true, // Re-validates even if request validation passed
]);
return response()->json($user);
}
Domain Object Structure:
class User implements Validatable {
use ValidatesWhenHydrated; // Optional trait for validation rules
public function rules() {
return [
'email' => 'required|email',
'password' => 'nullable|min:8',
];
}
}
Partial Updates:
$hydrator->hydrate(User::class, ['email' => 'new@example.com'], [
'partial' => true, // Only updates specified fields
]);
Validation Conflicts:
validate: true in hydrator, the hydrator’s validation will run after request validation. Use validate: false in hydrator if you want to skip it.omitDataWhenNotIncluded Quirk (Fixed in 4.3.0):
null values in the response for omitted fields. Now it completely omits them (e.g., ['email' => null] becomes []).['email' => null] to ensure expected behavior.Performance:
$hydrator = app(Hydrator::class); // Reuse this instance
Validation Errors:
try {
$user = $hydrator->hydrate(User::class, $data, ['validate' => true]);
} catch (ValidationException $e) {
return response()->json($e->errors(), 422);
}
Inspect Hydrated Data:
$hydrator->hydrate(User::class, $data, [
'debug' => true, // Logs raw data and validation rules (use in development only)
]);
Custom Validation:
Override the validate() method in your domain object:
class User {
public function validate(array $data) {
// Custom logic
return validator($data, $this->customRules())->validate();
}
}
Event Hooks:
Bind to yin.hydrated event for post-processing:
Yin::hydrated(function ($object, $data) {
// Example: Auto-generate UUIDs
if ($object instanceof User) {
$object->uuid = Str::uuid();
}
});
Response Transformation:
Use the toArray() method with custom logic:
$hydrator->hydrate(User::class, $data)->toArray(function ($object) {
return [
'id' => $object->id,
'email' => $object->email,
// Custom fields
];
});
How can I help you explore Laravel packages today?