Skip to main content

Laravel Nova v4.10.0 - Administration Panel For Laravel

Download

Requirements

Laravel Nova has a few requirements you should be aware of before installing:

  • Composer
  • Laravel Framework 8.0+
  • Laravel Mix 6
  • Node.js (Version 14)
  • NPM

#Browser Support

Nova supports modern versions of the following browsers:

  • Apple Safari
  • Google Chrome
  • Microsoft Edge
  • Mozilla Firefox

#Installing Nova Via Composer

Zip Downloads

Previous releases of Laravel Nova allowed Nova to be installed by downloading Zip archives of the source code; however, Nova 4 installation is always performed via Composer.

You may install Nova as a Composer package via our private Satis repository. To get started, add the Nova repository to your application's composer.json file:

"repositories": [
    {
        "type": "composer",
        "url": "https://nova.laravel.com"
    }
],

Or, you may use the following CLI command to add the Composer repository to your composer.json file:

composer config repositories.nova '{"type": "composer", "url": "https://nova.laravel.com"}' --file composer.json

Next, you may add laravel/nova to your list of required packages in your composer.json file:

"require": {
    "php": "^8.0",
    "laravel/framework": "^9.0",
    "laravel/nova": "~4.0"
},

After your composer.json file has been updated, run the composer update command in your console terminal:

composer update --prefer-dist

When running composer update, you will be prompted to provide a username and password. You should use your Nova website email for the username and a license key (opens new window)should be used as the password. These credentials will authenticate your Composer session as having permission to download the Nova source code.

To avoid manually typing these credentials, you may create a Composer auth.json file (opens new window)while using your license key (opens new window)in place of your password:

composer config http-basic.nova.laravel.com your-nova-account-email@your-domain.com your-license-key

Finally, run the nova:install and migrate Artisan commands. The nova:install command will install Nova's service provider and public assets within your application:

php artisan nova:install

php artisan migrate

After running this command, verify that the App\Providers\NovaServiceProvider was added to the providers array in your app configuration file. If it wasn't, you should add it manually. Of course, if your application does not use the App namespace, you should update the provider class name as needed.

The default App\Nova\User Nova resource references the App\Models\User model. If you place your models in a different directory or namespace, you should adjust this value within the resource:

public static $model = 'App\\Models\\User';

If you don't have a Nova admin user yet in your users table, you can add one by running the nova:user Artisan command and following the prompts:

php artisan nova:user

That's it! Next, you may navigate to your application's /nova path in your browser and you should be greeted with the Nova dashboard which includes links to various parts of this documentation.

#Registering a Nova License Key and Production URL

Nova requires a license key a production URL to be used in production environments. Nova will check your license key and the current host against the values from the license details found in your Nova account.

You can generate license keys and register the production URL for your project inside the license's page on your Nova account at https://nova.laravel.com/licenses (opens new window):

Registering your production site

Wildcard subdomains

You can register a wildcard subdomain for your production URL for use in multi-tenant scenarios (e.g. *.laravel.com).

You can register your license key by setting the license_key option in your config/nova.php configuration file:

'license_key' => env('NOVA_LICENSE_KEY', ''),

Since Nova can be used in staging and local development environments, Nova will not check your license key when used on localhost or these local TLDs specified in IETF RFC 2606 (opens new window):

  • .test
  • .example
  • .invalid
  • .localhost
  • .local

Nova will also not check the current license key when the hostname contains commonly-used staging subdomains:

  • admin.
  • staging.
  • stage.
  • test.
  • testing.
  • dev.
  • development.

#Verifying Your Nova License Key Configuration

To verify everything has been configured correctly, you should run the following command:

php artisan nova:check-license

#Authenticating Nova in Continuous Integration (CI) Environments

It's not advised to store your Composer auth.json file inside your project's version control repository. However, there may be times you wish to download Nova inside a CI environment like CodeShip (opens new window). For instance, you may wish to run tests for any custom tools you create. To authenticate Nova in these situations, you can use Composer to set the configuration option inside your CI system's pipeline, injecting environment variables containing your Nova username and license key:

composer config http-basic.nova.laravel.com ${NOVA_USERNAME} ${NOVA_LICENSE_KEY}

#Authorizing Access To Nova

Within your app/Providers/NovaServiceProvider.php file, there is a gate method. This authorization gate controls access to Nova in non-local environments. By default, any user can access the Nova dashboard when the current application environment is local. You are free to modify this gate as needed to restrict access to your Nova installation:

/**
 * Register the Nova gate.
 *
 * This gate determines who can access Nova in non-local environments.
 *
 * @return void
 */
protected function gate()
{
    Gate::define('viewNova', function ($user) {
        return in_array($user->email, [
            'taylor@laravel.com',
        ]);
    });
}

#Customization

#Branding

Although Nova's interface is intended to be an isolated part of your application that is managed by Nova, you can make some small customizations to the branding logo and color used by Nova to make the interface more cohesive with the rest of your application.

Branding

To customize the logo used at the top left of the Nova interface, you may specify a configuration value for the brand.logo configuration item within your application's config/nova.php configuration file. This configuration value should contain an absolute path to the SVG file of the logo you would like to use:

'brand' => [
    'logo' => resource_path('/img/example-logo.svg'),

    // ...
],

SVG Sizing

You may need to adjust the size and width of your SVG logo by modifying its width in the SVG file itself.

#Brand Color

To customize the color used as the "primary" color within the Nova interface, you may specify a value for the brand.colors configuration item within your application's config/nova.php configuration file. This color will be used as the primary button color as well as the color of various emphasized items throughout the Nova interface. This configuration value should be a valid RGB value:

'brand' => [
    // ...

    'colors' => [
        "400" => "24, 182, 155, 0.5",
        "500" => "24, 182, 155",
        "600" => "24, 182, 155, 0.75",
    ]
],

There are times you may wish to customize Nova's default footer text to include relevant information for your users, such as your application version, IP addresses, or other information. You can do this by setting Nova's footer within App\Providers\NovaServiceProvider:

use Laravel\Nova\Nova;
use Illuminate\Support\Facades\Blade;

/**
 * Boot any application services.
 *
 * @return void
 */
