Skip to content

Version v1.6.5 Older versions: docs on GitHub

Entities

On this page

An Entity describes how a model appears in the panel: its fields, what to search by, and which records the user can see. The class extends Maxcxam\Larsadmin\Entity.

If you know Nova, an Entity corresponds to a Resource.

Generator

php artisan larsadmin:entity Post --model=Post
  • The class is created as App\Larsadmin\Post.
  • Without --model, the model is taken from the class name (Post gives App\Models\Post).
  • --force overwrites an existing class.

Classes in app/Larsadmin (including subdirectories) are registered automatically in the boot() method of the App\Providers\LarsadminServiceProvider provider. To register them manually:

use Maxcxam\Larsadmin\Larsadmin;

Larsadmin::entities([\App\Larsadmin\Post::class]);
Larsadmin::entitiesIn(app_path('Domain/Admin')); // a directory inside app/

A minimal Entity

namespace App\Larsadmin;

use Illuminate\Http\Request;
use Maxcxam\Larsadmin\Entity;
use Maxcxam\Larsadmin\Fields\ID;
use Maxcxam\Larsadmin\Fields\Text;

class Category extends Entity
{
    public static string $model = \App\Models\Category::class;
    public static string $title = 'name';
    public static array $search = ['id', 'name', 'slug'];
    public static ?string $group = 'Контент';
    public static ?string $label = 'Категорії';
    public static ?string $singularLabel = 'Категорія';

    public function fields(Request $request): array
    {
        return [
            ID::make()->sortable(),
            Text::make('Назва', 'name')->sortable()->rules('required', 'max:255'),
        ];
    }
}

fields() is the only required method.

Static properties

Property Type, default Description
$model class-string<Model>, required The Eloquent model
$title string, 'id' Attribute used as the record's title (read with data_get)
$search array, ['id'] What to search (see below). An empty array disables search
$with array, [] Relations always eager-loaded on index and detail
$label ?string, null Plural label for navigation and headings; translated with __(). When null, the plural of the class name is used
$singularLabel ?string, null Singular label; translated with __(). When null, it is derived from the class name
$group ?string, null Navigation group
$sort array, [] Default sort order when the request has no valid sort: ['published_at' => 'desc']
$perPage int, 25 Default page size
$perPageOptions array, [25, 50, 100] Allowed page sizes (?perPage=). Any other value is replaced with $perPage
$displayInNavigation bool, true Show the Entity in the side navigation
$globallySearchable bool, false Take part in the global search (Ctrl/⌘+K), see Global search
$globalSearchLimit ?int, null Results in the global search; null uses larsadmin.search.limit (5), clamped to 1..20
$subtitle ?string, null Attribute of the global search result's second line (a column or a one-level relation.attribute)
$auditable bool, true Record the Entity's changes in the audit log when the log is on; false opts out, see Audit log

Relations that fields need (for example, BelongsTo) are loaded automatically. You only need $with for extra relations, say, when $title points to author.name.

Default sort order

public static array $sort = ['published_at' => 'desc'];

Keys are field attributes, values are asc or desc. Each attribute must belong to a ->sortable() field that the user can see (canSee); otherwise an InvalidArgumentException is thrown. A ?sort= in the request takes precedence; the record key is always the final tiebreaker. The UI receives the value as query.defaultSort and shows it as the current sort.

URI key

Entity::uriKey() builds the URL segment: the plural of the class name in kebab-case (BlogPost gives blog-posts, URL /admin/entities/blog-posts). Override the static method to change the key.

Entries of $search:

Entry Behaviour
'title' LIKE on the column
'id' (the model's key name) equality; for an integer key, only a numeric term is used
'author.name' relation.column: one level deep, via orWhereHas

The term is trimmed and cut to 100 characters.

On SQLite, LIKE ignores case for Latin letters only, so "огляд" does not find "Огляд". MySQL and PostgreSQL collations handle Cyrillic case.

For relation.column, the search only covers records that the related Entity's indexQuery lets through (when the relation matches a registered Entity), so hidden related rows are not revealed.

Columns of fields hidden from the user with canSee are not searched.

The global search uses the same columns when the Entity enables $globallySearchable and the model does not use Laravel Scout. See Global search.

Record URLs

A serialized record contains urls (show, edit, destroy), built on the server. A value is null when the action is not allowed or the record key is unsafe for a path. The $entity->url('show') method returns a relative URL or null.

Scoping rows: indexQuery, detailQuery, relatableQuery

Three static hooks decide which rows the user sees.

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;

public static function indexQuery(Request $request, Builder $query): Builder
{
    return $query->where('status', 'live');
}
Method Used for Default
indexQuery($request, $query) the list (and the HasMany/BelongsToMany panels) returns $query unchanged
detailQuery($request, $query) a single record: show, edit, update, delete, actions on selected records calls indexQuery
relatableQuery($request, $query) records that can be selected in BelongsTo/BelongsToMany and that validation accepts calls indexQuery

indexQuery should match the rows the user is allowed to see; detailQuery and relatableQuery inherit it. Override them only to loosen or tighten the restriction. A record outside detailQuery returns 404.

Actions and filters

Optional instance methods (both return an empty array by default):

public function actions(Request $request): array { return [new MarkLive]; }
public function filters(Request $request): array { return [SelectFilter::make('Статус', 'status')->withOptions([...])]; }

See Filters and Actions.

Cards above the list

cards() returns the metrics shown above the Entity's list table ([] by default):

public function cards(Request $request): array
{
    return [NewPosts::make(), PostsByStatus::make()];
}

See Dashboards.

Field blocks

fields() can return not only fields but also Panel and Tabs blocks. See Field blocks.

Record title

$entity->title() returns (string) data_get($record, static::$title). This is the record's label in headings, breadcrumbs, relation pickers and global search results.

$entity->subtitle() returns the $subtitle value (or null) and is only used as the second line of a global search result. For $title/$subtitle the search checks canSee and access to the related record; an overridden title()/subtitle() is used as is, so your code owns its visibility. See Global search.

Authorization

An Entity checks the model policy: viewAny, create, view, update, delete. Details in Authorization.

Next: Fields.

Type to search all guides. Use ↑ ↓ to move and Enter to open.