yepwoo/laragine
Laragine is a Laravel wrapper for the Imagine image manipulation library, offering a fluent API to resize, crop, rotate, filter, and save images with configurable drivers and filesystem integration for common image-processing workflows.
Laragine is a small, opinionated modularization layer for Laravel built around the idea of "engines" — self-contained folders that bundle a domain's controllers, models, migrations, routes, views, and config together instead of scattering them across the default app/ tree.
Minimal steps:
Install and pin.
composer require yepwoo/laragine
Add a caret/locked version in composer.json and commit composer.lock. With 42 stars and a last release in April 2024, treat this as a "read the source" dependency, not a "trust the docs on Stack Overflow" one.
Publish the config (if the package ships one).
php artisan vendor:publish --provider="Yepwoo\Laragine\...ServiceProvider"
Check the repo README and src/ for the exact provider namespace — it is not standardized enough across small Laravel packages to guess reliably.
Generate your first engine via the package's artisan command (likely laragine:engine or engine:make — confirm the signature with php artisan list | grep -i engineer). This scaffolds a Blog engine with its own service provider, routes, and directory layout.
Where to look first:
README.md in the repo (primary source of truth for commands and directory conventions).config/laragine.php after publishing — this tells you where engines live and how routes/providers are discovered.ServiceProvider — that is the seam where Laragine wires the engine into Laravel.vendor/yepwoo/laragine/src/ — read the commands and the service provider. This package is small enough to read end-to-end in an afternoon and you will need to.First real use case: create one engine for a bounded domain (e.g. Billing), move a handful of controllers/models/migrations/routes into it, register its provider, and verify with:
php artisan route:list
php artisan migrate --pretend
php artisan optimize:clear
Resist migrating the whole app in one pass.
Domain-per-engine, not layer-per-engine. The package is designed so an engine owns a vertical slice: Engines/Blog/{Http,Models,Database/Migrations,Routes,Providers,Resources}. Keep the engine folder flat-ish and cohesive rather than replicating the default app/ shape inside it.
Service provider as the engine boundary. Each engine should register its own bindings, event listeners, and route files in its provider. Call out this convention in your team's contribution guide — it's the single most important thing for keeping engines decoupled.
Auto-discovery vs. explicit registration. If Laragine auto-discovers engines from a directory/config glob, prefer explicit registration in a providers array in config for the engines you care about. Auto-discovery makes it easy to accidentally ship a half-finished engine; explicit registration makes the app's module surface auditable in code review.
Routes: keep one routes/web.php and one routes/api.php per engine, and let the engine's provider call Route::middleware(...)->prefix(...)->group(...). Avoid cross-engine route closures reaching into other engines' controllers — that reintroduces the coupling you bought the package to remove.
Migrations: per-engine migration folders are a common feature of this class of package. When they exist, prefer running php artisan migrate normally (the provider should merge paths) and keep timestamps unique across engines to avoid ordering surprises. If the package loads engine migrations in a separate command, wire that into your deploy script explicitly rather than relying on someone remembering.
Communication between engines: use contracts (interfaces bound in providers) or Laravel events, never new BlogService() from inside Billing. This is the day-to-day discipline that makes the modularization pay off; without it, engines become just deeply nested folders with worse IDE support.
Shared code: anything genuinely shared (base request classes, value objects, traits) belongs in a shared/support engine or in app/Support, not copied into multiple engines. A quick grep for duplicate helper functions is a good periodic check.
Incremental adoption in an existing app: pick one low-risk domain, create the engine, and use Laravel's class_alias or a thin adapter if other code still references the old namespace. This lets you move one slice per sprint without a big-bang refactor.
Testing: add each engine's tests inside the engine (Engines/Blog/Tests) and confirm phpunit.xml includes the engine test directories. If the package doesn't do this automatically, add the paths yourself — otherwise engine tests silently don't run.
Autoloading is the #1 failure mode. New engine namespaces under something like Engines\Blog\ need to be PSR-4 mapped (either via the package's composer.json merge plugin or manually in your root composer.json). Run composer dump-autoload every time you add an engine; "class not found" after scaffolding almost always means a stale autoloader.
Route and config caching. php artisan route:cache and config:cache can hide newly added engine routes or config keys. During development, php artisan optimize:clear after any engine scaffolding or provider change. In production, remember to re-run route:cache after adding an engine — otherwise the routes exist on disk but not in the cached router.
Migration ordering. If engines ship their own migrations with their own timestamps, a fresh migrate can interleave them in unexpected order across engines. Either namespace migration filenames per engine (e.g. 2024_01_01_000000_blog_create_posts_table.php with deliberate ordering) or accept that foreign keys across engines require the referenced engine to migrate first.
Provider registration order matters. If engine A binds an interface that engine B's provider depends on, B must boot after A. Laragine's auto-registration likely sorts alphabetically or by config order — read the discovery code before assuming. Document any required order in config/laragine.php comments.
Debugging checklist when something "isn't there": (1) php artisan list | grep -i laragine to confirm commands registered; (2) check config/laragine.php path globs; (3) php artisan about / php artisan route:list to see what actually loaded; (4) composer dump-autoload -o; (5) php artisan optimize:clear; (6) tail storage/logs/laravel.log. In that order.
Stub customization. Most engine-generating packages let you publish their stubs (vendor:... stubs). If you have team conventions (strict types, docblocks, base controller), publish and edit the stubs once so laragine:engine produces compliant code out of the box — cheaper than fixing every scaffold by hand.
Low-maintenance risk. With 42 stars and the last tagged release in April 2024, pin your Laravel version in composer.json ("laravel/framework": "^10.0" or whatever the package supports) so a Laravel major upgrade doesn't silently break engine discovery. Before upgrading Laravel, run the engine test suite and check the package's open issues.
Don't over-engineer. The engine concept is easy to fall in love with; you can end up with 15 engines and 3 real domains. Start with one engine per bounded context and only split when an engine's internals start fighting each other. Engines that share models heavily are a signal the boundary is wrong, not that you need a shared engine.
Extension points worth knowing: engine service providers (bindings, route registration, event listeners), published stubs (code-gen conventions), and the config file (discovery paths and provider loading). If you can't hook what you need through those three, prefer subclassing/wrapping the package's provider over forking — forks of small packages get stale fast.
How can I help you explore Laravel packages today?