public function boot()
{
    parent::boot();

    Nova::footer(function ($request) {
        return Blade::render('
            @env(\'prod\')
                This is production!
            @endenv
        ');
    });
}

#Customizing Nova's Authentication Guard

Nova uses the default authentication guard defined in your auth configuration file. If you would like to customize this guard, you may set the guard value within Nova's configuration file:

'guard' => env('NOVA_GUARD', null),

#Customizing Nova's Password Reset Functionality

Nova uses the default password reset broker defined in your auth configuration file. If you would like to customize this broker, you may set the passwords value within Nova's configuration file:

'passwords' => env('NOVA_PASSWORDS', null),

#Customizing Nova's Storage Disk Driver

Nova uses the default storage disk driver defined in your filesystems configuration file. If you would like to customize this disk, you may set the storage_disk value within Nova's configuration file:

'storage_disk' => env('NOVA_STORAGE_DISK', 'public'),

#Customizing Nova's Initial Path

When visiting Nova, the Main dashboard is typically loaded by default. However, you are free to define a different initial path that should be loaded using Nova's initialPath method. Typically, this method may be invoked from the register method of your application's App\Providers\NovaServiceProvider service provider:

use Laravel\Nova\Nova;

/**
 * Register any application services.
 *
 * @return void
 */
public function register()
{
    Nova::initialPath('/resources/users');

    // ...
}

#Enabling RTL Support

If you wish to display Nova's content "right-to-left" (RTL), you can enable this behavior by calling the enableRTL method from your App\Providers\NovaServiceProvider service provider:

use Laravel\Nova\Nova;

/**
 * Boot any application services.
 *
 * @return void
 */
public function boot()
{
    parent::boot();

    Nova::enableRTL();
}

The enableRTL method also accept a closure that allows you to enable RTL support for specific users or in other custom scenarios:

use Illuminate\Http\Request;
use Laravel\Nova\Nova;

Nova::enableRTL(fn (Request $request) => $request->user()->wantsRTL());

#Disabling Nova's Theme Switcher

If you wish to completely hide Nova's light/dark mode switcher and instead have Nova honor the system preference only, you can call the withoutThemeSwitcher method from your App/Providers/NovaServiceProvider:

use Laravel\Nova\Nova;

/**
 * Boot any application services.
 *
 * @return void
 */
public function boot()
{
    parent::boot();

    Nova::withoutThemeSwitcher();
}

#Error Reporting

Nova uses its own internal exception handler instead of using the default App\Exceptions\ExceptionHandler. If you need to integrate third-party error reporting tools with your Nova installation, you should use the Nova::report method. Typically, this method should be invoked from the register method of your application's App\Providers\NovaServiceProvider class:

use Laravel\Nova\Nova;

Nova::report(function ($exception) {
    if (app()->bound('sentry')) {
        app('sentry')->captureException($exception);
    }
});

#Updating Nova

To update your Nova installation, you may run the composer update command:

composer update

#Updating Nova's Assets

After updating to a new Nova release, you should be sure to update Nova's JavaScript and CSS assets using the nova:publish Artisan command and clear any cached views using the view:clear Artisan command. This will ensure the newly-updated Nova version is using the latest versions of Nova's assets and views:

php artisan nova:publish
php artisan view:clear

The nova:publish command will re-publish Nova's public assets, configuration, views, and language files. This command will not overwrite any existing configuration, views, or language files. If you would like the command to overwrite existing files, you may use the --force flag when executing the command:

php artisan nova:publish --force

#Keeping Nova's Assets Updated

To ensure Nova's assets are updated when a new version is downloaded, you may add a Composer hook inside your project's composer.json file to automatically publish Nova's latest assets:

"scripts": {
    "post-update-cmd": [
        "@php artisan nova:publish"
    ]
}

#Code Distribution

Nova's license does not allow the public distribution of its source code. So, you may not build an application using Nova and distribute that application public via open source repository hosting platforms or any other code distribution platform.

If you would like to develop a third party package that augments Nova's functionality, you are free to do so. However, you may not distribute the Nova source code along with your package.

Bug Reports

If you discover a bug in Laravel Nova, please open an issue on the Nova issues GitHub repository (opens new window).

#Support Questions

Laravel Nova's GitHub issue trackers are not intended to provide Nova help or support. Instead, use one of the following channels:

#Security Vulnerabilities

If you discover a security vulnerability within Laravel Nova, please send an email to nova@laravel.com. All security vulnerabilities will be promptly addressed.

Code of Conduct

The Laravel code of conduct is derived from the Ruby code of conduct. Any violations of the code of conduct may be reported to Taylor Otwell (taylor@laravel.com):

  • Participants will be tolerant of opposing views.
  • Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
  • When interpreting the words and actions of others, participants should always assume good intentions.
  • Behavior which can be reasonably considered harassment will not be tolerated.

Introduction

Laravel Nova is a beautiful administration dashboard for Laravel applications. Of course, the primary feature of Nova is the ability to administer your underlying database records using Eloquent. Nova accomplishes this by allowing you to define a Nova "resource" that corresponds to each Eloquent model in your application.

#Defining Resources

By default, Nova resources are stored in the app/Nova directory of your application. You may generate a new resource using the nova:resource Artisan command:

php artisan nova:resource Post

The most basic and fundamental property of a resource is its model property. This property tells Nova which Eloquent model the resource corresponds to:

/**
 * The model the resource corresponds to.
 *
 * @var string
 */
public static $model = 'App\Models\Post';

Freshly created Nova resources only contain an ID field definition. Don't worry, we'll add more fields to our resource soon.

Reserved Resource Names

Nova contains a few reserved words which may not be used for resource names:

  • Card
  • Dashboard
  • Field
  • Impersonate
  • Metric
  • Resource
  • Search
  • Script
  • Style
  • Tool

#Registering Resources

Automatic Registration

By default, all resources within the app/Nova directory will automatically be registered with Nova. You are not required to manually register them.

Before resources are available within your Nova dashboard, they must first be registered with Nova. Resources are typically registered in your application's app/Providers/NovaServiceProvider.php file. This file contains various configuration and bootstrapping code related to your Nova installation.

As mentioned above, you are not required to manually register your resources; however, if you choose to do so, you may do so by overriding the resources method of your NovaServiceProvider.

There are two approaches to manually registering resources. You may use the resourcesIn method to instruct Nova to register all Nova resources within a given directory. Alternatively, you may use the resources method to manually register individual resources:

use App\Nova\User;
use App\Nova\Post;

/**
 * Register the application's Nova resources.
 *
 * @return void
 */
protected function resources()
{
    Nova::resourcesIn(app_path('Nova'));

    Nova::resources([
        User::class,
        Post::class,
    ]);
}

Once your resources are registered with Nova, they will be available in the Nova sidebar:

Nova Dashboard

If you do not want a resource to appear in the sidebar, you may override the displayInNavigation property of your resource class:

/**
 * Indicates if the resource should be displayed in the sidebar.
 *
 * @var bool
 */
public static $displayInNavigation = false;

#Customizing Resource Menus

You can customize the resource's menu by defining a menu method on your resource class:

use Illuminate\Http\Request;

/**
 * Get the menu that should represent the resource.
 *
 * @return \Laravel\Nova\Menu\MenuItem
 */
public function menu(Request $request)
{
    return parent::menu($request)->withBadge(function () {
        return static::$model::count();
    });
}

Please refer to the documentation on menu customization for more information.

#Grouping Resources

If you would like to separate resources into different sidebar groups, you may override the group property of your resource class:

/**
 * The logical group associated with the resource.
 *
 * @var string
 */
public static $group = 'Admin';

#Resource Table Style Customization

Nova supports a few visual customization options for your resources.

#Table Styles

Sometimes it's convenient to show more data on your resource index tables. To accomplish this, you can use the "tight" table style option designed to increase the visual density of your table rows. To accomplish this, override the static $tableStyle property or the static tableStyle method on your resource class:

/**
 * The visual style used for the table. Available options are 'tight' and 'default'.
 *
 * @var string
 */
public static $tableStyle = 'tight';

This will display your table rows with less visual height, enabling more data to be shown:

Tight Table Style

#Column Borders

You can instruct Nova to display column borders by overriding the static $showColumnBorders property or the static showColumnBorders method on your resource class:

/**
 * Whether to show borders for each column on the X-axis.
 *
 * @var bool
 */
public static $showColumnBorders = true;

Setting this property to true will instruct Nova to display the table with borders on every table item:

Table Column Borders

#Eager Loading

If you routinely need to access a resource's relationships within your fields, resource title, or resource subtitle, it may be a good idea to add the relationship to the with property of your resource. This property instructs Nova to always eager load the listed relationships when retrieving the resource.

For example, if you access a Post resource's user relationship within the Post resource's subtitle method, you should add the user relationship to the Post resource's with property:

/**
 * The relationships that should be eager loaded on index queries.
 *
 * @var array
 */
public static $with = ['user'];

#Resource Replication

Sometimes, you may want to create a new resource while using all of the data from an existing resource as a starting point. Nova's resource replication feature does just that. After clicking the replicate button, you'll be whisked away to a resource creation form with all of the replicated resource's data hydrated into the form and ready for tweaking:

Resource Replication

To customize the replication model, you can override the replicate method on the resource class:

/**
 * Return a replicated resource.
 *
 * @return static
 *
 * @throws \InvalidArgumentException
 */
public function replicate()
{
    return tap(parent::replicate(), function ($resource) {
        $model = $resource->model();

        $model->name = 'Duplicate of '.$model->name;
    });
}

#Resource Events

All Nova operations use the typical savedeleteforceDeleterestore Eloquent methods you are familiar with. Therefore, it is easy to listen for model events triggered by Nova and react to them. The easiest approach is to simply attach a Laravel model observer (opens new window)to a model:

namespace App\Providers;

use App\Models\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        User::observe(UserObserver::class);
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

If you would like to attach an observer whose methods are invoked only during Nova related HTTP requests, you may register observers using the make method provided by the Laravel\Nova\Observable class. Typically, this should be done within your application's NovaServiceProvider:

use App\Models\User;
use Laravel\Nova\Observable;
use App\Observers\UserObserver;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    parent::boot();

    Observable::make(User::class, UserObserver::class);
}

Alternatively, you can determine if the current HTTP request is serving a Nova related request within the Observer itself using Nova's whenServing method:

namespace App\Observers;

use App\Models\User;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Nova;

class UserObserver
{
    /**
     * Handle the User "created" event.
     *
     * @param  \App\Models\User  $user
     * @return void
     */
    public function created(User $user)
    {
        Nova::whenServing(function (NovaRequest $request) use ($user) {
            // Only invoked during Nova requests...
        });

        // Always invoked...
    }
}

#Resource Hooks

Nova also allows you to define the following static methods on a resource to serve as hooks that are only invoked when the corresponding resource action is executed from within Laravel Nova:

  • afterCreate
  • afterUpdate
  • afterDelete
  • afterForceDelete

For example, you may want to send an email verification notification after a user has been created within Nova:

use App\Models\User;
use App\Nova\Resource;
use Illuminate\Database\Eloquent\Model;
use Laravel\Nova\Http\Requests\NovaRequest;

class User extends Resource
{
    /**
     * Register a callback to be called after the resource is created.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public static function afterCreate(NovaRequest $request, Model $model)
    {
        $model->sendEmailVerificationNotification();
    }
}

#Preventing Conflicts

If a model has been updated since it was last retrieved by Nova, Nova will automatically respond with a 409 Conflict HTTP status code and display an error message to prevent unintentional model changes. This may occur if another user updates the model after you have opened the "Edit" page on the resource. This feature is also known as the Nova "Traffic Cop".

#Disabling Traffic Cop

If you are not concerned with preventing conflicts, you can disable the Traffic Cop feature by setting the trafficCop property to false on a given resource class:

/**
 * Indicates whether Nova should check for modifications between viewing and updating a resource.
 *
 * @var bool
 */
public static $trafficCop = false;

You may also override the trafficCop method on the resource if you have more intense customization needs in order to determine if this feature should be enabled:

/**
 * Indicates whether Nova should check for modifications between viewing and updating a resource.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return  bool
*/
public static function trafficCop(Request $request)
{
    return static::$trafficCop;
}

Time Synchronization

If you are experiencing issues with traffic cop you should ensure that your system time is correctly synchronized using NTP.

#Resource Polling

Nova can automatically fetch the latest records for a resource at a specified interval. To enable polling, override the polling property of your Resource class:

/**
 * Indicates whether the resource should automatically poll for new resources.
 *
 * @var bool
 */
public static $polling = true;

To customize the polling interval, you may override the pollingInterval property on your resource class with the number of seconds Nova should wait before fetching new resource records:

/**
 * The interval at which Nova should poll for new resources.
 *
 * @var int
 */
public static $pollingInterval = 5;

#Toggling Resource Polling

By default, when resource polling is enabled, there is no way to disable it once the page loads. You can instruct Nova to display a start / stop toggle button for resource polling by setting the showPollingToggle property on your resource class to true:

/**
 * Indicates whether to show the polling toggle button inside Nova.
 *
 * @var bool
 */
public static $showPollingToggle = true;

Nova will then display a clickable button that you may use to enable / disable polling for the resource:

Nova Resource Polling Toggle Button

#Redirection

Nova allows you to easily customize where a user is redirected after performing resource actions such as creating or updating a resource:

Behind the scenes, Nova's redirect features use Inertia.js's visit method. Because of this, redirection is limited to paths within Laravel Nova. You may invoke the URL::remote method to redirect to an external URL:

use Laravel\Nova\URL;

return URL::remote('https://nova.laravel.com');

#After Creating Redirection

You may customize where a user is redirected after creating a resource using by overriding your resource's redirectAfterCreate method:

/**
 * Return the location to redirect the user after creation.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @param  \Laravel\Nova\Resource  $resource
 * @return \Laravel\Nova\URL|string
 */
public static function redirectAfterCreate(NovaRequest $request, $resource)
{
    return '/resources/'.static::uriKey().'/'.$resource->getKey();
}

#After Updating Redirection

You may customize where a user is redirected after updating a resource using by overriding your resource's redirectAfterUpdate method:

/**
 * Return the location to redirect the user after update.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @param  \Laravel\Nova\Resource  $resource
 * @return \Laravel\Nova\URL|string
 */
public static function redirectAfterUpdate(NovaRequest $request, $resource)
{
    return '/resources/'.static::uriKey().'/'.$resource->getKey();
}

#After Deletion Redirection

You may customize where a user is redirected after deleting a resource using by overriding your resource's redirectAfterDelete method:

/**
 * Return the location to redirect the user after deletion.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return \Laravel\Nova\URL|string|null
 */
public static function redirectAfterDelete(NovaRequest $request)
{
    return null;
}

#Pagination

Nova has the ability to show pagination links for your Resource listings. You can choose between three different styles: "simple", "load-more", and "links", depending on your application's needs:

Simple Pagination

Load-more Pagination

Links Pagination

By default, Nova Resources are displayed using the "simple" style. However, you may customize this to use either the load-more or links styles by changing the value of the pagination configuration option within your application's config/nova.php configuration file:

'pagination' => 'links',

#Customizing Pagination

If you would like to customize the selectable maximum result amounts shown on each resource's "per page" filter menu, you can do so by customizing the resource's perPageOptions property:

/**
 * The pagination per-page options configured for this resource.
 *
 * @return array
 */
public static $perPageOptions = [50, 100, 150];

Alternatively, you can override the perPageOptions method on your application's base Resource class, which is created when you install Nova:

/**
 * The pagination per-page options configured for this resource.
 *
 * @return array
 */
public static function perPageOptions()
{
    return [50, 100, 150];
}

Customizing perPageOptions & Resource Fetching

Changing the value of perPageOptions on your Resource will cause Nova to fetch the number of resources equal to the first value in the perPageOptions array.

#CSV Export

Occasionally you may need to export a group of resource records as a CSV file so that you can interact with the data in a spreadsheet application or import the data into another system. Thankfully, Nova includes built-in support for exporting resource data.

To get started, add the Laravel\Nova\Actions\ExportAsCsv action to your Nova resource:

use Laravel\Nova\Actions\ExportAsCsv;
use Laravel\Nova\Http\Requests\NovaRequest;

/**
 * Get the actions available for the resource.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return array
 */
public function actions(NovaRequest $request)
{
    return [
        ExportAsCsv::make(),
    ];
}

If you would like to allow the user to name the CSV file that is downloaded, you may invoke the nameable method when registering the action:

return [
    ExportAsCsv::make()->nameable(),
];

If you would like to customize and format the fields that are included in the generated CSV, you may invoke the withFormat method when registering the action:

return [
    ExportAsCsv::make()->withFormat(function ($model) {
        return [
            'ID' => $model->getKey(),
            'Name' => $model->name,
            'Email Address' => $model->email,
        ];
    }),
];

#Resource Index Search Debounce

You may wish to customize the search debounce timing of an individual resource's index listing. For example, the queries executed to retrieve some resources may take longer than others. You can customize an individual resource's search debounce by setting the debounce property on the resource class:

/**
 * The debounce amount (in seconds) to use when searching this resource.
 *
 * @var float
 */
public static $debounce = 0.5; // 0.5 seconds

#Keyboard Shortcuts

You may press the C key on a resource index to navigate to the "Create Resource" page. On the resource detail page, the E key may be used to navigate to the "Update Resource" page.

Defining Fields

Each Nova resource contains a fields method. This method returns an array of fields, which generally extend the Laravel\Nova\Fields\Field class. Nova ships with a variety of fields out of the box, including fields for text inputs, booleans, dates, file uploads, Markdown, and more.

To add a field to a resource, you may simply add it to the resource's fields method. Typically, fields may be created using their static make method. This method accepts several arguments; however, you usually only need to pass the "human readable" name of the field. Nova will automatically "snake case" this string to determine the underlying database column:

use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Text;

/**
 * Get the fields displayed by the resource.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return array
 */
public function fields(NovaRequest $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Name')->sortable(),
    ];
}

#Field Column Conventions

As noted above, Nova will "snake case" the displayable name of the field to determine the underlying database column. However, if necessary, you may pass the column name as the second argument to the field's make method:

Text::make('Name', 'name_column'),

#Showing / Hiding Fields

Often, you will only want to display a field in certain situations. For example, there is typically no need to show a Password field on a resource index listing. Likewise, you may wish to only display a Created At field on the creation / update forms. Nova makes it a breeze to hide / show fields on certain pages.

The following methods may be used to show / hide fields based on the display context:

  • showOnIndex
  • showOnDetail
  • showOnCreating
  • showOnUpdating
  • showOnPreview
  • hideFromIndex
  • hideFromDetail
  • hideWhenCreating
  • hideWhenUpdating
  • onlyOnIndex
  • onlyOnDetail
  • onlyOnForms
  • exceptOnForms

You may chain any of these methods onto your field's definition in order to instruct Nova where the field should be displayed:

Text::make('Name')->hideFromIndex(),

Alternatively, you may pass a callback to the following methods.

  • showOnIndex
  • showOnDetail
  • showOnCreating
  • showOnUpdating
  • hideFromIndex
  • hideFromDetail
  • hideWhenCreating
  • hideWhenUpdating

For show* methods, the field will be displayed if the given callback returns true:

Text::make('Name')->showOnIndex(function () {
    return $this->name === 'Taylor Otwell';
}),

For hide* methods, the field will be hidden if the given callback returns true:

Text::make('Name')->hideFromIndex(function () {
    return $this->name === 'Taylor Otwell';
}),

#Resource Preview Modal

You may also define which fields should be included in the resource's "preview" modal. This modal can be displayed for a given resource by the user when viewing the resource's index:

Text::make('Title')->showOnPreview(),

Markdown::make('Content')->showOnPreview(),

Resource Preview

#Dynamic Field Methods

If your application requires it, you may specify a separate list of fields for specific display contexts. For example, imagine you have a resource with the following list of fields:

/**
 * Get the fields displayed by the resource.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return array
 */
public function fields(NovaRequest $request)
{
    return [
        Text::make('First Name'),
        Text::make('Last Name'),
        Text::make('Job Title'),
    ];
}

On your detail page, you may wish to show a combined name via a computed field, followed by the job title. In order to do this, you could add a fieldsForDetail method to the resource class which returns a separate list of fields that should only be displayed on the resource's detail page:

/**
 * Get the fields displayed by the resource on detail page.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return array
 */
public function fieldsForDetail(NovaRequest $request)
{
    return [
        Text::make('Name', function () {
            return sprintf('%s %s', $this->first_name, $this->last_name);
        }),

        Text::make('Job Title'),
    ];
}

The available methods that may be defined for individual display contexts are:

  • fieldsForIndex
  • fieldsForDetail
  • fieldsForInlineCreate
  • fieldsForCreate
  • fieldsForUpdate

Dynamic Field Methods Precedence ::

The fieldsForIndexfieldsForDetailfieldsForInlineCreatefieldsForCreate, and fieldsForUpdate methods always take precedence over the fields method.

#Default Values

There are times you may wish to provide a default value to your fields. Nova offers this functionality via the default method, which accepts a value or callback. This value will be used as the field's default input value on the resource's creation view:

BelongsTo::make('Name')->default($request->user()->getKey()),

Text::make('Uuid')->default(function ($request) {
    return Str::orderedUuid();
}),

#Field Placeholder Text

By default, the placeholder text of a field will be it's name. You can override the placeholder text of a field that supports placeholders by using the placeholder method:

Text::make('Name')->placeholder('My New Post'),

#Field Hydration

On every create or update request that Nova receives for a given resource, each field's corresponding model attribute will automatically be filled before the model is persisted to the database. If necessary, you may customize the hydration behavior of a given field using the fillUsing method:

Text::make('Name', 'name')
    ->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
        $model->{$attribute} = Str::title($request->input($attribute));
    }),

