phattarachai/laravel-mobile-detect
Detect mobile, tablet, and desktop visitors in Laravel using a simple User-Agent based API. Check device type, OS, and browser anywhere in your app, with a clean facade and Blade-friendly helpers for serving the right experience.
v1.0.2 is a drop-in, non-breaking release — the only change is docblock-level (@method annotations added to the Facade class), so existing code needs no edits. Upgrade with:
composer require your-vendor/your-package:^1.0
If the package is auto-discovered, the ServiceProvider and Facade alias are registered for you. If not, add the alias to config/app.php under aliases. Verify the install with:
php artisan about # confirm the provider is booted
composer dump-autoload # refresh autoload + IDE index
Where to look first: open the Facade class and read the new @method block. As of v1.0.2 that docblock is effectively the package's public API index — every method listed is a real, supported call, and it is the fastest way to see what the package actually does without reading the service class. Then check the ServiceProvider for what it binds and whether there is a publishable config (php artisan vendor:publish --provider="Vendor\\Package\\ServiceProvider").
First use case: inject the underlying contract into a controller (preferred) or call the Facade statically in a one-off path. Both now autocomplete and type-check in your editor, which is the point of this release.
Prefer constructor injection; use the Facade at the edges. Resolve the underlying contract in constructors, jobs, and services so dependencies stay explicit and swappable. Reach for the Facade in Blade templates, route closures, Artisan commands, and quick prototypes — the places where injection is awkward. Both resolve the same singleton from the container.
// Preferred in classes
public function __construct(private PackageContract $package) {}
// Fine at the boundary
Route::get('/thing', fn () => Package::doSomething());
Treat the new @method block as your static-analysis contract. With Larastan/PHPStan or Psalm running, calls against the Facade are now checked. Run:
vendor/bin/phpstan analyse
This catches typos and argument-count mistakes that previously failed only at runtime — a genuinely useful CI gate when paired with larastan/larastan.
Testing via the Facade is the fastest path. Because the Facade proxies to a container binding, Facade::shouldReceive('method')->once()->andReturn($value) lets you unit-test callers without booting the real service. For integration-style tests, resolve the concrete class and use the real implementation. If the package ships a fake()-style helper, prefer it — it usually wires up the container binding correctly and avoids mock/proxy mismatches.
Swap implementations through the container, not by editing Facades. Bind your own implementation in a ServiceProvider:
$this->app->bind(PackageContract::class, CustomImplementation::class);
The Facade follows the binding automatically, which is the cleanest extension point the package offers.
Register the Facade alias explicitly in packages/older apps that disable auto-discovery; otherwise static calls work in tests but fail in production with "Class not found".
@method annotations added in v1.0.2 exist only for IDEs and static analysers. If the service class changes but the docblock is not regenerated, your editor will happily autocomplete a method that no longer exists, and you will only find out at runtime. After every package upgrade, diff the Facade docblock against the service class.php artisan config:clear && php artisan cache:clear && composer dump-autoload resolves the majority of "the new methods aren't showing up" reports — both in the IDE and at runtime.vendor/ directory is indexed and not excluded.barryvdh/laravel-ide-helper can generate a real-time facade docblock that stays in sync automatically: php artisan ide-helper:generate. Do not run it blindly if you also rely on the hand-written @method block — the generated file can shadow or duplicate hints.shouldReceive(...)->once() combined with a Facade that caches state between tests leads to flaky suites; call Facade::clearResolvedInstances() in tearDown() if you see leakage.dd(app(PackageContract::class)) and dd(Package::getFacadeRoot()) should return the same object — if they don't, you have a duplicate or overridden binding, usually from a second provider or a test that did not restore the container.How can I help you explore Laravel packages today?