tourze/face-detect-bundle
A Symfony bundle that adds face detection capabilities to your application through a configurable service layer. Integrates detection providers with dependency injection and Twig helpers, keeping face-detection logic decoupled from your business code.
tourze/face-detect-bundle 0.0.1 is the initial tagged release — there is no prior assessment to diff against, so treat everything below as a first-look. The changelog for 0.0.1 contains only a compare link (no feature list, no BC notes), which is itself a signal: this is an early, likely alpha-quality package.
Where to look first, in order:
composer.json — PHP version constraint, tourze/* sibling dependencies, and whether it pulls in a native extension (GD/Imagick) or an HTTP-based detection backend. This determines your deployment story more than anything else.src/DependencyInjection/*Extension.php + Resources/config/services.yaml (or config/services.php) — the bundle's public surface is whatever services it registers. That list is the API in a Symfony bundle.detect()/analyze() signature, return type (array of boxes? an object? a result DTO?), and exception behaviour.docs/ if present — often absent at 0.0.x.Minimal install:
composer require tourze/face-detect-bundle:0.0.1
Pin the exact version (0.0.1, not ^0.0.1) — at this maturity, 0.0.2 can rename anything.
Reality check for a Laravel app: this is a Symfony bundle, not a Laravel package. It will not be auto-discovered, and FaceDetectBundle::class registration in config/bundles.php has no Laravel equivalent. Your first real use case should be narrow: a single-image upload endpoint that returns a face count and bounding boxes, exercised through a thin adapter you own. If you need this in production imminently, evaluate whether the underlying detection engine (whatever the bundle wraps) is usable directly — you may end up depending on that instead and dropping the bundle layer.
Adapter, not direct coupling. The bundle's services are wired through Symfony's container. In Laravel, bind the detector behind your own contract so the rest of the app never imports a Tourze\ class:
// app/Contracts/FaceDetector.php
interface FaceDetector { public function detect(string $absolutePath): array; }
// app/Services/TourzeFaceDetector.php
final class TourzeFaceDetector implements FaceDetector
{
public function __construct(private object $inner) {}
public function detect(string $absolutePath): array
{
return $this->inner->detect($absolutePath) ?? [];
}
}
Register it in a FaceDetectionServiceProvider, resolving $inner manually (construct it with its own dependencies, or run the bundle's container in a scoped Symfony ContainerBuilder). This adapter is your escape hatch when 0.0.2 breaks.
Controller → Job → Result row. Keep the request cycle thin:
FormRequest validates image (mimes:jpg,jpeg,png, max:8192).DetectFaces job, returns 202 with a job/record id.Storage::disk('images')->path($key), runs detection, persists normalized boxes into a face_detections table (boxes as JSON: [{x,y,w,h,score}], plus count, engine_version, duration_ms).Cache by content hash. Detection is CPU-bound; sha1_file() on the resized derivative makes a good cache key. Store the box array, not the image. This single pattern removes most of the cost in read-heavy flows (avatars, repeated uploads, retries).
Deterministic tests. Never call the real detector in feature tests. Bind a fake FaceDetector returning a fixed box array, and keep 2–3 small fixture images (one face, many faces, zero faces) for an integration test that runs only in CI with the extension available.
Decorator for observability. Because you own the contract, wrap the adapter with a logging/timing decorator (Log::info('face_detect', ['ms' => ..., 'count' => ...])) rather than editing vendor code — that's also your extension point if the bundle later adds events.
Config surface. Any bundle configuration (thresholds, model path, backend selection) lives in Symfony bundle config and will not be read by Laravel's config/*.php. Mirror the values you care about into your own config file and pass them explicitly to the adapter; do not rely on the bundle's defaults being loaded.
config/bundles.php. Any tutorial or README snippet you find will assume Symfony. Budget for the adapter work up front.0.0.1 means no compatibility promise. No changelog content, no upgrade guide. Pin exactly, and read src/ before upgrading — assume breaking changes in every patch.php artisan config:cache and optimize do not know about the bundle's configuration; anything you smuggle in via a raw Symfony container will be rebuilt per request or silently stale. Keep configuration in Laravel config and inject it.extension_loaded('gd') in a health/readiness endpoint, verify the model path resolves from the queue worker's working directory (relative paths break under artisan queue:work), and confirm the file ships with the package rather than being downloaded at runtime.exif_read_data orientation, convert to RGB, strip alpha. Do this in your own code — don't assume the bundle handles it.422, a stored row with count: 0, or a soft pass — and make sure the adapter doesn't coerce null into a false negative.$timeout, run on a dedicated queue, and cap memory_limit so a bad image fails one job rather than the worker.0.0.1 gives you nothing to read.final, and override bundle parameters via a manually built ContainerBuilder only as a last resort. Avoid patching vendor files — you'll need that diff to survive the next tag.tourze/* publishes many small, fast-moving packages. Run composer audit and check the transitive tree; a 0.0.1 bundle can pull a surprisingly deep dependency set for what is conceptually a few calls into an image API.How can I help you explore Laravel packages today?