#Field Panels

If your resource contains many fields, your resource "detail" page can become crowded. For that reason, you may choose to break up groups of fields into their own "panels":

Field Panel Example

You may accomplish this by creating a new Panel instance within the fields method of a resource. Each panel requires a name and an array of fields that belong to that panel:

use Laravel\Nova\Panel;

/**
 * Get the fields displayed by the resource.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return array
 */
public function fields(NovaRequest $request)
{
    return [
        ID::make()->sortable(),

        new Panel('Address Information', $this->addressFields()),
    ];
}

/**
 * Get the address fields for the resource.
 *
 * @return array
 */
protected function addressFields()
{
    return [
        Text::make('Address', 'address_line_1')->hideFromIndex(),
        Text::make('Address Line 2')->hideFromIndex(),
        Text::make('City')->hideFromIndex(),
        Text::make('State')->hideFromIndex(),
        Text::make('Postal Code')->hideFromIndex(),
        Country::make('Country')->hideFromIndex(),
    ];
}

You may limit the amount of fields shown in a panel by using the limit method:

(new Panel('Profile', [
    Text::make('Full Name'),
    Date::make('Date of Birth'),
    Text::make('Place of Birth'),
]))->limit(1),

Panels with a defined field limit will display a Show All Fields button in order to allow the user to view all of the defined fields when needed.

#Sortable Fields

When attaching a field to a resource, you may use the sortable method to indicate that the resource index may be sorted by the given field:

Text::make('Name', 'name_column')->sortable(),

#Field Types

Relationship Fields

This portion of the documentation only discusses non-relationship fields. To learn more about relationship fields, check out their documentation.

Nova ships with a variety of field types. So, let's explore all of the available types and their options:

#Avatar Field

The Avatar field extends the Image field and accepts the same options and configuration:

use Laravel\Nova\Fields\Avatar;

Avatar::make('Avatar'),

If a resource contains an Avatar field, that field will be displayed next to the resource's title when the resource is displayed in search results:

Avatar Search Results

You may use the squared method to display the image's thumbnail with squared edges. Additionally, you may use the rounded method to display its thumbnails with fully-rounded edges:

Avatar::make('Avatar')->squared(),

#Badge Field

The Badge field can be used to display the status of a Resource in the index and detail views:

use Laravel\Nova\Fields\Badge;

Badge::make('Status', function () {
    return User::statuses[$this->status];
}),

By default, the Badge field supports four variations: infosuccessdanger, and warning. You may define your possible field values and their associated badge types using the map method:

Badge::make('Status')->map([
    'draft' => 'danger',
    'published' => 'success',
]),

Alternatively, you may use the types method to completely replace the built-in badge types and their associated CSS classes. The CSS classes may be provided as a string or an array:

Badge::make('Status')->types([
    'draft' => 'font-medium text-gray-600',
    'published' => ['font-bold', 'text-green-600'],
]),

If you only wish to supplement the built-in badge types instead of overwriting all of them, you may use the addTypes method:

Badge::make('Status')->addTypes([
    'draft' => 'custom classes',
]),

Editing Badge Types

By default the Badge field is not shown on a resource's edit or update pages. If you wish to modify the underlying value represented by the Badge field on your edit forms, define another field in combination with the onlyOnForms field option.

If you'd like to display your badge with an associated icon, you can use the withIcons method to direct Nova to display an icon:

Badge::make('Status')->map([
    'draft' => 'danger',
    'published' => 'success',
])->withIcons(),

If you'd like to customize the icons used when display Badge fields you can use the icons method:

Badge::make('Status')->map([
    'draft' => 'danger',
    'published' => 'success',
])->icons([
    'danger' => 'exclamation-circle',
    'success' => 'check-circle',
]),

#Boolean Field

The Boolean field may be used to represent a boolean / "tiny integer" column in your database. For example, assuming your database has a boolean column named active, you may attach a Boolean field to your resource like so:

use Laravel\Nova\Fields\Boolean;

Boolean::make('Active'),

#Customizing True / False Values

If you are using values other than truefalse1, or 0 to represent "true" and "false", you may instruct Nova to use the custom values recognized by your application. To accomplish this, chain the trueValue and falseValue methods onto your field's definition:

Boolean::make('Active')
    ->trueValue('On')
    ->falseValue('Off'),

#Boolean Group Field

The BooleanGroup field may be used to group a set of Boolean checkboxes, which are then stored as JSON key-values in the database column they represent. You may create a BooleanGroup field by providing a set of keys and labels for each option:

use Laravel\Nova\Fields\BooleanGroup;

BooleanGroup::make('Permissions')->options([
    'create' => 'Create',
    'read' => 'Read',
    'update' => 'Update',
    'delete' => 'Delete',
]),

The user will be presented with a grouped set of checkboxes which, when saved, will be converted to JSON format:

{
  "create": true,
  "read": false,
  "update": false,
  "delete": false
}

Before using this field type, you should ensure that the underlying Eloquent attribute is configured to cast to an array (or equivalent) within your Eloquent model class:

protected $casts = [
    'permissions' => 'array'
];

Sometimes, you may wish to exclude values that are true or false from display to avoid cluttering the representation of the field. You may accomplish this by invoking the hideFalseValues or hideTrueValues methods on the field definition:

BooleanGroup::make('Permissions')->options([
    'create' => 'Create',
    'read' => 'Read',
    'update' => 'Update',
    'delete' => 'Delete',
])->hideFalseValues(),

BooleanGroup::make('Permissions')->options([
    'create' => 'Create',
    'read' => 'Read',
    'update' => 'Update',
    'delete' => 'Delete',
])->hideTrueValues(),

If the underlying field is empty, Nova will display "No Data". You may customize this text using the noValueText method:

BooleanGroup::make('Permissions')->options([
    'create' => 'Create',
    'read' => 'Read',
    'update' => 'Update',
    'delete' => 'Delete',
])->noValueText('No permissions selected.'),

#Code Field

The Code fields provides a beautiful code editor within your Nova administration panel. Generally, code fields should be attached to TEXT database columns:

use Laravel\Nova\Fields\Code;

Code::make('Snippet'),

You may also attach Code fields to JSON database columns. By default, the field will display the value as a JSON string. You may cast the underlying Eloquent attribute to arraycollectionobject, or json based on your application's needs:

use Laravel\Nova\Fields\Code;

Code::make('Options')->json(),

Code Fields On The Index

By default, Nova will never display a Code field on a resource index listing.

#Editing JSON

If you intend to use a given Code field instance to only edit JSON, you may chain the json method onto your field definition:

Code::make('Options')->json(),

Code Field JSON Validation

Nova does not automatically apply the json validation rule to Code fields. This rule must be manually specified during validation if you wish for it to be applied.

#Syntax Highlighting

You may customize the language syntax highlighting of the Code field using the language method:

Code::make('Snippet')->language('php'),

