1577 lines
43 KiB
PHP
1577 lines
43 KiB
PHP
<?php
|
|
|
|
namespace Laravel\Nova;
|
|
|
|
use BadMethodCallException;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Blade;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Route;
|
|
use Illuminate\Support\Str;
|
|
use Laravel\Nova\Actions\ActionResource;
|
|
use Laravel\Nova\Contracts\ImpersonatesUsers;
|
|
use Laravel\Nova\Exceptions\ResourceMissingException;
|
|
use Laravel\Nova\Http\Middleware\RedirectIfAuthenticated;
|
|
use Laravel\Nova\Http\Requests\NovaRequest;
|
|
use Laravel\Nova\Menu\Menu;
|
|
use ReflectionClass;
|
|
use Symfony\Component\Finder\Finder;
|
|
|
|
/**
|
|
* @method static bool runsMigrations()
|
|
*/
|
|
class Nova
|
|
{
|
|
use AuthorizesRequests;
|
|
use Concerns\HandlesRoutes;
|
|
use Concerns\InteractsWithActionEvent;
|
|
use Concerns\InteractsWithEvents;
|
|
|
|
/**
|
|
* The registered dashboard names.
|
|
*
|
|
* @var array<int, \Laravel\Nova\Dashboard>
|
|
*/
|
|
public static $dashboards = [];
|
|
|
|
/**
|
|
* The registered resource names.
|
|
*
|
|
* @var array<int, class-string<\Laravel\Nova\Resource>>
|
|
*/
|
|
public static $resources = [];
|
|
|
|
/**
|
|
* An index of resource names keyed by the model name.
|
|
*
|
|
* @var array<class-string<\Illuminate\Database\Eloquent\Model>, class-string<\Laravel\Nova\Resource>>
|
|
*/
|
|
public static $resourcesByModel = [];
|
|
|
|
/**
|
|
* The callback used to create new users via the CLI.
|
|
*
|
|
* @var (\Closure(string, string, string):(\Illuminate\Database\Eloquent\Model))|null
|
|
*/
|
|
public static $createUserCallback;
|
|
|
|
/**
|
|
* The callback used to gather new user information via the CLI.
|
|
*
|
|
* @var (\Closure(\Illuminate\Console\Command):(array))|null
|
|
*/
|
|
public static $createUserCommandCallback;
|
|
|
|
/**
|
|
* The callable that resolves the user's locale.
|
|
*
|
|
* @var (\Closure(\Illuminate\Http\Request):(?string))|null
|
|
*/
|
|
public static $userLocaleCallback;
|
|
|
|
/**
|
|
* The callable that resolves the user's timezone.
|
|
*
|
|
* @var (\Closure(\Illuminate\Http\Request):(?string))|null
|
|
*/
|
|
public static $userTimezoneCallback;
|
|
|
|
/**
|
|
* All of the registered Nova tools.
|
|
*
|
|
* @var array<int, \Laravel\Nova\Tool>
|
|
*/
|
|
public static $tools = [];
|
|
|
|
/**
|
|
* All of the registered Nova tool scripts.
|
|
*
|
|
* @var array<int, \Laravel\Nova\Script>
|
|
*/
|
|
public static $scripts = [];
|
|
|
|
/**
|
|
* All of the registered Nova tool CSS.
|
|
*
|
|
* @var array<int, \Laravel\Nova\Style>
|
|
*/
|
|
public static $styles = [];
|
|
|
|
/**
|
|
* The variables that should be made available on the Nova JavaScript object.
|
|
*
|
|
* @var array<string, mixed>
|
|
*/
|
|
public static $jsonVariables = [];
|
|
|
|
/**
|
|
* The callback used to report Nova's exceptions.
|
|
*
|
|
* @var (\Closure(\Throwable):(void))|(callable(\Throwable):(void))|null
|
|
*/
|
|
public static $reportCallback;
|
|
|
|
/**
|
|
* Indicates if Nova should register its migrations.
|
|
*
|
|
* @var bool
|
|
*/
|
|
public static $runsMigrations = true;
|
|
|
|
/**
|
|
* The translations that should be made available on the Nova JavaScript object.
|
|
*
|
|
* @var array<string, string>
|
|
*/
|
|
public static $translations = [];
|
|
|
|
/**
|
|
* The callback used to sort Nova resources in the sidebar.
|
|
*
|
|
* @var (\Closure(string):(mixed))|null
|
|
*/
|
|
public static $sortCallback;
|
|
|
|
/**
|
|
* The debounce amount to use when using global search.
|
|
*
|
|
* @var float
|
|
*/
|
|
public static $debounce = 0.5;
|
|
|
|
/**
|
|
* The callback used to create Nova's main menu.
|
|
*
|
|
* @var (\Closure(\Illuminate\Http\Request, \Laravel\Nova\Menu\Menu):(\Laravel\Nova\Menu\Menu|array))|null
|
|
*/
|
|
public static $mainMenuCallback;
|
|
|
|
/**
|
|
* The callback used to create Nova's user menu.
|
|
*
|
|
* @var (\Closure(\Illuminate\Http\Request, \Laravel\Nova\Menu\Menu):(\Laravel\Nova\Menu\Menu|array))|null
|
|
*/
|
|
public static $userMenuCallback;
|
|
|
|
/**
|
|
* The callback used to resolve Nova's footer.
|
|
*
|
|
* @var (\Closure(\Illuminate\Http\Request):(string|\Stringable))|null
|
|
*/
|
|
public static $footerCallback;
|
|
|
|
/**
|
|
* The callback used to resolve Nova's RTL.
|
|
*
|
|
* @var (\Closure(\Laravel\Nova\Http\Requests\NovaRequest):(bool))|bool|null
|
|
*/
|
|
public static $rtlCallback;
|
|
|
|
/**
|
|
* The callback used to resolve Nova's Breadcrumb.
|
|
*
|
|
* @var (\Closure(\Laravel\Nova\Http\Requests\NovaRequest):(bool))|bool|null
|
|
*/
|
|
public static $withBreadcrumbs;
|
|
|
|
/**
|
|
* The initial path Nova should route to when visiting the base.
|
|
*
|
|
* @var string|(\Closure(\Illuminate\Http\Request):(string|null))
|
|
*/
|
|
public static $initialPath = '/dashboards/main';
|
|
|
|
/**
|
|
* Indicates if Nova is being used to authenticate users.
|
|
*
|
|
* @var bool
|
|
*/
|
|
public static $withAuthentication = false;
|
|
|
|
/**
|
|
* Indicates if Nova is being used to reset passwords.
|
|
*
|
|
* @var bool
|
|
*/
|
|
public static $withPasswordReset = false;
|
|
|
|
/**
|
|
* The interval (in seconds) to poll for new Nova notifications.
|
|
*
|
|
* @var int
|
|
*/
|
|
public static $notificationPollingInterval = 7;
|
|
|
|
/**
|
|
* Indicates if Nova's global search is enabled.
|
|
*
|
|
* @var bool
|
|
*/
|
|
public static $withGlobalSearch = true;
|
|
|
|
/**
|
|
* Indicates if Nova's notification center is enabled.
|
|
*
|
|
* @var bool
|
|
*/
|
|
public static $withNotificationCenter = true;
|
|
|
|
/**
|
|
* Indicates if Nova's light/dark mode switcher is enabled.
|
|
*
|
|
* @var bool
|
|
*/
|
|
public static $withThemeSwitcher = true;
|
|
|
|
/**
|
|
* Indicates if Nova's notification center should show unread count.
|
|
*
|
|
* @var bool
|
|
*/
|
|
public static $showUnreadCountInNotificationCenter = false;
|
|
|
|
/**
|
|
* Get the current Nova version.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function version()
|
|
{
|
|
return Cache::driver('array')->rememberForever('nova.version', function () {
|
|
$manifest = json_decode(File::get(__DIR__.'/../composer.json'), true);
|
|
|
|
$version = $manifest['version'] ?? '4.x';
|
|
|
|
return $version.' (Silver Surfer)';
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the app name utilized by Nova.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function name()
|
|
{
|
|
return config('nova.name', 'Nova Site');
|
|
}
|
|
|
|
/**
|
|
* Run callback when currently serving Nova.
|
|
*
|
|
* @param callable(\Laravel\Nova\Http\Requests\NovaRequest):mixed $callback
|
|
* @param (callable(\Illuminate\Http\Request):(mixed))|null $default
|
|
* @return mixed
|
|
*/
|
|
public static function whenServing(callable $callback, callable $default = null)
|
|
{
|
|
if (app()->bound(NovaRequest::class)) {
|
|
return $callback(app()->make(NovaRequest::class));
|
|
}
|
|
|
|
if (is_callable($default)) {
|
|
return $default(app('request'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get current user using `nova.guard`.
|
|
*
|
|
* @param \Illuminate\Http\Request|null $request
|
|
* @return \Illuminate\Foundation\Auth\User|null
|
|
*/
|
|
public static function user(Request $request = null)
|
|
{
|
|
$guard = config('nova.guard');
|
|
|
|
if (is_null($request)) {
|
|
return call_user_func(app('auth')->userResolver(), $guard);
|
|
}
|
|
|
|
return $request->user($guard);
|
|
}
|
|
|
|
/**
|
|
* Register the Nova routes.
|
|
*
|
|
* @return \Laravel\Nova\PendingRouteRegistration
|
|
*/
|
|
public static function routes()
|
|
{
|
|
Route::aliasMiddleware('nova.guest', RedirectIfAuthenticated::class);
|
|
|
|
return new PendingRouteRegistration();
|
|
}
|
|
|
|
/**
|
|
* Retrieve Nova's Impersonator Implementation.
|
|
*
|
|
* @return \Laravel\Nova\Contracts\ImpersonatesUsers
|
|
*/
|
|
public static function impersonator()
|
|
{
|
|
return app(ImpersonatesUsers::class);
|
|
}
|
|
|
|
/**
|
|
* Enable Nova's authentication functionality.
|
|
*
|
|
* @return static
|
|
*/
|
|
public static function withAuthentication()
|
|
{
|
|
static::$withAuthentication = true;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Enable Nova's password reset functionality.
|
|
*
|
|
* @return static
|
|
*/
|
|
public static function withPasswordReset()
|
|
{
|
|
static::$withPasswordReset = true;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Get the resources available for the given request.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return array
|
|
*/
|
|
public static function resourcesForNavigation(Request $request)
|
|
{
|
|
return static::authorizedResources($request)
|
|
->availableForNavigation($request)
|
|
->sortBy(static::sortResourcesWith())
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* Return Nova's authorized resources.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Laravel\Nova\ResourceCollection<int, class-string<\Laravel\Nova\Resource>>
|
|
*/
|
|
public static function authorizedResources(Request $request)
|
|
{
|
|
return static::resourceCollection()->authorized($request);
|
|
}
|
|
|
|
/**
|
|
* Return the base collection of Nova resources.
|
|
*
|
|
* @return \Laravel\Nova\ResourceCollection<int, class-string<\Laravel\Nova\Resource>>
|
|
*/
|
|
private static function resourceCollection()
|
|
{
|
|
return ResourceCollection::make(static::$resources);
|
|
}
|
|
|
|
/**
|
|
* Get the sorting strategy to use for Nova resources.
|
|
*
|
|
* @return \Closure(string):mixed
|
|
*/
|
|
public static function sortResourcesWith()
|
|
{
|
|
return static::$sortCallback ?? function ($resource) {
|
|
return $resource::label();
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Replace the registered resources with the given resources.
|
|
*
|
|
* @param array<int, class-string<\Laravel\Nova\Resource>> $resources
|
|
* @return static
|
|
*/
|
|
public static function replaceResources(array $resources)
|
|
{
|
|
static::$resources = $resources;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Get the available resource groups for the given request.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Illuminate\Support\Collection
|
|
*/
|
|
public static function groups(Request $request)
|
|
{
|
|
return collect(static::availableResources($request))
|
|
->map(function ($item, $key) {
|
|
return $item::group();
|
|
})->unique()->values();
|
|
}
|
|
|
|
/**
|
|
* Get the resources available for the given request.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return array<int, class-string<\Laravel\Nova\Resource>>
|
|
*/
|
|
public static function availableResources(Request $request)
|
|
{
|
|
return static::authorizedResources($request)
|
|
->sortBy(static::sortResourcesWith())
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* Get the grouped resources available for the given request.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return array<string, \Laravel\Nova\ResourceCollection<int, class-string<\Laravel\Nova\Resource>>>
|
|
*/
|
|
public static function groupedResources(Request $request)
|
|
{
|
|
return ResourceCollection::make(static::availableResources($request))
|
|
->grouped()
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* Get the grouped resources available for the given request.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Laravel\Nova\ResourceCollection<string, \Laravel\Nova\ResourceCollection<int, class-string<\Laravel\Nova\Resource>>>
|
|
*/
|
|
public static function groupedResourcesForNavigation(Request $request)
|
|
{
|
|
return ResourceCollection::make(static::availableResources($request))
|
|
->groupedForNavigation($request)
|
|
->filter->count();
|
|
}
|
|
|
|
/**
|
|
* Register all of the resource classes in the given directory.
|
|
*
|
|
* @param string $directory
|
|
* @return void
|
|
*/
|
|
public static function resourcesIn($directory)
|
|
{
|
|
$namespace = app()->getNamespace();
|
|
|
|
$resources = [];
|
|
|
|
foreach ((new Finder())->in($directory)->files() as $resource) {
|
|
$resource = $namespace.str_replace(
|
|
['/', '.php'],
|
|
['\\', ''],
|
|
Str::after($resource->getPathname(), app_path().DIRECTORY_SEPARATOR)
|
|
);
|
|
|
|
if (
|
|
is_subclass_of($resource, Resource::class) &&
|
|
! (new ReflectionClass($resource))->isAbstract() &&
|
|
! is_subclass_of($resource, ActionResource::class)
|
|
) {
|
|
$resources[] = $resource;
|
|
}
|
|
}
|
|
|
|
static::resources(
|
|
collect($resources)->sort()->all()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Register the given resources.
|
|
*
|
|
* @param array<int, class-string<\Laravel\Nova\Resource>> $resources
|
|
* @return static
|
|
*/
|
|
public static function resources(array $resources)
|
|
{
|
|
static::$resources = array_unique(
|
|
array_merge(static::$resources, $resources)
|
|
);
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Get a new resource instance with the given model instance.
|
|
*
|
|
* @param \Illuminate\Database\Eloquent\Model $model
|
|
* @return \Laravel\Nova\Resource<\Illuminate\Database\Eloquent\Model>
|
|
*
|
|
* @throws \Laravel\Nova\Exceptions\ResourceMissingException
|
|
*/
|
|
public static function newResourceFromModel($model)
|
|
{
|
|
if (is_null($resource = static::resourceForModel($model))) {
|
|
throw new ResourceMissingException($model);
|
|
}
|
|
|
|
return new $resource($model);
|
|
}
|
|
|
|
/**
|
|
* Get the resource class name for a given model class.
|
|
*
|
|
* @param \Illuminate\Database\Eloquent\Model|class-string<\Illuminate\Database\Eloquent\Model> $class
|
|
* @return class-string<\Laravel\Nova\Resource>|null
|
|
*/
|
|
public static function resourceForModel($class)
|
|
{
|
|
if (is_object($class)) {
|
|
$class = get_class($class);
|
|
}
|
|
|
|
if (isset(static::$resourcesByModel[$class])) {
|
|
return static::$resourcesByModel[$class];
|
|
}
|
|
|
|
$resource = static::resourceCollection()->first(function ($value) use ($class) {
|
|
return $value::$model === $class;
|
|
});
|
|
|
|
return static::$resourcesByModel[$class] = $resource;
|
|
}
|
|
|
|
/**
|
|
* Get a resource instance for a given key.
|
|
*
|
|
* @param string $key
|
|
* @return \Laravel\Nova\Resource|null
|
|
*/
|
|
public static function resourceInstanceForKey($key)
|
|
{
|
|
if ($resource = static::resourceForKey($key)) {
|
|
return new $resource($resource::newModel());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the resource class name for a given key.
|
|
*
|
|
* @param string $key
|
|
* @return class-string<\Laravel\Nova\Resource>|null
|
|
*/
|
|
public static function resourceForKey($key)
|
|
{
|
|
return static::resourceCollection()->first(function ($value) use ($key) {
|
|
return $value::uriKey() === $key;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get a fresh model instance for the resource with the given key.
|
|
*
|
|
* @param string $key
|
|
* @return \Illuminate\Database\Eloquent\Model|null
|
|
*/
|
|
public static function modelInstanceForKey($key)
|
|
{
|
|
$resource = static::resourceForKey($key);
|
|
|
|
return $resource ? $resource::newModel() : null;
|
|
}
|
|
|
|
/**
|
|
* Create a new user instance.
|
|
*
|
|
* @param \Illuminate\Console\Command $command
|
|
* @return mixed
|
|
*/
|
|
public static function createUser($command)
|
|
{
|
|
if (! static::$createUserCallback) {
|
|
static::createUserUsing();
|
|
}
|
|
|
|
return call_user_func(
|
|
static::$createUserCallback,
|
|
...call_user_func(static::$createUserCommandCallback, $command)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Register the callbacks used to create a new user via the CLI.
|
|
*
|
|
* @param (\Closure(\Illuminate\Console\Command):(array))|null $createUserCommandCallback
|
|
* @param (\Closure(string, string, string):(\Illuminate\Database\Eloquent\Model))|null $createUserCallback
|
|
* @return static
|
|
*/
|
|
public static function createUserUsing($createUserCommandCallback = null, $createUserCallback = null)
|
|
{
|
|
if (! $createUserCallback) {
|
|
$createUserCallback = $createUserCommandCallback;
|
|
$createUserCommandCallback = null;
|
|
}
|
|
|
|
static::$createUserCommandCallback = $createUserCommandCallback ??
|
|
static::defaultCreateUserCommandCallback();
|
|
|
|
static::$createUserCallback = $createUserCallback ??
|
|
static::defaultCreateUserCallback();
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Get the default callback used for the create user command.
|
|
*
|
|
* @return \Closure(\Illuminate\Console\Command):array
|
|
*/
|
|
protected static function defaultCreateUserCommandCallback()
|
|
{
|
|
return function ($command) {
|
|
return [
|
|
$command->ask('Name'),
|
|
$command->ask('Email Address'),
|
|
$command->secret('Password'),
|
|
];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get the default callback used for creating new Nova users.
|
|
*
|
|
* @return \Closure(string, string, string):\Illuminate\Database\Eloquent\Model
|
|
*/
|
|
protected static function defaultCreateUserCallback()
|
|
{
|
|
return function ($name, $email, $password) {
|
|
$model = Util::userModel();
|
|
|
|
return tap((new $model())->forceFill([
|
|
'name' => $name,
|
|
'email' => $email,
|
|
'password' => Hash::make($password),
|
|
]))->save();
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Set the callable that resolves the user's preferred timezone.
|
|
*
|
|
* @param (callable(\Illuminate\Http\Request):(?string))|null $userTimezoneCallback
|
|
* @return static
|
|
*/
|
|
public static function userTimezone($userTimezoneCallback)
|
|
{
|
|
static::$userTimezoneCallback = $userTimezoneCallback;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Resolve the user's preferred timezone.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return string|null
|
|
*/
|
|
public static function resolveUserTimezone(Request $request)
|
|
{
|
|
if (static::$userTimezoneCallback) {
|
|
return call_user_func(static::$userTimezoneCallback, $request);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register new tools with Nova.
|
|
*
|
|
* @param array<int, \Laravel\Nova\Tool> $tools
|
|
* @return static
|
|
*/
|
|
public static function tools(array $tools)
|
|
{
|
|
static::$tools = array_merge(
|
|
static::$tools,
|
|
$tools
|
|
);
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Get the tools registered with Nova.
|
|
*
|
|
* @return array<int, \Laravel\Nova\Tool>
|
|
*/
|
|
public static function registeredTools()
|
|
{
|
|
return static::$tools;
|
|
}
|
|
|
|
/**
|
|
* Boot the available Nova tools.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return void
|
|
*/
|
|
public static function bootTools(Request $request)
|
|
{
|
|
collect(static::availableTools($request))->each->boot();
|
|
}
|
|
|
|
/**
|
|
* Get the tools registered with Nova.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return array<int, \Laravel\Nova\Tool>
|
|
*/
|
|
public static function availableTools(Request $request)
|
|
{
|
|
if (is_null(static::user($request))) {
|
|
return [];
|
|
}
|
|
|
|
return collect(static::$tools)->filter->authorize($request)->all();
|
|
}
|
|
|
|
/**
|
|
* Get the dashboards registered with Nova.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return array<int, \Laravel\Nova\Dashboard>
|
|
*/
|
|
public static function availableDashboards(Request $request)
|
|
{
|
|
return collect(static::$dashboards)->filter->authorize($request)->all();
|
|
}
|
|
|
|
/**
|
|
* Register the dashboards.
|
|
*
|
|
* @param array<int, \Laravel\Nova\Dashboard> $dashboards
|
|
* @return static
|
|
*/
|
|
public static function dashboards(array $dashboards)
|
|
{
|
|
static::$dashboards = array_merge(static::$dashboards, $dashboards);
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Get the available dashboard cards for the given request.
|
|
*
|
|
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
|
* @return \Illuminate\Support\Collection
|
|
*/
|
|
public static function allAvailableDashboardCards(NovaRequest $request)
|
|
{
|
|
return collect(static::$dashboards)
|
|
->filter
|
|
->authorize($request)
|
|
->flatMap(function ($dashboard) {
|
|
/** @var \Laravel\Nova\Dashboard $dashboard */
|
|
return $dashboard->cards();
|
|
})->unique()
|
|
->filter
|
|
->authorize($request)
|
|
->values();
|
|
}
|
|
|
|
/**
|
|
* Get the available dashboard for the given request.
|
|
*
|
|
* @param string $dashboard
|
|
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
|
* @return \Laravel\Nova\Dashboard|null
|
|
*/
|
|
public static function dashboardForKey($dashboard, NovaRequest $request)
|
|
{
|
|
return collect(static::$dashboards)
|
|
->first(function ($dash) use ($dashboard, $request) {
|
|
return $dash->uriKey() === $dashboard && $dash->authorize($request);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the available dashboard cards for the given request.
|
|
*
|
|
* @param string $dashboard
|
|
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
|
|
* @return \Illuminate\Support\Collection
|
|
*/
|
|
public static function availableDashboardCardsForDashboard($dashboard, NovaRequest $request)
|
|
{
|
|
return with(static::dashboardForKey($dashboard, $request), function ($dashboard) use ($request) {
|
|
if (is_null($dashboard)) {
|
|
return collect();
|
|
}
|
|
|
|
return collect($dashboard->cards())->filter->authorize($request)->values();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get all of the additional scripts that should be registered.
|
|
*
|
|
* @return array<int, \Laravel\Nova\Script>
|
|
*/
|
|
public static function allScripts()
|
|
{
|
|
return static::$scripts;
|
|
}
|
|
|
|
/**
|
|
* Get all of the available scripts that should be registered.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return array<int, \Laravel\Nova\Script>
|
|
*/
|
|
public static function availableScripts(Request $request)
|
|
{
|
|
if (is_null(static::user($request))) {
|
|
return [];
|
|
}
|
|
|
|
return static::$scripts;
|
|
}
|
|
|
|
/**
|
|
* Get all of the additional stylesheets that should be registered.
|
|
*
|
|
* @return array<int, \Laravel\Nova\Style>
|
|
*/
|
|
public static function allStyles()
|
|
{
|
|
return static::$styles;
|
|
}
|
|
|
|
/**
|
|
* Get all of the available stylesheets that should be registered.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return array<int, \Laravel\Nova\Style>
|
|
*/
|
|
public static function availableStyles(Request $request)
|
|
{
|
|
if (is_null(static::user($request))) {
|
|
return [];
|
|
}
|
|
|
|
return static::$styles;
|
|
}
|
|
|
|
/**
|
|
* Register the given remote script file with Nova.
|
|
*
|
|
* @param string $path
|
|
* @return static
|
|
*/
|
|
public static function remoteScript($path)
|
|
{
|
|
return static::script(Script::remote($path), $path);
|
|
}
|
|
|
|
/**
|
|
* Register the given script file with Nova.
|
|
*
|
|
* @param string|\Laravel\Nova\Script $name
|
|
* @param string $path
|
|
* @return static
|
|
*/
|
|
public static function script($name, $path)
|
|
{
|
|
static::$scripts[] = new Script($name, $path);
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Register the given remote CSS file with Nova.
|
|
*
|
|
* @param string $path
|
|
* @return static
|
|
*/
|
|
public static function remoteStyle($path)
|
|
{
|
|
return static::style(Style::remote($path), $path);
|
|
}
|
|
|
|
/**
|
|
* Register the given CSS file with Nova.
|
|
*
|
|
* @param string|\Laravel\Nova\Style $name
|
|
* @param string $path
|
|
* @return static
|
|
*/
|
|
public static function style($name, $path)
|
|
{
|
|
static::$styles[] = new Style($name, $path);
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Register the given translations with Nova.
|
|
*
|
|
* @param array<string, string>|string $translations
|
|
* @return static
|
|
*/
|
|
public static function translations($translations)
|
|
{
|
|
if (is_string($translations)) {
|
|
if (! is_readable($translations)) {
|
|
return new static();
|
|
}
|
|
|
|
$translations = json_decode(file_get_contents($translations), true);
|
|
}
|
|
|
|
static::$translations = array_merge(static::$translations, $translations);
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Get all of the additional translations that should be loaded.
|
|
*
|
|
* @return array<string, string>
|
|
*/
|
|
public static function allTranslations()
|
|
{
|
|
return static::$translations;
|
|
}
|
|
|
|
/**
|
|
* Get the JSON variables that should be provided to the global Nova JavaScript object.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return array<string, mixed>
|
|
*/
|
|
public static function jsonVariables(Request $request)
|
|
{
|
|
return collect(static::$jsonVariables)->map(function ($variable) use ($request) {
|
|
return is_object($variable) && is_callable($variable)
|
|
? $variable($request)
|
|
: $variable;
|
|
})->all();
|
|
}
|
|
|
|
/**
|
|
* Configure Nova to not register its migrations.
|
|
*
|
|
* @return static
|
|
*/
|
|
public static function ignoreMigrations()
|
|
{
|
|
static::$runsMigrations = false;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Humanize the given value into a proper name.
|
|
*
|
|
* @param string|object $value
|
|
* @return string
|
|
*/
|
|
public static function humanize($value)
|
|
{
|
|
if (is_object($value)) {
|
|
return static::humanize(class_basename(get_class($value)));
|
|
}
|
|
|
|
return Str::title(Str::snake($value, ' '));
|
|
}
|
|
|
|
/**
|
|
* Register the callback used to set a custom Nova error reporter.
|
|
*
|
|
* @param (\Closure(\Throwable):(void))|(callable(\Throwable):(void))|null $callback
|
|
* @return static
|
|
*/
|
|
public static function report($callback)
|
|
{
|
|
static::$reportCallback = $callback;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Provide additional variables to the global Nova JavaScript object.
|
|
*
|
|
* @param array<string, mixed> $variables
|
|
* @return static
|
|
*/
|
|
public static function provideToScript(array $variables)
|
|
{
|
|
if (empty(static::$jsonVariables)) {
|
|
$userId = Auth::guard(config('nova.guard'))->id() ?? null;
|
|
|
|
static::$jsonVariables = [
|
|
'debug' => function () {
|
|
return config('app.debug') || app()->environment('testing');
|
|
},
|
|
'logo' => static::logo(),
|
|
'brandColors' => static::brandColors(),
|
|
'brandColorsCSS' => static::brandColorsCSS(),
|
|
'rtlEnabled' => function () {
|
|
return static::rtlEnabled();
|
|
},
|
|
'breadcrumbsEnabled' => function () {
|
|
return static::breadcrumbsEnabled();
|
|
},
|
|
'globalSearchEnabled' => function () {
|
|
return static::globalSearchIsEnabled() && static::hasGloballySearchableResources();
|
|
},
|
|
'notificationCenterEnabled' => function () {
|
|
return static::$withNotificationCenter;
|
|
},
|
|
'hasGloballySearchableResources' => function () {
|
|
return static::hasGloballySearchableResources();
|
|
},
|
|
'themeSwitcherEnabled' => function () {
|
|
return static::$withThemeSwitcher;
|
|
},
|
|
'showUnreadCountInNotificationCenter' => function () {
|
|
return static::$showUnreadCountInNotificationCenter;
|
|
},
|
|
'withAuthentication' => static::$withAuthentication,
|
|
'withPasswordReset' => static::$withPasswordReset,
|
|
'customLoginPath' => config('nova.routes.login', false),
|
|
'customLogoutPath' => config('nova.routes.logout', false),
|
|
'forgotPasswordPath' => config('nova.routes.forgot_password', false),
|
|
'resetPasswordPath' => config('nova.routes.reset_password', false),
|
|
'debounce' => static::$debounce * 1000,
|
|
'initialPath' => function ($request) {
|
|
return static::resolveInitialPath($request);
|
|
},
|
|
'base' => static::path(),
|
|
'userId' => $userId,
|
|
'mainMenu' => function ($request) use ($userId) {
|
|
return ! is_null($userId) ? Menu::wrap(self::resolveMainMenu($request)) : [];
|
|
},
|
|
'userMenu' => function ($request) use ($userId) {
|
|
return ! is_null($userId) ? Menu::wrap(self::resolveUserMenu($request)) : Menu::make();
|
|
},
|
|
'notificationPollingInterval' => static::$notificationPollingInterval * 1000,
|
|
'resources' => function ($request) {
|
|
return static::resourceInformation($request);
|
|
},
|
|
'footer' => function ($request) {
|
|
return self::resolveFooter($request);
|
|
},
|
|
];
|
|
}
|
|
|
|
static::$jsonVariables = array_merge(static::$jsonVariables, $variables);
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Check to see if Nova is valid for the configured license key.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function checkLicenseValidity()
|
|
{
|
|
return Cache::remember('nova_valid_license_key', 3600, function () {
|
|
return rescue(function () {
|
|
return true;
|
|
}, false);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Check to see if Nova is valid for the configured license key.
|
|
*
|
|
* @return \Illuminate\Http\Client\Response
|
|
*/
|
|
public static function checkLicense()
|
|
{
|
|
return Http::post('https://nova.laravel.com/api/license-check', [
|
|
'url' => request()->getHost(),
|
|
'key' => config('nova.license_key', ''),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get the logo that is configured for the Nova admin.
|
|
*
|
|
* @return string|null
|
|
*/
|
|
public static function logo()
|
|
{
|
|
$logo = config('nova.brand.logo');
|
|
|
|
if (! empty($logo) && file_exists(realpath($logo))) {
|
|
return file_get_contents(realpath($logo));
|
|
}
|
|
|
|
return $logo;
|
|
}
|
|
|
|
/**
|
|
* Get Nova's content direction.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function rtlEnabled()
|
|
{
|
|
if (is_callable(static::$rtlCallback)) {
|
|
static::$rtlCallback = value(static::$rtlCallback, app(NovaRequest::class));
|
|
}
|
|
|
|
return (bool) static::$rtlCallback;
|
|
}
|
|
|
|
/**
|
|
* Enable RTL content direction.
|
|
*
|
|
* @param (\Closure(\Laravel\Nova\Http\Requests\NovaRequest):(bool))|bool $rtlCallback
|
|
* @return static
|
|
*/
|
|
public static function enableRTL($rtlCallback = true)
|
|
{
|
|
static::$rtlCallback = $rtlCallback;
|
|
|
|
return new static;
|
|
}
|
|
|
|
/**
|
|
* Determine if there are any globally searchable resources.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function hasGloballySearchableResources()
|
|
{
|
|
return collect(static::globallySearchableResources(app(NovaRequest::class)))->count() > 0;
|
|
}
|
|
|
|
/**
|
|
* Determine if global search is enabled.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function globalSearchIsEnabled(): bool
|
|
{
|
|
return static::$withGlobalSearch;
|
|
}
|
|
|
|
/**
|
|
* Get the resources available for the given request.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return array<int, class-string<\Laravel\Nova\Resource>>
|
|
*/
|
|
public static function globallySearchableResources(Request $request)
|
|
{
|
|
return static::authorizedResources($request)
|
|
->searchable()
|
|
->sortBy(static::sortResourcesWith())
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* Get the URI path prefix utilized by Nova.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function path()
|
|
{
|
|
return config('nova.path', '/nova');
|
|
}
|
|
|
|
/**
|
|
* Resolve the main menu for Nova.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Laravel\Nova\Menu\Menu
|
|
*/
|
|
public static function resolveMainMenu(Request $request)
|
|
{
|
|
$defaultMenu = static::defaultMainMenu($request);
|
|
|
|
if (! is_null(static::$mainMenuCallback)) {
|
|
return call_user_func(static::$mainMenuCallback, $request, $defaultMenu);
|
|
}
|
|
|
|
return $defaultMenu;
|
|
}
|
|
|
|
/**
|
|
* Resolve the default main menu for Nova.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Laravel\Nova\Menu\Menu
|
|
*/
|
|
public static function defaultMainMenu(Request $request)
|
|
{
|
|
return Menu::make(with(collect(static::availableTools($request)), function ($tools) use ($request) {
|
|
return $tools->map(function ($tool) use ($request) {
|
|
return $tool->menu($request);
|
|
});
|
|
})->filter()->values()->all());
|
|
}
|
|
|
|
/**
|
|
* Resolve the user menu for Nova.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Laravel\Nova\Menu\Menu
|
|
*/
|
|
public static function resolveUserMenu(Request $request)
|
|
{
|
|
$defaultMenu = static::defaultUserMenu($request);
|
|
|
|
if (! is_null(static::$userMenuCallback)) {
|
|
return call_user_func(static::$userMenuCallback, $request, $defaultMenu);
|
|
}
|
|
|
|
return $defaultMenu;
|
|
}
|
|
|
|
/**
|
|
* Resolve the default user menu for Nova.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Laravel\Nova\Menu\Menu
|
|
*/
|
|
public static function defaultUserMenu(Request $request)
|
|
{
|
|
return Menu::make([
|
|
//
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get meta data information about all resources for client side consumption.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
public static function resourceInformation(Request $request)
|
|
{
|
|
return static::resourceCollection()->map(function ($resource) use ($request) {
|
|
/** @var class-string<\Laravel\Nova\Resource> $resource */
|
|
return array_merge([
|
|
'uriKey' => $resource::uriKey(),
|
|
'label' => $resource::label(),
|
|
'singularLabel' => $resource::singularLabel(),
|
|
'createButtonLabel' => $resource::createButtonLabel(),
|
|
'updateButtonLabel' => $resource::updateButtonLabel(),
|
|
'authorizedToCreate' => $resource::authorizedToCreate($request),
|
|
'searchable' => $resource::searchable(),
|
|
'perPageOptions' => $resource::perPageOptions(),
|
|
'tableStyle' => $resource::tableStyle(),
|
|
'showColumnBorders' => $resource::showColumnBorders(),
|
|
'debounce' => $resource::$debounce * 1000,
|
|
'clickAction' => $resource::$clickAction,
|
|
], $resource::additionalInformation($request));
|
|
})->values()->all();
|
|
}
|
|
|
|
/**
|
|
* Dynamically proxy static method calls.
|
|
*
|
|
* @param string $method
|
|
* @param array $parameters
|
|
* @return mixed
|
|
*
|
|
* @throws \BadMethodCallException
|
|
*/
|
|
public static function __callStatic($method, $parameters)
|
|
{
|
|
if (! property_exists(get_called_class(), $method)) {
|
|
throw new BadMethodCallException("Method {$method} does not exist.");
|
|
}
|
|
|
|
return static::${$method};
|
|
}
|
|
|
|
/**
|
|
* Register the callback used to sort Nova resources in the sidebar.
|
|
*
|
|
* @param \Closure(string):mixed $callback
|
|
* @return static
|
|
*/
|
|
public static function sortResourcesBy($callback)
|
|
{
|
|
static::$sortCallback = $callback;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Return the debounce amount to use when using global search.
|
|
*
|
|
* @param int $debounce
|
|
* @return static
|
|
*/
|
|
public static function globalSearchDebounce($debounce)
|
|
{
|
|
static::$debounce = $debounce;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Set the main menu for Nova.
|
|
*
|
|
* @param \Closure(\Illuminate\Http\Request, \Laravel\Nova\Menu\Menu):(\Laravel\Nova\Menu\Menu|array) $callback
|
|
* @return static
|
|
*/
|
|
public static function mainMenu($callback)
|
|
{
|
|
static::$mainMenuCallback = $callback;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Set the initial route path when visiting the base Nova url.
|
|
*
|
|
* @param string|(\Closure(\Illuminate\Http\Request):(string|null)) $path
|
|
* @return static
|
|
*/
|
|
public static function initialPath($path)
|
|
{
|
|
static::$initialPath = $path;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Set the main menu for Nova.
|
|
*
|
|
* @param \Closure(\Illuminate\Http\Request, \Laravel\Nova\Menu\Menu):(\Laravel\Nova\Menu\Menu|array) $userMenuCallback
|
|
* @return static
|
|
*/
|
|
public static function userMenu($userMenuCallback)
|
|
{
|
|
static::$userMenuCallback = $userMenuCallback;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Enable Breadcrumb Menu.
|
|
*
|
|
* @param (\Closure(\Laravel\Nova\Http\Requests\NovaRequest):(bool))|bool $withBreadcrumbs
|
|
* @return static
|
|
*/
|
|
public static function withBreadcrumbs($withBreadcrumbs = true)
|
|
{
|
|
static::$withBreadcrumbs = $withBreadcrumbs;
|
|
|
|
return new static;
|
|
}
|
|
|
|
/**
|
|
* Determine if Nova's breadcrumbs menu should be displayed.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function breadcrumbsEnabled()
|
|
{
|
|
return is_callable(static::$withBreadcrumbs)
|
|
? call_user_func(static::$withBreadcrumbs, app(NovaRequest::class))
|
|
: static::$withBreadcrumbs;
|
|
}
|
|
|
|
/**
|
|
* Set the polling interval used for Nova's notifications.
|
|
*
|
|
* @param int $seconds
|
|
* @return static
|
|
*/
|
|
public static function notificationPollingInterval($seconds)
|
|
{
|
|
static::$notificationPollingInterval = $seconds;
|
|
|
|
return new static;
|
|
}
|
|
|
|
/**
|
|
* Set the footer text used for Nova.
|
|
*
|
|
* @param \Closure(\Illuminate\Http\Request):(string|\Stringable) $footerCallback
|
|
* @return static
|
|
*/
|
|
public static function footer($footerCallback)
|
|
{
|
|
static::$footerCallback = $footerCallback;
|
|
|
|
return new static;
|
|
}
|
|
|
|
/**
|
|
* Resolve the footer used for Nova.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return string
|
|
*/
|
|
public static function resolveFooter(Request $request)
|
|
{
|
|
if (! is_null(static::$footerCallback)) {
|
|
return (string) call_user_func(static::$footerCallback, $request);
|
|
}
|
|
|
|
return static::defaultFooter($request);
|
|
}
|
|
|
|
/**
|
|
* Resolve the default footer text used for Nova.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return string
|
|
*/
|
|
public static function defaultFooter(Request $request)
|
|
{
|
|
return Blade::render('
|
|
<p class="text-center">Powered by <a class="link-default" href="https://nova.laravel.com">Laravel Nova</a> · v{!! $version !!}</p>
|
|
<p class="text-center">© {!! $year !!} Laravel Holdings Inc.</p>
|
|
', [
|
|
'version' => static::version(),
|
|
'year' => date('Y'),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Disable global search globally.
|
|
*
|
|
* @return static
|
|
*/
|
|
public static function withoutGlobalSearch()
|
|
{
|
|
static::$withGlobalSearch = false;
|
|
|
|
return new static;
|
|
}
|
|
|
|
/**
|
|
* Disable notification center.
|
|
*
|
|
* @return static
|
|
*/
|
|
public static function withoutNotificationCenter()
|
|
{
|
|
static::$withNotificationCenter = false;
|
|
|
|
return new static;
|
|
}
|
|
|
|
/**
|
|
* Disable light/dark mode theme switching.
|
|
*
|
|
* @return static
|
|
*/
|
|
public static function withoutThemeSwitcher()
|
|
{
|
|
static::$withThemeSwitcher = false;
|
|
|
|
return new static;
|
|
}
|
|
|
|
/**
|
|
* Return Nova's custom brand colors.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function brandColors()
|
|
{
|
|
return collect(config('nova.brand.colors'))->reject(function ($value, $key) {
|
|
return is_null($value);
|
|
})->all();
|
|
}
|
|
|
|
/**
|
|
* Return the CSS used to override Nova's brand colors.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function brandColorsCSS()
|
|
{
|
|
return Blade::render('
|
|
:root {
|
|
@foreach($colors as $key => $value)
|
|
--colors-primary-{{ $key }}: {{ $value }};
|
|
@endforeach
|
|
}', [
|
|
'colors' => static::brandColors(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Set the callable that resolves the user's preferred locale.
|
|
*
|
|
* @param (callable(\Illuminate\Http\Request):(?string))|null $userLocaleCallback
|
|
* @return static
|
|
*/
|
|
public static function userLocale($userLocaleCallback)
|
|
{
|
|
static::$userLocaleCallback = $userLocaleCallback;
|
|
|
|
return new static();
|
|
}
|
|
|
|
/**
|
|
* Resolve the user's preferred locale.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return string
|
|
*/
|
|
public static function resolveUserLocale(Request $request)
|
|
{
|
|
$locale = null;
|
|
|
|
if (static::$userLocaleCallback) {
|
|
$locale = call_user_func(static::$userLocaleCallback, $request);
|
|
}
|
|
|
|
return str_replace('_', '-', $locale ?? app()->getLocale());
|
|
}
|
|
|
|
/**
|
|
* Resolve the user's initial path.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return string
|
|
*/
|
|
public static function resolveInitialPath(Request $request)
|
|
{
|
|
/** @phpstan-ignore-next-line */
|
|
return value(static::$initialPath, $request) ?? '/dashboards/main';
|
|
}
|
|
|
|
/**
|
|
* Translate the given message.
|
|
*
|
|
* @param \Laravel\Nova\Support\PendingTranslation|string|null $key
|
|
* @param array<string, string> $replace
|
|
* @param string|null $locale
|
|
* @return \Laravel\Nova\Support\PendingTranslation&\Stringable
|
|
*/
|
|
public static function __($key = null, $replace = [], $locale = null)
|
|
{
|
|
if ($key instanceof Support\PendingTranslation) {
|
|
return $key;
|
|
}
|
|
|
|
return new Support\PendingTranslation($key, $replace, $locale);
|
|
}
|
|
|
|
/**
|
|
* Enable unread notifications count in the notification center.
|
|
*
|
|
* @return static
|
|
*/
|
|
public static function showUnreadCountInNotificationCenter()
|
|
{
|
|
static::$showUnreadCountInNotificationCenter = true;
|
|
|
|
return new static;
|
|
}
|
|
}
|