redlab-team/helpers-bundle
Redlab Team's helpers-bundle packages reusable PHP helper utilities into one convenient bundle, offering common string, array, formatting, and general-purpose functions that reduce boilerplate, speed up development, and keep codebases consistent.
v2.0 is a breaking release: every helper that used to expose static methods is now a regular class you resolve from Laravel's service container. The first thing to do after composer require-ing the upgrade is to run a search for the old static call style across your codebase — grep -rn "HelperName::" app/ resources/ routes/ database/ — because none of those calls will work any more.
Start with a single, low-risk consumer: pick a controller or a queued job and inject the helper you use most.
use Acme\Helpers\StringHelper;
class ReportController extends Controller
{
public function __construct(private StringHelper $strings) {}
public function show(string $slug)
{
return view('reports.show', [
'title' => $this->strings->titleize($slug),
]);
}
}
If the class type-hints cleanly without any manual binding in a service provider, the package's auto-discovery and container bindings are working and you can proceed with the wider migration. If it does not resolve, check config/app.php for a manually registered provider and confirm you have re-run composer dump-autoload — a stale classmap is the most common cause of "class not found" immediately after this upgrade.
Constructor injection is the default. Controllers, jobs, listeners, commands, middleware and mailables are all resolved through the container, so constructor injection works everywhere. Prefer it over app(Helper::class) — it makes dependencies visible and lets you swap implementations in tests.
Inject into queued jobs, but resolve in handle() when state matters. Serialising a helper into a job payload is usually fine for stateless helpers, but if the helper carries per-request or per-tenant configuration, resolve it in handle() via method injection instead:
public function handle(CurrencyHelper $currency): void
{
$this->total = $currency->format($this->amount);
}
Bind to interfaces for the ones you actually want to fake. If the package ships contracts, bind them in a HelperServiceProvider; if not, wrap the helper behind your own interface. This is the biggest day-to-day payoff of the static-method removal: helpers become mockable without Facade::shouldReceive.
Blade and other non-container contexts. Views are not constructor-injected, so use @inject('strings', \Acme\Helpers\StringHelper::class) at the top of the template, or better, pass formatted values in from the controller / a view composer. Avoid reaching for a facade shim inside views — it quietly reintroduces the global-state coupling v2 is trying to remove.
Bulk migration tip. For files with many helper calls, temporarily alias the injected property to match the old facade name (private StringHelper $string) so the diff is mechanical, then rename in a second pass. It keeps the upgrade commit reviewable.
Grouping helpers. If the package exposes many small helpers, consider injecting only those used by a given class rather than injecting a single "kitchen sink" helper — it keeps constructors honest and unit tests fast.
Extension point. Because helpers are now ordinary classes, you can subclass or decorate them and bind your version in the container, which was effectively impossible with static methods.
new Helper() is no longer safe. If the helper has constructor dependencies, manual instantiation bypasses the container and will fail. Use app(Helper::class) in the rare places where injection genuinely is not possible (model accessors, config files, legacy global helpers).resources/views, config/, database/seeders, routes/, custom Blade directives, and any helpers.php in your own app.Helper::shouldReceive(...) with $this->mock(Helper::class) / $this->instance(...) in the container, and assert on the injected instance rather than the facade root. Any test that used Facade::clearResolvedInstances() needs revisiting.php artisan tinker → app(Helper::class) is the fastest way to confirm a binding; wrap in try/catch or run app()->bound() first. php artisan about will not show these bindings — inspect the provider's register() method instead.XxxHelper or move namespaces at the same time; a passing composer update does not mean your imports are correct.How can I help you explore Laravel packages today?