The Code field's currently supported languages are:

  • dockerfile
  • htmlmixed
  • javascript
  • markdown
  • nginx
  • php
  • ruby
  • sass
  • shell
  • sql
  • twig
  • vim
  • vue
  • xml
  • yaml-frontmatter
  • yaml

#Color Field

The Color field generate a color picker using the HTML5 color input element:

use Laravel\Nova\Fields\Color;

Color::make('Color', 'label_color'),

#Country Field

The Country field generates a Select field containing a list of the world's countries. The field will store the country's corresponding two-letter code:

use Laravel\Nova\Fields\Country;

Country::make('Country', 'country_code'),

#Currency Field

The Currency field generates a Number field that is automatically formatted using the brick/money PHP package. Nova will use USD as the default currency; however, this can be changed by modifying the nova.currency configuration value:

use Laravel\Nova\Fields\Currency;

Currency::make('Price'),

You may override the currency on a per-field basis using the currency method:

Currency::make('Price')->currency('EUR'),

Prerequisites

The ext-intl PHP extension is required to display formatted currency. Or, you may install the symfony/polyfill-intl-icu Composer package which offers support for the "en" locale.

You may use the minmax, and step methods to set their corresponding attributes on the generated input control:

Currency::make('price')->min(1)->max(1000)->step(0.01),

Currency Step Limitation

If you plan to customize the currency "step" amount using the step method, you should ensure you always call the step method after the currencyasMinorUnits, and asMajorUnits methods. Calling these methods after the step method will override the step method's behavior.

The field's locale will respect the value in your application's app.locale configuration value. You can override this behavior by providing a locale code to the locale method:

Currency::make('Price')->locale('fr'),

#Date Field

The Date field may be used to store a date value (without time). For more information about dates and timezones within Nova, check out the additional date / timezone documentation:

use Laravel\Nova\Fields\Date;

Date::make('Birthday'),

#DateTime Field

The DateTime field may be used to store a date-time value. For more information about dates and timezones within Nova, check out the additional date / timezone documentation:

use Laravel\Nova\Fields\DateTime;

DateTime::make('Updated At')->hideFromIndex(),

#Email Field

The Email field may be used to display a column with a mailto: link on the index and detail views:

use Laravel\Nova\Fields\Email;

Email::make(),

Email::make('Customer Email', 'customer_email'),

#File Field

To learn more about defining file fields and handling uploads, please refer to the comprehensive file field documentation.

use Laravel\Nova\Fields\File;

File::make('Attachment'),

#Gravatar Field

The Gravatar field does not correspond to any column in your application's database. Instead, it will display the "Gravatar" image of the model it is associated with.

By default, the Gravatar URL will be generated based on the value of the model's email column. However, if your user's email addresses are not stored in the email column, you may pass a custom column name to the field's make method:

use Laravel\Nova\Fields\Gravatar;

// Using the "email" column...
Gravatar::make(),

// Using the "email_address" column...
Gravatar::make('Avatar', 'email_address'),

You may use the squared method to display the image's thumbnail with squared edges. Additionally, you may use the rounded method to display the images with fully-rounded edges:

Gravatar::make('Avatar', 'email_address')->squared(),

#Heading Field

The Heading field does not correspond to any column in your application's database. It is used to display a banner across your forms and can function as a separator for long lists of fields:

Heading Field

use Laravel\Nova\Fields\Heading;

Heading::make('Meta'),

If you need to render HTML content within the Heading field, you may invoke the asHtml method when defining the field:

Heading::make('<p class="text-danger">* All fields are required.</p>')->asHtml(),

Headings & The Index Page

Heading fields are automatically hidden from the resource index page.

#Hidden Field

The Hidden field may be used to pass any value that doesn't need to be changed by the user but is required for saving the resource:

Hidden::make('Slug'),

Hidden::make('Slug')->default(Str::random(64)),

Combined with default valuesHidden fields are useful for passing things like related IDs to your forms:

Hidden::make('User', 'user_id')->default(function ($request) {
    return $request->user()->id;
}),

#ID Field

The ID field represents the primary key of your resource's database table. Typically, each Nova resource you define should contain an ID field. By default, the ID field assumes the underlying database column is named id; however, you may pass the column name as the second argument to the make method if necessary:

use Laravel\Nova\Fields\ID;

ID::make(),

ID::make('ID', 'id_column'),

If your application contains very large integer IDs, you may need to use the asBigInt method in order for the Nova client to correctly render the integer:

ID::make()->asBigInt(),

#Image Field

The Image field extends the File field and accepts the same options and configurations. The Image field, unlike the File field, will display a thumbnail preview of the underlying image when viewing the resource:

use Laravel\Nova\Fields\Image;

Image::make('Photo'),

By default, the Image field allows the user to download the linked file. To disable downloads, you may use the disableDownload method on the field definition:

Image::make('Photo')->disableDownload(),

You may use the squared method to display the image's thumbnail with squared edges. Additionally, you may use the rounded method to display its thumbnails with fully-rounded edges.

File Fields

To learn more about defining file fields and handling uploads, check out the comprehensive file field documentation.

#KeyValue Field

The KeyValue field provides a convenient interface to edit flat, key-value data stored inside JSON column types. For example, you might store profile information inside a JSON column type (opens new window)named meta:

use Laravel\Nova\Fields\KeyValue;

KeyValue::make('Meta')->rules('json'),

Given the field definition above, the following interface would be rendered by Nova:

Key/Value Field

#Customizing KeyValue Labels

You can customize the text values used in the component by calling the keyLabelvalueLabel, and actionText methods when defining the field. The actionText method customizes the "add row" button text:

KeyValue::make('Meta')
    ->keyLabel('Item')
    ->valueLabel('Label')
    ->actionText('Add Item'),

KeyValue Fields & The Index Page

By default, Nova will never display a KeyValue field on a resource index listing.

If you would like to disable the user's ability to edit the keys of the field, you may use the disableEditingKeys method to accomplish this. Disabling editing keys with the disableEditingKeys method will automatically disable adding rows as well:

KeyValue::make('Meta')->disableEditingKeys(),

You may also remove the user's ability to add new rows to the field by chaining the disableAddingRows method onto the field's definition:

KeyValue::make('Meta')->disableAddingRows(),

In addition, you may also wish to remove the user's ability to delete exisiting rows in the field. You may accomplish this by invoking the disableDeletingRows method when defining the field:

KeyValue::make('Meta')->disableDeletingRows(),

#Markdown Field

The Markdown field provides a WYSIWYG Markdown editor for its underlying Eloquent attribute. Typically, this field will correspond to a TEXT column in your database. The Markdown field will store the raw Markdown text within the associated database column:

use Laravel\Nova\Fields\Markdown;

Markdown::make('Biography'),

By default, Markdown fields will not display their content when viewing a resource's detail page. Instead, the content will be hidden behind a "Show Content" link that will reveal the field's content when clicked. You may specify that the Markdown field should always display its content by calling the alwaysShow method on the field itself:

Markdown::make('Biography')->alwaysShow(),

The Markdown field uses the markdown-it npm package to parse Markdown content. By default, it uses a parsing strategy similar to GitHub Flavoured Markdown, which does not allow HTML within the Markdown content. However, you can change the parsing strategy using the preset method. The currently supported presets are defaultcommonmark, and zero:

Markdown::make('Biography')->preset('commonmark'),

#MultiSelect Field

The MultiSelect field provides a Select field that allows multiple selection options. This field pairs nicely with model attributes that are cast to array or equivalent:

use Laravel\Nova\Fields\MultiSelect;

MultiSelect::make('Sizes')->options([
    'S' => 'Small',
    'M' => 'Medium',
    'L' => 'Large',
]),

On the resource index and detail pages, the MultiSelect field's "key" value will be displayed. If you would like to display the label values instead, you may invoke the displayUsingLabels method when defining the field:

MultiSelect::make('Size')->options([
    'S' => 'Small',
    'M' => 'Medium',
    'L' => 'Large',
])->displayUsingLabels(),

You may also display multi-select options in groups by providing an array structure that contains keys and label / group pairs:

MultiSelect::make('Sizes')->options([
    'MS' => ['label' => 'Small', 'group' => "Men's Sizes"],
    'MM' => ['label' => 'Medium', 'group' => "Men's Sizes"],
    'WS' => ['label' => 'Small', 'group' => "Women's Sizes"],
    'WM' => ['label' => 'Medium', 'group' => "Women's Sizes"],
])->displayUsingLabels(),

#Number Field

The Number field provides an input control with a type attribute of number:

use Laravel\Nova\Fields\Number;

Number::make('price'),

You may use the minmax, and step methods to set the corresponding HTML attributes on the generated input control:

Number::make('price')->min(1)->max(1000)->step(0.01),

#Password Field

The Password field provides an input control with a type attribute of password:

use Laravel\Nova\Fields\Password;

Password::make('Password'),

The Password field will automatically preserve the password that is currently stored in the database if the incoming password field is empty. Therefore, a typical password field definition might look like the following:

Password::make('Password')
    ->onlyOnForms()
    ->creationRules('required', Rules\Password::defaults())
    ->updateRules('nullable', Rules\Password::defaults()),

#Password Confirmation Field

The PasswordConfirmation field provides an input that can be used for confirming another Password field. This field will only be shown on forms and will not attempt to hydrate an underlying attribute on the Eloquent model:

PasswordConfirmation::make('Password Confirmation'),

When using this field, you should define the appropriate validation rules on the corresponding Password field:

Password::make('Password')
    ->onlyOnForms()
    ->creationRules('required', Rules\Password::defaults(), 'confirmed')
    ->updateRules('nullable', Rules\Password::defaults(), 'confirmed'),

PasswordConfirmation::make('Password Confirmation'),

#Select Field

The Select field may be used to generate a drop-down select menu. The Select menu's options may be defined using the options method:

use Laravel\Nova\Fields\Select;

Select::make('Size')->options([
    'S' => 'Small',
    'M' => 'Medium',
    'L' => 'Large',
]),

On the resource index and detail pages, the Select field's "key" value will be displayed. If you would like to display the labels instead, you may use the displayUsingLabels method:

Select::make('Size')->options([
    'S' => 'Small',
    'M' => 'Medium',
    'L' => 'Large',
])->displayUsingLabels(),

You may also display Select options in groups by providing an array structure that contains keys and label / group pairs:

Select::make('Size')->options([
    'MS' => ['label' => 'Small', 'group' => 'Men Sizes'],
    'MM' => ['label' => 'Medium', 'group' => 'Men Sizes'],
    'WS' => ['label' => 'Small', 'group' => 'Women Sizes'],
    'WM' => ['label' => 'Medium', 'group' => 'Women Sizes'],
])->displayUsingLabels(),

If you need more control over the generation of the Select field's options, you may provide a closure to the options method:

Select::make('Size')->options(function () {
    return array_filter([
        Size::SMALL => Size::MAX_SIZE === SIZE_SMALL ? 'Small' : null,
        Size::MEDIUM => Size::MAX_SIZE === SIZE_MEDIUM ? 'Medium' : null,
        Size::LARGE => Size::MAX_SIZE === SIZE_LARGE ? 'Large' : null,
    ]);
}),

#Searchable Select Fields

At times it's convenient to be able to search or filter the list of options available in a Select field. You can enable this by invoking the searchable method on the field:

Select::make('Size')->searchable()->options([
    'S' => 'Small',
    'M' => 'Medium',
    'L' => 'Large',
])->displayUsingLabels(),

After marking a select field as searchable, Nova will display an input field which allows you to filter the list of options based on its label:

Searchable Select Fields

#Slug Field

