<?php
namespace App\Providers;
use App\Enums\Acl\Role;
use App\Models\Album;
use App\Models\Artist;
use App\Models\Genre;
use App\Models\Playlist;
use App\Models\Podcast;
use App\Models\RadioStation;
use App\Models\Song;
use App\Models\User;
use App\Rules\ValidRadioStationUrl;
use App\Services\Contracts\Encyclopedia;
use App\Services\Geolocation\Contracts\GeolocationService;
use App\Services\Geolocation\IPinfoService;
use App\Services\LastfmService;
use App\Services\License\Contracts\LicenseServiceInterface;
use App\Services\LicenseService;
use App\Services\MusicBrainzService;
use App\Services\NullEncyclopedia;
use App\Services\Scanners\Contracts\ScannerCacheStrategy as ScannerCacheStrategyContract;
use App\Services\Scanners\ScannerCacheStrategy;
use App\Services\Scanners\ScannerNoCacheStrategy;
use App\Services\SpotifyService;
use App\Services\TicketmasterService;
use Illuminate\Database\DatabaseManager;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Schema\Builder;
use Illuminate\Database\SQLiteConnection;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
use SpotifyWebAPI\Session as SpotifySession;
class AppServiceProvider extends ServiceProvider
{
public function boot(Builder $schema, DatabaseManager $db): void
{
// Fix utf8mb4-related error starting from Laravel 5.4
$schema->defaultStringLength(191);
Model::preventLazyLoading(!app()->isProduction());
self::enableOnDeleteCascadeForSqliteConnections($db);
// disable wrapping JSON resource in a `data` key
JsonResource::withoutWrapping();
self::grantAllPermissionsToSuperAdminRole();
$this->app->bind(SpotifySession::class, static function () {
return SpotifyService::enabled()
? new SpotifySession(
config('koel.services.spotify.client_id'),
config('koel.services.spotify.client_secret'),
)
: null;
});
$this->app->bind(Encyclopedia::class, static function () {
// Prefer Last.fm over MusicBrainz, and fall back to a null encyclopedia.
if (LastfmService::enabled()) {
return app(LastfmService::class);
}
if (MusicBrainzService::enabled()) {
return app(MusicBrainzService::class);
}
return app(NullEncyclopedia::class);
});
$this->app->bind(LicenseServiceInterface::class, LicenseService::class);
$this->app->when(LicenseService::class)
->needs('$hashSalt')
->give(config('app.key'));
$this->app->bind(ScannerCacheStrategyContract::class, static function () {
// Use a no-cache strategy for unit tests to ensure consistent results
return app()->runningUnitTests() ? app(ScannerNoCacheStrategy::class) : app(ScannerCacheStrategy::class);
});
$this->app->singleton(ValidRadioStationUrl::class, static fn () => new ValidRadioStationUrl());
Route::bind('genre', static function (string $value): ?Genre {
if ($value === Genre::NO_GENRE_PUBLIC_ID) {
return null;
}
return Genre::query()->where('public_id', $value)->firstOrFail();
});
Relation::morphMap([
'playable' => Song::class,
'album' => Album::class,
'artist' => Artist::class,
'podcast' => Podcast::class,
'radio-station' => RadioStation::class,
'playlist' => Playlist::class,
]);
$this->app->when(TicketmasterService::class)
->needs('$defaultCountryCode')
->give(config('koel.services.ticketmaster.default_country_code'));
$this->app->bind(GeolocationService::class, static function (): GeolocationService {
return app(IPinfoService::class);
});
}
public function register(): void
{
if (class_exists('Laravel\Tinker\TinkerServiceProvider')) {
$this->app->register('Laravel\Tinker\TinkerServiceProvider');
}
}
private static function enableOnDeleteCascadeForSqliteConnections(DatabaseManager $db): void
{
if ($db->connection() instanceof SQLiteConnection) {
$db->statement($db->raw('PRAGMA foreign_keys = ON')->getValue($db->getQueryGrammar()));
}
}
private static function grantAllPermissionsToSuperAdminRole(): void
{
Gate::after(static fn (User $user) => $user->hasRole(Role::ADMIN));
}
}