nbgrp/env-bundle
nbgrp/env-bundle is a PHP package that simplifies environment variable management. It provides a clean, consistent way to load, organize, and access .env settings, helping keep configuration separate from code and easy to adapt across development, staging, and production.
v3.0.0 is a platform/compatibility release rather than a feature release: the only substantive change is Symfony 7 support, alongside CI/linter/Psalm housekeeping and a README improvement. There are no new APIs, deprecations, or breaking changes called out in the release notes, so treat the major bump as an ecosystem-alignment release (Symfony 7 implies PHP 8.2+ and pairs naturally with Laravel 11) rather than a rewrite.
Start with:
composer require <vendor>/<package>:^3.0
php artisan about
php artisan vendor:publish --provider="<Vendor>\\<Package>\\<Package>ServiceProvider"
Look first at:
config/<package>.php file that gets published.composer.json constraints for symfony/*, illuminate/*, and php — this tells you whether the bump is really about Symfony 7 or also about dropping older Laravel/PHP support.A good first use case is the simplest integration the package offers: resolve its client/manager from the container, inject it into a controller or queued job, configure credentials through .env, and make one call end-to-end before wiring it into anything else. If the package auto-discovers its provider, confirm it appears in bootstrap/cache/packages.php after composer dump-autoload.
Constructor injection over facades. Bind the package's client/manager in a service provider (or rely on its own binding) and inject it into controllers, jobs, and actions. Use the facade only for terse, one-off calls in controllers or Blade; keep domain/services code dependent on the injectable type so tests can swap it.
Config-first setup. Publish the config file, put environment-specific values in .env, and keep the committed config file as the source of truth for non-secret defaults. Since Laravel caches config, never call env() outside config files — read everything through config('<package>.*').
Push slow work to the queue. Anything that talks to an external service should run inside a job with sensible $tries, backoff(), and retryUntil(). If the package emits events or supports hooks, listen for them rather than polling.
Testing pattern. In TestCase::setUp(), bind a fake/stub implementation of the package's contract ($this->app->instance(...) or $this->swap(...)). If the package uses Laravel's HTTP client underneath, Http::fake() is usually enough. Use Event::fake() when asserting that package events fire.
Scheduled/batch usage. For bulk operations, wrap calls in an Artisan command and schedule it; use $this->components->info() for output so it plays nicely with Laravel's console UI.
Scoped bindings for multi-tenant apps. If the package holds per-tenant or per-connection state, register it with $this->app->scoped(...) (or bind + explicit reset) so long-running Octane/queue workers do not leak state between requests.
Extension points. Most packages of this shape expose one of: a manager with extend(), a contract you can rebind, or a config-driven driver list. Prefer rebinding the contract in a service provider over subclassing internals — that survives minor upgrades.
composer why-not <vendor>/<package> 3.0 before upgrading; transitive packages that pin symfony/* to 6.x are the usual blocker.composer.json for php, illuminate/support, and symfony/* ranges rather than trusting the commit list.php artisan config:clear, php artisan cache:clear, and composer dump-autoload. If the provider still isn't registered, delete bootstrap/cache/packages.php and bootstrap/cache/services.php.null.php artisan tinker and check app()->bound(<Contract>::class) and get_class(app(<Contract>::class)) to confirm which implementation is actually resolved.^3.0 rather than *, and let Renovate/Dependabot surface patch releases; the 3.x line should be low-churn given how 3.0.0 was assembled.How can I help you explore Laravel packages today?