Sometimes you may need to generate a unique, human-readable identifier based on the contents of another field, such as when generating a "slug" for a blog post title. You can automatically generate these "slugs" using the Slug field:

Slug::make('Slug')->from('Title'),

By default, the field will convert a string like 'My Blog Post' to a slug like 'my-blog-post'. If you would like the field to use underscores instead of dashes, you may use the separator method to define your own custom "separator":

Slug::make('Slug')->from('Title')->separator('_'),

#Sparkline Field

The Sparkline field may be used to display a small line chart on a resource's index or detail page. The data provided to a Sparkline may be provided via an array, a callable (which returns an array), or an instance of a Trend metric class:

// Using an array...
Sparkline::make('Post Views')->data([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),

// Using a callable...
Sparkline::make('Post Views')->data(function () {
    return json_decode($this->views_data);
}),

#Using Trend Metrics

If the data needed by your Sparkline field requires complicated database queries to compute, you may wish to encapsulate the data retrieval within a trend metric which can then be provided to the Sparkline field:

Sparkline::make('Post Views')->data(new PostViewsOverTime($this->id)),

In the example above, we're providing the post's id to the metric's constructor. This value will become the resourceId property of the request that is available within the trend metric. For example, within the metric, we could access this post ID via $request->resourceId:

return $this->countByDays(
    $request,
    PostView::where('post_id', '=', $request->resourceId)
);

Default Ranges

When providing data to a Sparkline field via a trend metric, the Sparkline field will always use the first range defined in the ranges method of the metric.

#Customizing The Chart

If a bar chart better suits your data, you may invoke the asBarChart method when defining the field:

Sparkline::make('Post Views')
           ->data([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
           ->asBarChart(),

By default, a Sparkline will appear on a resource's detail page. You can customize the dimensions of the chart using the height and width methods:

Sparkline::make('Post Views')
           ->data([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
           ->height(200)
           ->width(600),

#Status Field

The Status field may be used to display a "progress state" column. Internally, Nova uses the Status field to indicate the current state (waiting, running, or finished) of queued actions. However, you are free to use this field for your own purposes as needed:

Status Field Example

The loadingWhen and failedWhen methods may be used to instruct the field which words indicate a "loading" state and which words indicate a "failed" state. In this example, we will indicate that database column values of waiting or running should display a "loading" indicator:

use Laravel\Nova\Fields\Status;

Status::make('Status')
    ->loadingWhen(['waiting', 'running'])
    ->failedWhen(['failed']),

#Stack Field

As your resource classes grow, you may find it useful to be able to group fields together to simplify your index and detail views. A Stack field allows you to display fields like BelongsToText, and others in a vertical orientation:

Stack::make('Details', [
    Text::make('Name'),
    Text::make('Slug')->resolveUsing(function () {
        return Str::slug(optional($this->resource)->name);
    }),
]),

Stack Field

Stack fields are not shown on forms, and are only intended for stacking lines of text on the index and detail resource views.

#Line Fields

To gain more control over how the individual fields in a Stack are displayed, you may use the Line field, which provides methods for controlling the display of the line's text. Line fields offer the following presentational methods:

  • asHeading
  • asSubTitle
  • asSmall
  • asBase

Line presentational methods

In addition to the Line field's presentational methods, you may also pass any additional Tailwind classes to the field to customize the appearance of the Line:

Stack::make('Details', [
    Line::make('Title')->extraClasses('italic font-medium text-80'),
]),

#Passing Closures to Line Fields

In addition to passing BelongsToText, and Line fields to the Stack field, you may also pass a closure. The result of the closure will automatically be converted to a Line instance:

Stack::make('Details', [
    Line::make('Name')->asHeading(),
    fn () => optional($this->resource)->position
]),

#Text Field

The Text field provides an input control with a type attribute of text:

use Laravel\Nova\Fields\Text;

Text::make('Name'),

Text fields may be further customized by setting any attribute on the field. This can be done by calling the withMeta method and providing an extraAttributes array containing key / value pairs of HTML attributes:

Text::make('Name')->withMeta([
    'extraAttributes' => [
        'placeholder' => 'David Hemphill',
    ],
]),

#Text Field Suggestions

To offer auto-complete suggestions when typing into the Text field, you may invoke the suggestions method when defining the field. The suggestions method should return an array of suggestions:

Text::make('Name')->required()
    ->suggestions([
        'David Hemphill',
        'Taylor Otwell',
        'James Brooks',
    ]),

Field Suggestions

To format a Text field as a link, you may invoke the asHtml method when defining the field:

Text::make('Twitter Profile', function () {
    $username = $this->twitterUsername;

    return "<a href='https://twitter.com/{$username}'>@{$username}</a>";
})->asHtml(),

#Copying Text Field Values to the Clipboard

Sometimes you may wish to copy the value of a field into the system clipboard for pasting elsewhere. You can enable this on the detail view for a resource by calling the copyable method on the Text field:

Text::make('Twitter Profile')->copyable(),

#Textarea Field

The Textarea field provides a textarea control:

use Laravel\Nova\Fields\Textarea;

Textarea::make('Biography'),

By default, Textarea fields will not display their content when viewing a resource's detail page. Instead, the contents of the field will be hidden behind a "Show Content" link, which will reveal the content when clicked. However, if you would like, you may specify that the Textarea field should always display its content by invoking the alwaysShow method on the field:

Textarea::make('Biography')->alwaysShow(),

You may specify the Textarea height by invoking the rows method on the field:

Textarea::make('Excerpt')->rows(3),

Textarea fields may be further customized by setting any attribute on the field. This can be done by calling the withMeta method and providing an extraAttributes array containing key / value pairs of HTML attributes:

Textarea::make('Excerpt')->withMeta(['extraAttributes' => [
    'placeholder' => 'Make it less than 50 characters']
]),

#Timezone Field

The Timezone field generates a Select field containing a list of the world's timezones:

use Laravel\Nova\Fields\Timezone;

Timezone::make('Timezone'),

#Trix Field

The Trix field provides a Trix editor (opens new window)for its associated field. Typically, this field will correspond to a TEXT column in your database. The Trix field will store its corresponding HTML within the associated database column:

use Laravel\Nova\Fields\Trix;

Trix::make('Biography'),

By default, Trix fields will not display their content when viewing a resource on its detail page. Instead, the content will be hidden behind a "Show Content" link, which will reveal the field's content when clicked. If you would like, you may specify that the Trix field should always display its content by invoking the alwaysShow method when defining the field:

Trix::make('Biography')->alwaysShow(),

#Trix File Uploads

If you would like to allow users to drag-and-drop photos into the Trix field, you may chain the withFiles method onto the field's definition. When calling the withFiles method, you should pass the name of the filesystem disk (opens new window)that photos should be stored on:

use Laravel\Nova\Fields\Trix;

Trix::make('Biography')->withFiles('public'),

In addition, you should define two database tables to store pending and persisted Trix uploads. To do so, create a migration with the following table definitions:

Schema::create('nova_pending_trix_attachments', function (Blueprint $table) {
    $table->increments('id');
    $table->string('draft_id')->index();
    $table->string('attachment');
    $table->string('disk');
    $table->timestamps();
});

Schema::create('nova_trix_attachments', function (Blueprint $table) {
    $table->increments('id');
    $table->string('attachable_type');
    $table->unsignedInteger('attachable_id');
    $table->string('attachment');
    $table->string('disk');
    $table->string('url')->index();
    $table->timestamps();

    $table->index(['attachable_type', 'attachable_id']);
});

Finally, in your app/Console/Kernel.php file, you should register a daily job (opens new window)to prune any stale attachments from the pending attachments table and storage. For convenience, Laravel Nova provides the job implementation needed to accomplish this:

use Laravel\Nova\Trix\PruneStaleAttachments;

$schedule->call(new PruneStaleAttachments)->daily();

#UI-Avatar Field

The UiAvatar field does not correspond to any column in your application's database. Instead, this field will generate a simple avatar containing the user's initials. This field is powered by ui-avatars.com (opens new window).

By default, the UiAvatar image will be generated based on the value of the model's name column. However, if your user's names are not stored in the name column, you may pass a custom column name to the field's make method:

use Laravel\Nova\Fields\UiAvatar;

// Using the "name" column...
UiAvatar::make(),

// Using a custom column...
UiAvatar::make('Avatar', 'full_name'),

If necessary, you may invoke the resolveUsing method to specify a closure that should be invoked to determine the name that should be used to generate the avatar:

UiAvatar::make()->resolveUsing(function () {
    return implode(' ', explode('@', $this->email));
}),

You may use the squared method to display the image's thumbnail with squared edges. Additionally, you may use the rounded method to display the images with fully-rounded edges:

UiAvatar::make('Avatar', 'fullname')->squared(),

Additional options available when defining UiAvatar fields include:

OptionMethodDescription
Font SizefontSize(0.4)Set a font size between 0.1 to 1.
Boldbold()Set font weight to bold.
Background ColorbackgroundColor('1D4ED7')Set the hex color for the image background.
Text Colorcolor('FFFFFF')Set the hex color for the image text.

#URL Field

The URL field renders URLs as clickable links instead of plain text:

URL::make('GitHub URL'),

The URL field also supports customizing the generated link's text by invoking the displayUsing method when defining the field. The displayUsing method accepts a closure that should return the link's text:

URL::make('Receipt')
    ->displayUsing(fn () => "{optional($this->user)->name}'s receipt")

By providing a closure as the second argument to the URL field, you may use the field to render a link for a computed value that does not necessarily correspond to a column within the associated model's database table:

URL::make('Receipt', fn () => $this->receipt_url)

#Vapor File Field

The Vapor file field provides convenience and compatibility for uploading files when deploying applications to a serverless environment using Laravel Vapor (opens new window):

use Laravel\Nova\Fields\VaporFile;

VaporFile::make('Document'),

When uploading a file using a VaporFile field, Nova will first generate a signed storage URL on Amazon S3. Next, Nova will upload the file directly to temporary storage in the Amazon S3 bucket. When the resource is saved, Nova will move the file to permanent storage.

Vapor Storage

For more information on how file storage is handled for Vapor applications, please refer to the Laravel Vapor storage documentation (opens new window).

#Vapor Image Field

Vapor file fields provide convenience and compatibility for uploading image files when deploying applications in a serverless environment using Laravel Vapor (opens new window):

use Laravel\Nova\Fields\VaporImage;

VaporImage::make('Avatar'),

Vapor image files support many of the same methods available to Image fields.

File Fields

To learn more about defining file fields and handling uploads, check out the additional file field documentation.

#Validating Vapor Image / File Fields

In order to validate the size or other attributes of a Vapor file, you will need to inspect the file directly via the Storage facade:

use Illuminate\Support\Facades\Storage;

VaporFile::make('Document')
    ->rules('bail', 'required', function ($attribute, $value, $fail) use ($request) {
        if (Storage::size($request->input('vaporFile')[$attribute]['key']) > 1000000) {
            return $fail('The document size may not be greater than 1 MB');
        }
    }),

#Computed Fields

In addition to displaying fields that are directly associated with columns in your database, Nova allows you to create "computed fields". Computed fields may be used to display computed values that are not associated with a database column. Since they are not associated with a database column, computed fields may not be sortable. These fields may be created by passing a callable (instead of a column name) as the second argument to the field's make method:

Text::make('Name', function () {
    return $this->first_name.' '.$this->last_name;
}),

The model instance will be passed to the computed field callable, allowing you to access the model's properties while computing the field's value:

Text::make('Name', function ($model) {
    return $model->first_name.' '.$model->last_name;
}),

Model Attribute Access

As you may have noticed in the example above, you may also use $this to access the resource's underlying model attributes and relationships.

By default, Vue will escape the content of a computed field. If you need to render HTML content within the field, invoke the asHtml method when defining your field:

Text::make('Status', function () {
    return view('partials.status', [
        'isPassing' => $this->isPassing(),
    ])->render();
})->asHtml(),

#Customization

#Readonly Fields

There are times where you may want to allow the user to only create and update certain fields on a resource. You can mark fields as "read only" by invoking the readonly method on the field, which will disable the field's corresponding input. You may pass a boolean argument to the readonly method to dynamically control whether a field should be "read only":

Text::make('Email')->readonly(optional($this->resource)->trashed()),

You may also pass a closure to the readonly method, and the result of the closure will be used to determine if the field should be "read only". The closure will receive the current NovaRequest as its first argument:

Text::make('Email')->readonly(function ($request) {
    return ! $request->user()->isAdmin();
}),

If you only want to mark a field as "read only" when creating or attaching resources, you may use the isCreateOrAttachRequest and isUpdateOrUpdateAttachedRequest methods available via the NovaRequest instance, respectively:

Text::make('Email')->readonly(function ($request) {
    return $request->isUpdateOrUpdateAttachedRequest();
}),

#Required Fields

By default, Nova will use a red asterisk to indicate a field is required:

Required Fields

Nova does this by looking for the required rule inside the field's validation rules to determine if it should show the required state. For example, a field with the following definition would receive a "required" indicator:

Text::make('Email')->rules('required'),

When you have complex required validation requirements, you can manually mark the field as required by passing a boolean to the required method when defining the field. This will inform Nova that a "required" indicator should be shown in the UI:

Text::make('Email')->required(true),

In addition, you may also pass a closure to the required method to determine if the field should be marked as required. The closure will receive an instance of NovaRequest. The value returned by the closure will be used to determine if field is required:

use Illuminate\Validation\Rule;

Text::make('Email')->required(function ($request) {
    return $this->notify_via_email;
}),

required() Limitations

The required() method will only add a "required" indicator to the Nova UI. You must still define the related requirement rules() that should apply during validation.

#Nullable Fields

By default, Nova attempts to store all fields with a value, however, there are times where you may prefer that Nova store a null value in the corresponding database column when the field is empty. To accomplish this, you may invoke the nullable method on your field definition:

Text::make('Position')->nullable(),

You may also set which values should be interpreted as a null value using the nullValues method, which accepts an array or a closure as its only argument:

Text::make('Position')->nullable()->nullValues(['', '0', 'null']),

Text::make('Position')->nullable()->nullValues(function ($value) {
    return $value == '' || $value == 'null' || (int)$value === 0;
}),

#Field Help Text

If you would like to place "help" text beneath a field, you may invoke the help method when defining your field:

Text::make('Tax Rate')->help(
    'The tax rate to be applied to the sale'
),

If necessary, you may include HTML within your field's help text to further customize the help text:

Text::make('First Name')->help(
    '<a href="#">External Link</a>'
),

Text::make('Last Name')->help(
    view('partials.help-text', ['name' => $this->name])->render()
),

#Field Stacking

By default, Nova displays fields next to their labels, however some fields like "Code", "Markdown", and "Trix" may benefit from the extra width that can be gained by placing the field under their corresponding labels. Fields can be stacked underneath their label using the stacked method:

Trix::make('Content')->stacked(),

#Field Text Alignment

You may change the text alignment of fields using the textAlign method:

Text::make('Phone Number')->textAlign('left'),

The following alignments are valid:

  • left
  • center
  • right

#Field Resolution / Formatting

The resolveUsing method allows you to customize how a field is formatted after it is retrieved from your database but before it is sent to the Nova front-end. This method accepts a callback which receives the raw value of the underlying database column:

Text::make('Name')->resolveUsing(function ($name) {
    return strtoupper($name);
}),

If you would like to customize how a field is formatted only when it is displayed on a resource's "index" or "detail" pages, you may use the displayUsing method. Like the resolveUsing method, this method accepts a single callback:

Text::make('Name')->displayUsing(function ($name) {
    return strtoupper($name);
}),

#Filterable Fields

The filterable method allows you to enable convenient, automatic filtering functionality for a given field on resources, relationships, and lenses. The Nova generated filter will automatically be made available via the resource filter menu on the resource's index:

DateTime::make('Created At')->filterable(),

Filterable fields

The filterable method also accepts a closure as an argument. This closure will receive the filter query, which you may then customize in order to filter the resource results to your liking:

Text::make('Email')->filterable(function ($request, $query, $value, $attribute) {
    $query->where($attribute, 'LIKE', "{$value}%");
}),

The generated filter will be a text filter, select filter, number range filter, or date range filter depending on the underlying field type that was marked as filterable.

#Dependent Fields

The dependsOn method allows you to specify that a field's configuration depends on one or more other field's values. The dependsOn method accepts an array of dependent field attributes and a closure that modifies the configuration of the current field instance.

Dependent fields allow advanced customization, such as toggling read-only mode, validation rules, and more based on the state of another field:

use Laravel\Nova\Fields\FormData;
use Laravel\Nova\Fields\Select;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\NovaRequest;

Select::make('Purchase Type', 'type')
    ->options([
        'personal' => 'Personal',
        'gift' => 'Gift',
    ]),

// Recipient field configuration is customized based on purchase type...
Text::make('Recipient')
    ->readonly()
    ->dependsOn(
        ['type'], 
        function (Text $field, NovaRequest $request, FormData $formData) {
            if ($formData->type === 'gift') {
                $field->readonly(false)->rules(['required', 'email']);
            }
        }
    ),

The following field types may depend on other fields:

  • BelongsTo
  • Boolean
  • BooleanGroup
  • Color
  • Code
  • Country
  • Currency
  • File
  • Heading
  • Hidden
  • Image
  • KeyValue
  • Markdown
  • Number
  • Password
  • PasswordConfirmation
  • Status
  • Textarea
  • Text
  • URL
  • VaporFile
  • VaporImage

The following field types may not be depended upon by other fields since they do not live-report their changes to Nova:

  • Code
  • File
  • Image
  • KeyValue
  • Status
  • Trix
  • VaporFile
  • VaporImage

#Toggling Field Visibility

One common use-case for dependent fields is toggling field visibility based on the value of another field. You can accomplish this using the hide and show methods:

use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\Boolean;
use Laravel\Nova\Fields\FormData;
use Laravel\Nova\Http\Requests\NovaRequest;

Boolean::make('Anonymous Comment', 'anonymous')
    ->default(true),

BelongsTo::make('User')
    ->hide()
    ->rules('sometimes')
    ->dependsOn('anonymous', function (BelongsTo $field, NovaRequest $request, FormData $formData) {
        if ($formData->anonymous === false) {
            $field->show()->rules('required');
        }
    }),

#Accessing Request Resource IDs

When interacting with dependent fields, you may retrieve the current resource and related resource IDs via the resource method:

Currency::make('Price')
    ->dependsOn('book', function ($field, NovaRequest $request, $formData) {
        $bookId = (int) $formData->resource('book', $formData->book);

        if ($bookId == 1) {
            $field->rules([
                'required', 'numeric', 'min:10', 'max:199'
            ])->help('Price starts from $10-$199');

            return;
        }

        $field->rules([
            'required', 'numeric', 'min:0', 'max:99'
        ])->help('Price starts from $0-$99');
    }),

In addition to the variety of fields we've already discussed, Nova has full support for all of Laravel's relationships. Once you add relationship fields to your Nova resources, you'll start to experience the full power of the Nova dashboard, as the resource detail page will allow you to quickly view and search a resource's related models:

Detail page Relationship

#HasOne

The HasOne field corresponds to a hasOne Eloquent relationship. For example, let's assume a User model hasOne Address model. We may add the relationship to our User Nova resource like so:

use Laravel\Nova\Fields\HasOne;

HasOne::make('Address'),

Like other types of fields, relationship fields will automatically "camel case" the displayable name of the field to determine the underlying relationship method / attribute. However, you may explicitly specify the name of the relationship method by passing it as the second argument to the field's make method:

HasOne::make('Dirección', 'address'),

#HasOneOfMany

The HasOne relationship field can be transformed into an "has one of many" Eloquent relationship using the ofMany method. For example, let's assume a User model hasMany Post models. We may add the "has one of many" relationship to our User Nova resource like so:

use App\Nova\Post;
use Laravel\Nova\Fields\HasOne;

HasOne::ofMany('Latest Post', 'latestPost', Post::class),

#HasMany

The HasMany field corresponds to a hasMany Eloquent relationship. For example, let's assume a User model hasMany Post models. We may add the relationship to our User Nova resource like so:

use Laravel\Nova\Fields\HasMany;

HasMany::make('Posts'),

Once the field has been added to your resource, it will be displayed on the resource's detail page.

Plural Resource Names

When defining HasMany relationships, make sure to use the plural form of the relationship so Nova can infer the correct singular resource name:

HasMany::make('Posts'),

#HasOneThrough

The HasOneThrough field corresponds to a hasOneThrough Eloquent relationship. For example, let's assume a Mechanic model has one Car, and each Car may have one Owner. While the Mechanic and the Owner have no direct connection, the Mechanic can access the Owner through the Car itself. You can display this relationship by adding it to your Nova resource:

use Laravel\Nova\Fields\HasOneThrough;

HasOneThrough::make('Owner'),

#HasManyThrough

The HasManyThrough field corresponds to a hasManyThrough Eloquent relationship. For example, a Country model might have many Post models through an intermediate User model. In this example, you could easily gather all blog posts for a given country. To display this relationship within Nova, you may add it to your Nova resource:

use Laravel\Nova\Fields\HasManyThrough;

HasManyThrough::make('Posts'),

#BelongsTo

The BelongsTo field corresponds to a belongsTo Eloquent relationship. For example, let's assume a Post model belongsTo a User model. We may add the relationship to our Post Nova resource like so:

use Laravel\Nova\Fields\BelongsTo;

BelongsTo::make('User'),

Customizing Resource Classes

You may customize the resource class used by the relation field by providing the second and third arguments of the make method, which define the name of the relationship and the underlying Nova resource class:

BelongsTo::make('Author', 'author', 'App\Nova\User'),

#Nullable Relationships

If you would like your BelongsTo relationship to be nullable, you may simply chain the nullable method onto the field's definition:

use Laravel\Nova\Fields\BelongsTo;

BelongsTo::make('User')->nullable(),

#Title Attributes

When a BelongsTo field is shown on a resource creation / update page, a drop-down selection menu or search menu will display the "title" of the resource. For example, a User resource may use the name attribute as its title. Then, when the resource is shown in a BelongsTo selection menu, that attribute will be displayed:

Belongs To Title

To customize the "title" attribute of a resource, you may define a title property on the resource class:

public static $title = 'name';

Alternatively, you may override the resource's title method:

/**
 * Get the value that should be displayed to represent the resource.
 *
 * @return string
 */
public function title()
{
    return $this->name;
}

#Disable Ordering By Title

By default, associatable resources will be sorted by their title when listed in a select dropdown. Using the dontReorderAssociatables method, you can disable this behavior so that the resources as sorted based on the ordering specified by the relatable query:

BelongsTo::make('User')->dontReorderAssociatables(),

#Filter Trashed Items

By default, the BelongsTo field will allow users to select soft-deleted models; however, this can be disabled using the withoutTrashed method:

BelongsTo::make('User')->withoutTrashed(),

#BelongsToMany

The BelongsToMany field corresponds to a belongsToMany Eloquent relationship. For example, let's assume a User model belongsToMany Role models:

public function roles()
{
    return $this->belongsToMany(Role::class);
}

We may add the relationship to our User Nova resource like so:

use Laravel\Nova\Fields\BelongsToMany;

BelongsToMany::make('Roles'),

You may customize the resource class used by the relationship field by providing the second and third arguments to the make method:

BelongsToMany::make('Pseudonyms', 'pseudonyms', 'App\Nova\Author'),

Once the field has been added to your resource, it will be displayed on the resource's detail page.

#Pivot Fields

If your belongsToMany relationship interacts with additional "pivot" fields that are stored on the intermediate table of the many-to-many relationship, you may also attach those to your BelongsToMany Nova relationship. Once these fields are attached to the relationship field, and the relationship has been defined on both of the related models / resources, they will be displayed on the related resource index.

For example, let's assume our User model belongsToMany Role models. On our role_user intermediate table, let's imagine we have a notes field that contains some simple text notes about the relationship. We can attach this pivot field to the BelongsToMany field using the fields method:

BelongsToMany::make('Roles')
    ->fields(function ($request, $relatedModel) {
        return [
            Text::make('Notes'),
        ];
    }),

Of course, it is likely we would also define this field on the inverse of the relationship. So, if we define the BelongsToMany field on the User resource, we would define its inverse on the Role resource:

BelongsToMany::make('Users')
    ->fields(function ($request, $relatedModel) {
        return [
            Text::make('Notes'),
        ];
    }),

Pivot fields must be defined

Don't forget to define the pivot fields inside your Model's relationship definition using the withPivot method: https://laravel.com/docs/9.x/eloquent-relationships#retrieving-intermediate-table-columns(opens new window)

Since defining the field on both ends of the relationship can cause some code duplication, Nova allows you to pass an invokable object to the fields method:

BelongsToMany::make('Users')->fields(new RoleUserFields),

In this example, the RoleUserFields class would be a simple, invokable class that returns the array of pivot fields:

<?php

namespace App\Nova;

use Laravel\Nova\Fields\Text;

class RoleUserFields
{
    /**
     * Get the pivot fields for the relationship.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Model  $relatedModel
     * @return array
     */
    public function __invoke($request, $relatedModel)
    {
        return [
            Text::make('Notes'),
        ];
    }
}

#Pivot Computed Fields

Laravel Nova also allows you to define computed fields within the field list of a belongsToMany relationship field:

BelongsToMany::make('Users')
    ->fields(function ($request, $relatedModel) {
        return [
            Text::make('Notes'),

            Boolean::make('Has Notes', function ($pivot) {
                return ! empty($pivot->notes);
            }),
        ];
    }),

#Pivot Actions

Typically, Nova actions operate on a resource. However, you may also attach actions to belongsToMany fields so that they can operate on pivot / intermediate table records. To accomplish this, you may chain the actions method onto your field's definition:

BelongsToMany::make('Roles')
    ->actions(function () {
        return [
            new Actions\MarkAsActive,
        ];
    }),

Once the action has been attached to the field, you will be able to select the action and execute it from the relationship index on the parent resource's detail page.

Actions

To learn more about Nova actions, check out the complete action documentation.

#Title Attributes

When a BelongsToMany field is shown on a resource creation / update page, a drop-down selection menu or search menu will display the "title" of the resource. For example, a Role resource may use the name attribute as its title. Then, when the resource is shown in a BelongsToMany selection menu, that attribute will be displayed:

Belongs To Many Title

To customize the "title" attribute of a resource, you may define a title property on the resource class:

public static $title = 'name';

Alternatively, you may override the resource's title method:

/**
 * Get the value that should be displayed to represent the resource.
 *
 * @return string
 */
public function title()
{
    return $this->name;
}

#Allowing Duplicate Relations

By default, Laravel Nova ensures that "belongs to many" relationships are unique. However, if necessary, you may instruct Nova to allow duplicate relationship entries.

To get started, you should ensure that your pivot record's id column is available by using the withPivot method when defining the relationship on your Eloquent model. In this example, let's imagine that a User may purchase a Book one or more times:

public function books()
{
    return $this->belongsToMany(Book::class)
                ->using(BookPurchase::class)
                ->withPivot('id', 'notes')
                ->withTimestamps();
}

Next, we can define the Nova relationship that allows duplicate relations using the allowDuplicateRelations method:

BelongsToMany::make('Books')
    ->fields(function () {
        return [
            Text::make('Notes'),
        ];
    })->allowDuplicateRelations(),

#MorphOne

The MorphOne field corresponds to a morphOne Eloquent relationship. For example, let's assume a Post has a one-to-one polymorphic relationship with the Image model. We may add the relationship to our Post Nova resource like so:

use Laravel\Nova\Fields\MorphOne;

MorphOne::make('Image'),

#MorphOneOfMany

The MorphOne relationship field can be transformed into a "morph one of many" Eloquent relationship using the ofMany method. For example, let's assume a Post has a one-to-many polymorphic relationship with the Comment model. We may add the relationship to our Post Nova resource like so:

use App\Nova\Comment;
use Laravel\Nova\Fields\MorphOne;

MorphOne::ofMany('Latest Comment', 'latestComment', Comment::class),

#MorphMany

The MorphMany field corresponds to a morphMany Eloquent relationship. For example, let's assume a Post has a one-to-many polymorphic relationship with the Comment model. We may add the relationship to our Post Nova resource like so:

use Laravel\Nova\Fields\MorphMany;

MorphMany::make('Comments'),

#MorphTo

The MorphTo field corresponds to a morphTo Eloquent relationship. For example, let's assume a Comment model has a polymorphic relationship with both the Post and Video models. We may add the relationship to our Comment Nova resource like so:

use App\Nova\Post;
use App\Nova\Video;
use Laravel\Nova\Fields\MorphTo;

MorphTo::make('Commentable')->types([
    Post::class,
    Video::class,
]),

As you can see in the example above, the types method is used to instruct the MorphTo field what types of resources it may be associated with. Nova will use this information to populate the MorphTo field's type selection menu on the creation and update pages:

Morph To Type

MorphTo Title Attributes

When a MorphTo field is shown on a resource creation / update page, the title attributes of the available resources will automatically be displayed.

#Nullable Relationships

If you would like your MorphTo relationship to be nullable, chain the nullable method onto the field's definition:

use App\Nova\Post;
use App\Nova\Video;
use Laravel\Nova\Fields\MorphTo;

MorphTo::make('Commentable')->types([
    Post::class,
    Video::class,
])->nullable(),

#MorphToMany

The MorphToMany field corresponds to a morphToMany Eloquent relationship. For example, let's assume a Post has a many-to-many polymorphic relationship with the Tag model. We may add the relationship to our Post Nova resource like so:

use Laravel\Nova\Fields\MorphToMany;

MorphToMany::make('Tags'),

#Pivot Fields

If your morphToMany relationship interacts with additional "pivot" fields that are stored on the intermediate table of the many-to-many relationship, you may also attach those to your MorphToMany Nova relationship. Once these fields are attached to the relationship field, they will be displayed on the related resource index.

For example, on our taggables intermediate table, let's imagine we have a notes field that contains some simple text notes about the relationship. We can attach this pivot field to the MorphToMany field using the fields method:

MorphToMany::make('Tags')
    ->fields(function ($request, $relatedModel) {
        return [
            Text::make('Notes'),
        ];
    }),

Of course, it is likely we would also define this field on the inverse of the relationship. So, if we define the MorphToMany field on the Post resource, we would define it's inverse on the Tag resource:

MorphToMany::make('Posts')
    ->fields(function ($request, $relatedModel) {
        return [
            Text::make('Notes'),
        ];
    }),

Pivot fields must be defined

Don't forget to define the pivot fields inside your Model's relationship definition using the withPivot method: https://laravel.com/docs/9.x/eloquent-relationships#retrieving-intermediate-table-columns(opens new window)

Since defining the field on both ends of the relationship can cause some code duplication, Nova allows you to pass an invokable object to the fields method:

MorphToMany::make('Users')->fields(new TaggableFields),

In this example, the TaggableFields class would be a simple, invokable class that returns the array of pivot fields:

<?php

namespace App\Nova;

use Laravel\Nova\Fields\Text;

class TaggableFields
{
    /**
     * Get the pivot fields for the relationship.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Model  $relatedModel
     * @return array
     */
    public function __invoke($request, $relatedModel)
    {
        return [
            Text::make('Notes'),
        ];
    }
}

#Title Attributes

When a MorphToMany field is shown on a resource creation / update page, a drop-down selection menu or search menu will display the "title" of the resource. For example, a Tag resource may use the name attribute as its title. Then, when the resource is shown in a MorphToMany selection menu, that attribute will be displayed:

Morph To Many Title

To customize the "title" attribute of a resource, you may define a title property on the resource class:

public static $title = 'name';

Alternatively, you may override the resource's title method:

/**
 * Get the value that should be displayed to represent the resource.
 *
 * @return string
 */
public function title()
{
    return $this->name;
}

#Searchable Relations

By default, when the BelongsToMorphTo, and MorphToMany relationship fields are shown on a resource creation / update page, a simple drop-down selection menu will be displayed. However, this can quickly become cumbersome if a resource model has many records. For example, imagine a drop-down selection menu populated with over 10,000 users!

Instead of displaying a drop-down selection menu, you may mark your relationships as searchable. When a relationship is marked as searchable, a beautiful search input control will be displayed instead:

Belongs To Search

To mark a relationship as searchable, chain the searchable method onto the field's definition. If you would like to conditionally determine if a field should be searchable, you may pass a closure to the searchable method:

BelongsTo::make('User')->searchable(),

BelongsTo::make('User')->searchable(function ($request) {
    return true;
}),

You may also instruct the relation field to display the resource's subtitle by invoking the withSubtitles method when defining the field:

BelongsTo::make('User')->searchable()->withSubtitles(),

#Limiting Relation Results

You can limit the number of results that are returned when searching the field by defining a relatableSearchResults property on the class of the resource that you are searching for:

/**
 * The number of results to display when searching for relatable resources without Scout.
 *
 * @var int|null
 */
public static $relatableSearchResults = 200;

#Creating Inline Relations

For convenience, When BelongsTo or MorphTo relationship fields are shown on a resource create or update page, you may create the related resource inline via a modal window without leaving the creation / update page:

Creating Inline Relations

To enable this functionality, invoke the showCreateRelationButton method when defining the relationship field:

BelongsTo::make('User')->showCreateRelationButton(),

You may also pass a closure to the showCreateRelationButton method to conditionally determine if inline resource creation should be enabled:

BelongsTo::make('User')->showCreateRelationButton(function ($request) {
    //
}),

You may also create related many-to-many relationships from the "attach" and "update attached" pages. To enable this feature, invoke the showCreateRelationButton when defining a BelongsToMany or MorphToMany relationship:

BelongsToMany::make('Roles')->showCreateRelationButton(),

To hide the inline creation button, invoke the hideCreateRelationButton method when defining the relationship field:

BelongsTo::make('User')->hideCreateRelationButton(),

The inline relation creation process will respect any authorization policies you have defined.

Inline Creation Limitations

Inline relation creation only supports creating relations one level deep. This means you cannot trigger an additional inline creation modal inside an existing inline creation modal. Instead, you must select a resource that already exists.

When Nova is accessed only by you or your development team, you may not need additional authorization before Nova handles incoming requests. However, if you provide access to Nova to your clients or a large team of developers, you may wish to authorize certain requests. For example, perhaps only administrators may delete records. Thankfully, Nova takes a simple approach to authorization that leverages many of the Laravel features you are already familiar with.

#Policies

To limit which users may view, create, update, or delete resources, Nova leverages Laravel's authorization policies (opens new window). Policies are simple PHP classes that organize authorization logic for a particular model or resource. For example, if your application is a blog, you may have a Post model and a corresponding PostPolicy within your application.

When manipulating a resource within Nova, Nova will automatically attempt to find a corresponding policy for the model. Typically, these policies will be registered in your application's AuthServiceProvider. If Nova detects a policy has been registered for the model, it will automatically check that policy's relevant authorization methods before performing their respective actions, such as:

  • viewAny
  • view
  • create
  • update
  • replicate
  • delete
  • restore
  • forceDelete

No additional configuration is required! So, for example, to determine which users are allowed to update a Post model, you simply need to define an update method on the model's corresponding policy class:

<?php

namespace App\Policies;

use App\Models\User;
use App\Models\Post;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can update the post.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Post  $post
     * @return mixed
     */
    public function update(User $user, Post $post)
    {
        return $user->type == 'editor';
    }
}

#Undefined Policy Methods

If a policy exists but is missing a method for a particular action, Nova will use the following default permission for each actions:

Policy ActionDefault Permission
viewAnyAllowed
viewForbidden
createForbidden
updateForbidden
replicateFallback to create and update
deleteForbidden
forceDeleteForbidden
restoreForbidden
add{Model}Allowed
attach{Model}Allowed
detach{Model}Allowed
runActionFallback to update
runDestructiveActionFallback to delete

So, if you have defined a policy, don't forget to define all of its relevant authorization methods so that the authorization rules for a given resource are explicit.

#Hiding Entire Resources

If you would like to hide an entire Nova resource from a subset of your dashboard's users, you may define a viewAny method on the model's policy class. If no viewAny method is defined for a given policy, Nova will assume that the user can view the resource:

<?php

namespace App\Policies;

use App\Models\User;
use App\Models\Post;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can view any posts.
     *
     * @param  \App\Models\User  $user
     * @return mixed
     */
    public function viewAny(User $user)
    {
        return in_array('view-posts', $user->permissions);
    }
}

#Relationships

We have already learned how to authorize the typical view, create, update, and delete actions, but what about relationship interactions? For example, if you are building a podcasting application, perhaps you would like to specify that only certain Nova users may add comments to podcasts. Again, Nova makes this simple by leveraging Laravel's policies.

When working with relationships, Nova uses a simple policy method naming convention. To illustrate this convention, lets assume your application has Podcast resources and Comment resources. If you would like to authorize which users can add comments to a podcast, you should define an addComment method on your podcast model's policy class:

<?php

namespace App\Policies;

use App\Models\User;
use App\Models\Podcast;
use Illuminate\Auth\Access\HandlesAuthorization;

class PodcastPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can add a comment to the podcast.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Podcast  $podcast
     * @return mixed
     */
    public function addComment(User $user, Podcast $podcast)
    {
        return true;
    }
}

As you can see, Nova uses a simple add{Model} policy method naming convention for authorizing relationship actions.

#Authorizing Attaching / Detaching

For many-to-many relationships, Nova uses a similar naming convention. However, instead of add{Model}, you should use an attach{Model} / detach{Model} naming convention. For example, imagine a Podcast model has a many-to-many relationship with the Tag model. If you would like to authorize which users can attach "tags" to a podcast, you may add an attachTag method to your podcast policy. In addition, you will likely want to define the inverse attachPodcast on the tag policy:

<?php

namespace App\Policies;

use App\Models\Tag;
use App\Models\User;
use App\Models\Podcast;
use Illuminate\Auth\Access\HandlesAuthorization;

class PodcastPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can attach a tag to a podcast.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Podcast  $podcast
     * @param  \App\Models\Tag  $tag
     * @return mixed
     */
    public function attachTag(User $user, Podcast $podcast, Tag $tag)
    {
        return true;
    }

    /**
     * Determine whether the user can detach a tag from a podcast.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Podcast  $podcast
     * @param  \App\Models\Tag  $tag
     * @return mixed
     */
    public function detachTag(User $user, Podcast $podcast, Tag $tag)
    {
        return true;
    }
}

In the previous examples, we are determining if a user is authorized to attach one model to another. If certain types of users are never allowed to attach a given type of model, you may define a attachAny{Model} method on your policy class. This will prevent the "Attach" button from displaying in the Nova UI entirely:

<?php

namespace App\Policies;

use App\Models\User;
use App\Models\Podcast;
use Illuminate\Auth\Access\HandlesAuthorization;

class PodcastPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can attach any tags to the podcast.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Podcast  $podcast
     * @return mixed
     */
    public function attachAnyTag(User $user, Podcast $podcast)
    {
        return false;
    }
}

Many To Many Authorization

When working with many-to-many relationships, make sure you define the proper authorization policy methods on each of the related resource's policy classes.

#Disabling Authorization

If one of your Nova resources' models has a corresponding policy, but you want to disable Nova authorization for that resource (thus allowing all actions), you may override the authorizable method on the Nova resource:

/**
 * Determine if the given resource is authorizable.
 *
 * @return bool
 */
public static function authorizable()
{
    return false;
}

#Fields

Sometimes you may want to hide certain fields from a group of users. You may easily accomplish this by chaining the canSee method onto your field definition. The canSee method accepts a closure which should return true or false. The closure will receive the incoming HTTP request:

use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Text;

/**
 * Get the fields displayed by the resource.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return array
 */
public function fields(NovaRequest $request)
{
    return [
        ID::make()->sortable(),

        Text::make('Name')
                ->sortable()
                ->canSee(function ($request) {
                    return $request->user()->can('viewProfile', $this);
                }),
    ];
}

In the example above, we are using Laravel's Authorizable trait's can method on our User model to determine if the authorized user is authorized for the viewProfile action. However, since proxying to authorization policy methods is a common use-case for canSee, you may use the canSeeWhen method to achieve the same behavior. The canSeeWhen method has the same method signature as the Illuminate\Foundation\Auth\Access\Authorizable trait's can method:

Text::make('Name')
        ->sortable()
        ->canSeeWhen('viewProfile', $this),

Authorization & The "Can" Method

To learn more about Laravel's authorization helpers and the can method, check out the full Laravel authorization documentation (opens new window).

#Index Filtering

You may notice that returning false from a policy's view method does not stop a given resource from appearing in the resource index. To filter models from the resource index query, you may override the indexQuery method on the resource's class.

This method is already defined in your application's App\Nova\Resource base class; therefore, you may simply copy and paste the method into a specific resource and then modify the query based on how you would like to filter the resource's index results:

/**
 * Build an "index" query for the given resource.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @param  \Illuminate\Database\Eloquent\Builder  $query
 * @return \Illuminate\Database\Eloquent\Builder
 */
public static function indexQuery(NovaRequest $request, $query)
{
    return $query->where('user_id', $request->user()->id);
}

#Relatable Filtering

If you would like to filter the queries that are used to populate relationship model selection menus, you may override the relatableQuery method on your resource.

For example, if your application has a Comment resource that belongs to a Podcast resource, Nova will allow you to select the parent Podcast when creating a Comment. To limit the podcasts that are available in that selection menu, you should override the relatableQuery method on your Podcast resource:

/**
 * Build a "relatable" query for the given resource.
 *
 * This query determines which instances of the model may be attached to other resources.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @param  \Illuminate\Database\Eloquent\Builder  $query
 * @param  \Laravel\Nova\Fields\Field  $field
 * @return \Illuminate\Database\Eloquent\Builder
 */
public static function relatableQuery(NovaRequest $request, $query)
{
    return $query->where('user_id', $request->user()->id);
}

#Dynamic Relatable Methods

You can customize the "relatable" query for individual relationships by using a dynamic, convention based method name. For example, if your application has a Post resource, in which posts can be tagged, but the Tag resource is associated with different types of models, you may define a relatableTags method to customize the relatable query for this relationship:

/**
 * Build a "relatable" query for the given resource.
 *
 * This query determines which instances of the model may be attached to other resources.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @param  \Illuminate\Database\Eloquent\Builder  $query
 * @param  \Laravel\Nova\Fields\Field  $field
 * @return \Illuminate\Database\Eloquent\Builder
 */
public static function relatableTags(NovaRequest $request, $query)
{
    return $query->where('type', 'posts');
}

If necessary, you may access the resource and resourceId for the request via the NovaRequest instance that is passed to your method:

public static function relatableTags(NovaRequest $request, $query)
{
    $resource = $request->route('resource'); // The resource type...
    $resourceId = $request->route('resourceId'); // The resource ID...

    return $query->where('type', $resource);
}

When a Nova resource depends on another resource via multiple fields, you will often assign the fields different names. In these situations, you should supply a third argument when defining the relationship to specify which Nova resource the relationship should utilize, since Nova may not be able to determine this via convention:

HasMany::make('Owned Teams', 'ownedTeams', Team::class),
BelongsToMany::make('Teams', 'teams', Team::class),

#Relationship Types

If necessary when customizing the "relatable" query, you may examine the field type to determine how to build the relationship query:

/**
 * Build a "relatable" query for the given resource.
 *
 * This query determines which instances of the model may be attached to other resources.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @param  \Illuminate\Database\Eloquent\Builder  $query
 * @param  \Laravel\Nova\Fields\Field  $field
 * @return \Illuminate\Database\Eloquent\Builder
 */
public static function relatableTeams(NovaRequest $request, $query, Field $field)
{
    if ($field instanceof BelongsToMany) {
        // ...
    }

    return $query;
}

#Scout Filtering

If your application is leveraging the power of Laravel Scout for search, you may also customize the Laravel\Scout\Builder query instance before it is sent to your search provider. To accomplish this, override the scoutQuery method on your resource class:

/**
 * Build a Scout search query for the given resource.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @param  \Laravel\Scout\Builder  $query
 * @return \Laravel\Scout\Builder
 */
public static function scoutQuery(NovaRequest $request, $query)
{
    return $query->where('user_id', $request->user()->id);
}

Registering Filters

    Once you have defined a filter, you are ready to attach it to a resource. Each resource generated by Nova contains a filters method. To attach a filter to a resource, you should simply add it to the array of filters returned by this method:

    /**
     * Get the filters available for the resource.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @return array
     */
    public function filters(NovaRequest $request)
    {
        return [
            new Filters\UserType,
        ];
    }
    

    Comments

    Popular posts from this blog

    Maan News v2.0.1 - Laravel Magazine Blog & News PHP Script

      Maan News Maan News- Laravel News, Magazine & Blog PHP Script Created:  13/10/2021 By:   Maan Theme Email:   support@maantheme.com Thank you for purchasing our product. We hope that you find all your questions regarding this product answered in this Documentation as much in details as possible. However, if you still need support, do not hesitate to contact us at our support forum for this Template. If you have any questions that are beyond the scope of this help file, please feel free to email me. Thanks so much! I...

    Live TV with Firebase Admin Panel and Admob , Facebook Ads v1.4

      Fire Tv  – Live TV Application is app that show live tv on android device. Watch your favorite TV channels Live in your mobile phone with this Android application on your Android device. that support almost all format.The application is specially optimized to be extremely easy to configure and detailed documentation is provided. Preview Item   Screenshots Add to Favorites   Add to Collection Fire Tv  – Live TV Application is app that show live tv on android device. Watch your favorite TV channels Live in your mobile phone with this Android application on your Android device. that support almost all format.The application is specially optimized to be extremely easy to configure and detailed documentation is provided. Download Demo App –  Click Here   Features Trending Channels Search channels Personalized channels All Categories and their channels Latest Channels / Streams Channel Detail One Signal Notification Add Streams into Favourites Share with o...