Поля

Базовые методы

Описание

Все поля наследуют базовый класс Field, который предоставляет базовые методы работы с полями.

Создание поля

Для создания экземпляра поля используется статический метод make().

make(
Closure|string|null $label = null,
?string $column = null,
?Closure $formatted = null
)
make(
Closure|string|null $label = null,
?string $column = null,
?Closure $formatted = null
)
  • $label - заголовок поля,
  • $column - связь столбца в базе и атрибута name у поля ввода (например: description > <input name="description">). Если это поле отношения, то используется название отношения (например: countries),
  • $formatted - замыкание для форматирования значения поля в режиме preview (для BelongsTo и BelongsToMany форматирует значения для выбора).

HTML в $label экранируется по умолчанию. Используйте unescapeLabel(), чтобы разрешить доверенный HTML. Подробнее: Экранирование отображаемого текста.

Если не указать $column, то поле в базе данных будет определено автоматически на основе $label (только для английского языка).

Пример замыкания $formatted для форматирования значения:

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Text;
Text::make(
'Name',
'first_name',
fn($item) => $item->first_name . ' ' . $item->last_name
)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Text;
Text::make(
'Name',
'first_name',
fn($item) => $item->first_name . ' ' . $item->last_name
)

Поля не поддерживающие $formatted: Json, File, Range, RangeSlider, DateRange, Select, Enum, HasOne, HasMany.

Отображение поля

Label

Подписи экранируются по умолчанию, в том числе в заголовках таблицы, переключателях выбора столбцов и заголовках отношений. Используйте unescapeLabel() для вывода доверенного HTML или escapeLabel() для явного включения экранирования. Локальная настройка переопределяет глобальную конфигурацию.

Если необходимо изменить label после создания экземпляра поля, можно воспользоваться методом setLabel().

setLabel(Closure|string $label)
setLabel(Closure|string $label)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\UI\Fields\Field;
use MoonShine\Laravel\Fields\Slug;
Slug::make('Slug')
->setLabel(
fn(Field $field) => $field->getData()?->exists
? 'Slug (do not change)'
: 'Slug'
)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\UI\Fields\Field;
use MoonShine\Laravel\Fields\Slug;
Slug::make('Slug')
->setLabel(
fn(Field $field) => $field->getData()?->exists
? 'Slug (do not change)'
: 'Slug'
)

Для перевода label необходимо в качестве названия передать ключ перевода и добавить метод translatable().

translatable(string $key = '')
translatable(string $key = '')
Text::make('ui.Title')->translatable()
Text::make('Title')->translatable('ui')
Text::make('ui.Title')->translatable()
Text::make('Title')->translatable('ui')
Text::make(fn() => __('Title'))
Text::make(fn() => __('Title'))

insideLabel()

Для оборачивания поля в тег <label> можно использовать метод insideLabel().

Text::make('Name')->insideLabel()
Text::make('Name')->insideLabel()

beforeLabel()

Для отображения label после поля ввода можно использовать метод beforeLabel().

Text::make('Name')->beforeLabel()
Text::make('Name')->beforeLabel()

Подсказка

Подсказка с описанием можно создать с помощью метода hint().

hint(string $hint)
hint(string $hint)

Строки подсказок экранируются по умолчанию. Используйте unescapeHint() для вывода доверенного HTML или escapeHint() для явного включения экранирования независимо от подписи и значения поля.

Number::make('Rating')
->hint('From 0 to 5')
->min(0)
->max(5)
->stars()
Number::make('Rating')
->hint('From 0 to 5')
->min(0)
->max(5)
->stars()

Полю можно добавить ссылку (например с инструкциями) link().

link(
string|Closure $link,
string|Closure $name = '',
?string $icon = null,
bool $withoutIcon = false,
bool $blank = false
)
link(
string|Closure $link,
string|Closure $name = '',
?string $icon = null,
bool $withoutIcon = false,
bool $blank = false
)
Text::make('Link')
->link('https://cutcode.dev', 'CutCode', blank: true)
Text::make('Link')
->link('https://cutcode.dev', 'CutCode', blank: true)

Badge

Для отображения поля в режиме preview в виде badge, необходимо воспользоваться методом badge().

badge(string|Color|Closure|null $color = null, string|Closure|null $icon = null)
badge(string|Color|Closure|null $color = null, string|Closure|null $icon = null)
  • $color - цвет значка,
  • $icon - иконка значка.

Доступные цвета:

primary secondary success warning error info purple pink blue green yellow red gray

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\Support\Enums\Color;
Text::make('Title')
->badge(Color::PRIMARY)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\Support\Enums\Color;
Text::make('Title')
->badge(Color::PRIMARY)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Field;
Text::make('Title')
->badge(fn($status, Field $field) => 'green')
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Field;
Text::make('Title')
->badge(fn($status, Field $field) => 'green')

С иконкой:

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\Support\Enums\Color;
Text::make('Status')
->badge(Color::SUCCESS, 'check')
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\Support\Enums\Color;
Text::make('Status')
->badge(Color::SUCCESS, 'check')

Также можно использовать замыкание для определения иконки:

Text::make('Status')
->badge(Color::SUCCESS, fn($value, Text $ctx) => 'users')
Text::make('Status')
->badge(Color::SUCCESS, fn($value, Text $ctx) => 'users')

Горизонтально отображение

Метод horizontal() позволяет отображать название и поле горизонтально.

horizontal()
horizontal()
Text::make('Title')
->horizontal()
Text::make('Title')
->horizontal()

Обертка

Поля при отображении в формах используют специальную обертку для заголовков, подсказок, ссылок и тд. Иногда может возникнуть ситуация, когда требуется отобразить поле без дополнительных элементов. Метод withoutWrapper() позволяет отключить создание обертки.

withoutWrapper(mixed $condition = null)
withoutWrapper(mixed $condition = null)
Text::make('Title')->withoutWrapper()
Text::make('Title')->withoutWrapper()

Text wrap

Если поля в режиме предварительного просмотра не помещаются в область, выделенную им по ширине, они выходят за ее пределы. Но этим поведением можно управлять с помощью метода textWrap(), определяющего, как именно обрезать текст.

Clamp:

Text::make('Field')->textWrap(TextWrap::CLAMP)
Text::make('Field')->textWrap(TextWrap::CLAMP)

Ellipsis:

Text::make('Field')->textWrap(TextWrap::ELLIPSIS)
Text::make('Field')->textWrap(TextWrap::ELLIPSIS)

Disable:

Text::make('Field')->withoutTextWrap()
Text::make('Field')->withoutTextWrap()

По умолчанию поле Text имеет Elipsis, а Textarea имеет Clamp.

Сортировка

Для возможности сортировки поля в таблицах (на главной странице) необходимо добавить метод sortable().

sortable(Closure|string|null $callback = null)
sortable(Closure|string|null $callback = null)
Text::make('Title')->sortable()
Text::make('Title')->sortable()

Метод sortable() в качестве параметра может принимать название поля в базе данных или замыкание.

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:3]
use Illuminate\Contracts\Database\Eloquent\Builder;
use MoonShine\Laravel\Fields\Relationships\BelongsTo;
use MoonShine\UI\Fields\Text;
BelongsTo::make('Author')
->sortable('author_id'),
Text::make('Title')
->sortable(function (Builder $query, string $column, string $direction) {
$query->orderBy($column, $direction);
})
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:3]
use Illuminate\Contracts\Database\Eloquent\Builder;
use MoonShine\Laravel\Fields\Relationships\BelongsTo;
use MoonShine\UI\Fields\Text;
BelongsTo::make('Author')
->sortable('author_id'),
Text::make('Title')
->sortable(function (Builder $query, string $column, string $direction) {
$query->orderBy($column, $direction);
})

Режимы отображения

Подробнее о режимах отображения поля можно прочитать в разделе Основы > Смена режима отображения.

Режим "Default"

Чтобы поле вне зависимости от контекста всегда работало в режиме "Default" (отображение "input" поля), необходимо использовать метод defaultMode().

Text::make('Title')->defaultMode()
Text::make('Title')->defaultMode()

Режим "Preview"

Чтобы поле вне зависимости от контекста всегда работало в режиме "Preview", необходимо использовать метод previewMode().

Text::make('Title')->previewMode()
Text::make('Title')->previewMode()

Режим "RawMode"

Чтобы поле вне зависимости от контекста всегда работало в режиме "RawMode" (отображение исходного состояния), необходимо использовать метод rawMode().

Text::make('Title')->rawMode()
Text::make('Title')->rawMode()

Атрибуты

Основные html атрибуты, такие как required, disabled и readonly, у поля необходимо задавать через соответствующие методы.

required(Closure|bool|null $condition = null)
required(Closure|bool|null $condition = null)
Text::make('Title')->required()
Text::make('Title')->required()
disabled(Closure|bool|null $condition = null)
disabled(Closure|bool|null $condition = null)
Text::make('Title')->disabled()
Text::make('Title')->disabled()
readonly(Closure|bool|null $condition = null)
readonly(Closure|bool|null $condition = null)
Text::make('Title')->readonly()
Text::make('Title')->readonly()

Другие атрибуты

Чтобы указать любые другие атрибуты, используется метод customAttributes().

Поля являются компонентами, подробнее об атрибутах читайте в разделе Атрибуты компонентов.

customAttributes(
array $attributes,
bool $override = false
)
customAttributes(
array $attributes,
bool $override = false
)
  • $attributes - массив атрибутов,
  • $override - для добавления атрибутов к полю, используется merge. Если атрибут, который вы хотите добавить к полю, уже присутствует, то он добавлен не будет. $override = true позволяет изменить данное поведение и перезаписать уже добавленный атрибут.
Password::make('Title')
->customAttributes(['autocomplete' => 'off'])
Password::make('Title')
->customAttributes(['autocomplete' => 'off'])

Атрибуты для wrapper поля

Метод wrapperClass() добавляет обёртке класс или несколько, если передать массив.

wrapperClass(string|array $classes);
wrapperClass(string|array $classes);
Text::make('name')
->wrapperClass('my-input');
Text::make('name')
->wrapperClass('my-input');

Метод removeWrapperClass() удаляет класс обёртки. Можно передать паттерн для удаления нескольких классов (через функцию preg_replace).

removeWrapperClass(string $pattern);
removeWrapperClass(string $pattern);
Text::make('name')
->removeWrapperClass('my-input');
Text::make('name')
->removeWrapperClass('my-input');
Text::make('name')
->removeWrapperClass('text-(success|primary)');
Text::make('name')
->removeWrapperClass('text-(success|primary)');

Метод wrapperStyle() добавляет CSS-стили.

wrapperStyle(string|array $styles);
wrapperStyle(string|array $styles);
Text::make('name')
->wrapperStyle('width: 100px');
Text::make('name')
->wrapperStyle('width: 100px');

Метод customWrapperAttributes() позволяет добавить любые атрибуты для обертки поля.

customWrapperAttributes(array $attributes);
customWrapperAttributes(array $attributes);
Text::make('Name')
->customWrapperAttributes(['data-handle' => 'handle']);
Text::make('Name')
->customWrapperAttributes(['data-handle' => 'handle']);

Метод removeWrapperAttribute() удаляет атрибут у обёртки.

removeWrapperAttribute(string $name);
removeWrapperAttribute(string $name);
Text::make('Name')
->removeWrapperAttribute('data-handle');
Text::make('Name')
->removeWrapperAttribute('data-handle');

Модифицирование атрибута "name"

Так как атрибут name генерируется на основе вложенности и имеет сложную логику формирования, то для его изменения требуется воспользоваться методом setNameAttribute().

Text::make('Name')
->setNameAttribute('custom_name')
Text::make('Name')
->setNameAttribute('custom_name')

wrapName

Для того чтобы добавить wrapper для значения атрибута name, используется метод wrapName().

Text::make('Name')
->wrapName('options')
Text::make('Name')
->wrapName('options')

В результате атрибут name примет вид <input name="options[name]>. Это особенно полезно для настройки фильтров.

virtualName

Иногда необходимо хранить по одному полю ввода два значения Field. Например, по условию отображение одно из полей может становиться невидимым, но присутствовать в DOM и отправляться вместе с запросом.

// это поле отображается в DOM на одном условии
File::make('image')
// это поле отображается в DOM на другом условии
File::make('image')
// это поле отображается в DOM на одном условии
File::make('image')
// это поле отображается в DOM на другом условии
File::make('image')

Для того чтобы изменить атрибут name у этих полей, используется метод virtualName().

File::make('image')
->virtualColumn('image_1')
// ...
File::make('image')
->virtualColumn('image_2')
File::make('image')
->virtualColumn('image_1')
// ...
File::make('image')
->virtualColumn('image_2')

Далее, например в onApply() методе, мы обрабатываем эти поля по своему усмотрению.

Модифицирование значения поля

Значение по умолчанию

Для указания значения по умолчанию используется метод default().

default(mixed $default)
default(mixed $default)
Text::make('Name')
->default('Default value')
Text::make('Name')
->default('Default value')
Enum::make('Status')
->attach(ColorEnum::class)
->default(ColorEnum::from('B')->value)
Enum::make('Status')
->attach(ColorEnum::class)
->default(ColorEnum::from('B')->value)

Nullable

Если необходимо у поля по умолчанию сохранять NULL, то необходимо использовать метод nullable().

nullable(Closure|bool|null $condition = null)
nullable(Closure|bool|null $condition = null)
Password::make('Title')->nullable()
Password::make('Title')->nullable()

Изменение отображения

Когда необходимо изменить view с помощью fluent interface можно воспользоваться методом customView().

customView(string $view, array $data = [])
customView(string $view, array $data = [])
Text::make('Title')
->customView('fields.my-custom-input')
Text::make('Title')
->customView('fields.my-custom-input')

Метод changePreview() позволяет переопределить view для превью (везде кроме формы).

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\UI\Components\Thumbnails;
use MoonShine\UI\Fields\Text;
Text::make('Thumbnail')
->changePreview(function (?string $value, Text $field) {
return Thumbnails::make($value);
})
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\UI\Components\Thumbnails;
use MoonShine\UI\Fields\Text;
Text::make('Thumbnail')
->changePreview(function (?string $value, Text $field) {
return Thumbnails::make($value);
})

Хук до рендера

Если вам необходимо получить доступ к полю непосредственно перед рендером, для этого можно воспользоваться методом onBeforeRender().

/**
* @param Closure(static $ctx): void $onBeforeRender
*/
onBeforeRender(Closure $onBeforeRender)
/**
* @param Closure(static $ctx): void $onBeforeRender
*/
onBeforeRender(Closure $onBeforeRender)
Text::make('Thumbnail')
->onBeforeRender(function(Text $ctx) {
// ...
})
Text::make('Thumbnail')
->onBeforeRender(function(Text $ctx) {
// ...
})

Получение значения из запроса

Метод onRequestValue() позволяет переопределить логику получения значения из Request.

/**
* @param Closure(mixed $value, string $name, mixed $default, static $ctx): mixed $callback
*/
onRequestValue(Closure $callback)
/**
* @param Closure(mixed $value, string $name, mixed $default, static $ctx): mixed $callback
*/
onRequestValue(Closure $callback)
  • $value - значение полученное по умолчанию,
  • $name - наименование параметра запроса,
  • $default - значение поля по умолчанию, при отсутствии в запросе,
  • $ctx - текущее поле,

Статический метод requestValueResolver() позволяет глобально переопределить логику получения значения из Request для всех полей.

/**
* @param Closure(string|int|null $index, mixed $default, static $ctx): mixed $resolver
*/
requestValueResolver(Closure $resolver)
/**
* @param Closure(string|int|null $index, mixed $default, static $ctx): mixed $resolver
*/
requestValueResolver(Closure $resolver)
FormElement::requestValueResolver(function (string|int|null $index, mixed $default, static $ctx): mixed {
return request()->input($ctx->getRequestNameDot($index), $default);
})
FormElement::requestValueResolver(function (string|int|null $index, mixed $default, static $ctx): mixed {
return request()->input($ctx->getRequestNameDot($index), $default);
})

До и после рендеринга

Методы beforeRender() и afterRender() позволяют вывести какую-то информацию перед и после поля соответственно.

beforeRender(Closure $closure)
afterRender(Closure $closure)
beforeRender(Closure $closure)
afterRender(Closure $closure)

Строковые результаты экранируются по умолчанию. Используйте unescapeBeforeRender() и unescapeAfterRender() для вывода доверенных HTML-строк. Соответствующие методы escapeBeforeRender() и escapeAfterRender() явно включают экранирование. Возвращаемые объекты Renderable, например представления, сохраняют своё поведение при рендеринге. Подробнее: Экранирование отображаемого текста.

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\UI\Fields\Field;
use MoonShine\UI\Fields\Text;
Text::make('Title')
->beforeRender(function(Field $field) {
return $field->preview();
})
->unescapeBeforeRender()
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\UI\Fields\Field;
use MoonShine\UI\Fields\Text;
Text::make('Title')
->beforeRender(function(Field $field) {
return $field->preview();
})
->unescapeBeforeRender()

Условные методы

Отображать компонент можно по условию, воспользовавшись методом canSee().

Text::make('Name')
->canSee(function (Text $field) {
return $field->toValue() !== 'hide';
})
Text::make('Name')
->canSee(function (Text $field) {
return $field->toValue() !== 'hide';
})
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\Laravel\Fields\Relationships\BelongsTo;
// или для полей отношений
BelongsTo::make('Item', 'item', resource: ItemResource::class)
->canSee(function (Comment $comment, BelongsTo $field) {
// ваше условие
})
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\Laravel\Fields\Relationships\BelongsTo;
// или для полей отношений
BelongsTo::make('Item', 'item', resource: ItemResource::class)
->canSee(function (Comment $comment, BelongsTo $field) {
// ваше условие
})

Метод when() реализует fluent interface и выполнит callback, когда первый аргумент, переданный методу, имеет значение true.

when(
$value = null,
?callable $callback = null,
?callable $default = null
)
when(
$value = null,
?callable $callback = null,
?callable $default = null
)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Field;
Text::make('Slug')
->when(
fn() => true,
fn(Field $field) => $field->locked()
)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Field;
Text::make('Slug')
->when(
fn() => true,
fn(Field $field) => $field->locked()
)

Метод unless() обратный методу when().

unless(
$value = null,
?callable $callback = null,
?callable $default = null
)
unless(
$value = null,
?callable $callback = null,
?callable $default = null
)

Apply

У каждого поля реализован метод apply(), который трансформирует данные. Чтобы переопределить стандартный apply у поля, можно воспользоваться методом onApply(). Подробнее о цикле жизни применения поля можно прочитать в разделе Основы > Процесс применения полей.

/**
* @param Closure(mixed, mixed, FieldContract): mixed $onApply
*/
onApply(Closure $onApply)
/**
* @param Closure(mixed, mixed, FieldContract): mixed $onApply
*/
onApply(Closure $onApply)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:3]
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
use MoonShine\UI\Fields\Text;
Text::make('Thumbnail by link', 'thumbnail')
->onApply(function(Model $item, $value, Field $field) {
$path = 'thumbnail.jpg';
if ($value) {
$item->thumbnail = Storage::put($path, file_get_contents($value));
}
return $item;
})
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:3]
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
use MoonShine\UI\Fields\Text;
Text::make('Thumbnail by link', 'thumbnail')
->onApply(function(Model $item, $value, Field $field) {
$path = 'thumbnail.jpg';
if ($value) {
$item->thumbnail = Storage::put($path, file_get_contents($value));
}
return $item;
})

Пример onApply для фильтров:

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\UI\Fields\Text;
use Illuminate\Contracts\Database\Eloquent\Builder;
Text::make('Title')
->onApply(function (Builder $query, mixed $value, Text $field) {
$query->where('title', $value);
})
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\UI\Fields\Text;
use Illuminate\Contracts\Database\Eloquent\Builder;
Text::make('Title')
->onApply(function (Builder $query, mixed $value, Text $field) {
$query->where('title', $value);
})

Для того чтобы выполнить какие-либо действия до "apply", можно воспользоваться методом onBeforeApply().

/**
* @param Closure(mixed, mixed, FieldContract): static $onBeforeApply
*/
onBeforeApply(Closure $onBeforeApply)
/**
* @param Closure(mixed, mixed, FieldContract): static $onBeforeApply
*/
onBeforeApply(Closure $onBeforeApply)

Для того чтобы выполнить какие-либо действия после "apply", можно воспользоваться методом onAfterApply().

/**
* @param Closure(mixed, mixed, FieldContract): static $onBeforeApply
*/
onAfterApply(Closure $onBeforeApply)
/**
* @param Closure(mixed, mixed, FieldContract): static $onBeforeApply
*/
onAfterApply(Closure $onBeforeApply)

Выполнять метод apply() можно по условию, воспользовавшись методом canApply().

canApply(Closure $canApply)
canApply(Closure $canApply)
Text::make('Title')
->canApply(fn() => false)
Text::make('Title')
->canApply(fn() => false)

Метод refreshAfterApply() инициирует ререндер поля после "применения". Так же можно влиять на этот процесс через колбэк.

refreshAfterApply(?Closure $callback = null)
refreshAfterApply(?Closure $callback = null)
Text::make('Title')
->refreshAfterApply(fn(Text $ctx) => $ctx)
Text::make('Title')
->refreshAfterApply(fn(Text $ctx) => $ctx)

У полей File эта функция включена по умолчанию для обновления "preview". Это поведение можно отключить с помощью метода disableRefreshAfterApply() или переопределить в соответствии со своей логикой.

Image::make('Avatar')
->disableRefreshAfterApply()
Image::make('Avatar')
->disableRefreshAfterApply()
Image::make('Avatar')
->refreshAfterApply(fn(Image $ctx) => $ctx)
Image::make('Avatar')
->refreshAfterApply(fn(Image $ctx) => $ctx)

Глобальное определение apply логики

Если вы хотите глобально для определенного поля изменить логику apply, то вы можете создать apply класс и привязать его к необходимому полю.

Для начала создайте apply класс:

php artisan moonshine:apply FileModelApply
php artisan moonshine:apply FileModelApply

О всех поддерживаемых опциях можно узнать в разделе Команды.

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\Contracts\UI\ApplyContract;
use MoonShine\Contracts\UI\FieldContract;
/**
* @implements ApplyContract<File>
*/
final class FileModelApply implements ApplyContract
{
/**
* @param File $field
*/
public function apply(FieldContract $field): Closure
{
return function (mixed $item) use ($field): mixed {
$requestValue = $field->getRequestValue();
$newValue = // ...
return data_set($item, $field->getColumn(), $newValue);
};
}
}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\Contracts\UI\ApplyContract;
use MoonShine\Contracts\UI\FieldContract;
/**
* @implements ApplyContract<File>
*/
final class FileModelApply implements ApplyContract
{
/**
* @param File $field
*/
public function apply(FieldContract $field): Closure
{
return function (mixed $item) use ($field): mixed {
$requestValue = $field->getRequestValue();
$newValue = // ...
return data_set($item, $field->getColumn(), $newValue);
};
}
}

Далее зарегистрируйте его для поля:

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:start]
use App\MoonShine\Applies\FileModelApply;
use Illuminate\Support\ServiceProvider;
use MoonShine\Contracts\Core\DependencyInjection\AppliesRegisterContract;
use MoonShine\Contracts\Core\DependencyInjection\CoreContract;
use MoonShine\Contracts\Core\DependencyInjection\ConfiguratorContract;
use MoonShine\Laravel\DependencyInjection\MoonShine;
use MoonShine\Laravel\DependencyInjection\MoonShineConfigurator;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Applies\AppliesRegister;
use MoonShine\UI\Fields\File; // [tl! collapse:end]
class MoonShineServiceProvider extends ServiceProvider
{
/**
* @param MoonShine $core
* @param MoonShineConfigurator $config
* @param AppliesRegister $applies
*
*/
public function boot(
CoreContract $core,
ConfiguratorContract $config,
AppliesRegisterContract $applies,
): void
{
$applies
// resource group, default ModelResource
->for(ModelResource::class)
// type fields or filters
->fields()
->add(File::class, FileModelApply::class);
}
}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:start]
use App\MoonShine\Applies\FileModelApply;
use Illuminate\Support\ServiceProvider;
use MoonShine\Contracts\Core\DependencyInjection\AppliesRegisterContract;
use MoonShine\Contracts\Core\DependencyInjection\CoreContract;
use MoonShine\Contracts\Core\DependencyInjection\ConfiguratorContract;
use MoonShine\Laravel\DependencyInjection\MoonShine;
use MoonShine\Laravel\DependencyInjection\MoonShineConfigurator;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Applies\AppliesRegister;
use MoonShine\UI\Fields\File; // [tl! collapse:end]
class MoonShineServiceProvider extends ServiceProvider
{
/**
* @param MoonShine $core
* @param MoonShineConfigurator $config
* @param AppliesRegister $applies
*
*/
public function boot(
CoreContract $core,
ConfiguratorContract $config,
AppliesRegisterContract $applies,
): void
{
$applies
// resource group, default ModelResource
->for(ModelResource::class)
// type fields or filters
->fields()
->add(File::class, FileModelApply::class);
}
}

Заполнение

Поля можно заполнить значениями, используя метод fill(). Более подробно о процессе заполнения поля можно прочитать в разделе Основы > Изменить наполнение.

fill(
mixed $value = null,
?DataWrapperContract $casted = null,
int $index = 0
)
fill(
mixed $value = null,
?DataWrapperContract $casted = null,
int $index = 0
)
Text::make('Title')
->fill('Some title')
Text::make('Title')
->fill('Some title')

Изменение логики наполнения поля

Для того чтобы изменить логику заполнения поля, можно использовать метод changeFill().

Select::make('Images')->options([
'/images/1.png' => 'Picture 1',
'/images/2.png' => 'Picture 2',
])
->multiple()
->changeFill(
fn(Article $article, Select $ctx) => $article->images
->map(fn($value) => "https://cutcode.dev$value")
->toArray()
);
Select::make('Images')->options([
'/images/1.png' => 'Picture 1',
'/images/2.png' => 'Picture 2',
])
->multiple()
->changeFill(
fn(Article $article, Select $ctx) => $article->images
->map(fn($value) => "https://cutcode.dev$value")
->toArray()
);

В данном примере к путям изображений будет добавлено https://cutcode.dev.

Действия после наполнения поля

Для применения логики к уже наполненному полю можно использовать метод afterFill().

Похожий по логике метод when срабатывает в момент создания экземпляра поля, когда оно еще не наполнено. Метод afterFill() работает уже с наполненным полем.

Select::make('Links')->options([
'/images/1.png' => 'Picture 1',
'/images/2.png' => 'Picture 2',
])
->multiple()
->afterFill(
function(Select $ctx) {
if(collect($ctx->toValue())->every(fn($value) => str_contains($value, 'cutcode.dev'))) {
return $ctx->customWrapperAttributes(['class' => 'full-url']);
}
return $ctx;
}
)
Select::make('Links')->options([
'/images/1.png' => 'Picture 1',
'/images/2.png' => 'Picture 2',
])
->multiple()
->afterFill(
function(Select $ctx) {
if(collect($ctx->toValue())->every(fn($value) => str_contains($value, 'cutcode.dev'))) {
return $ctx->customWrapperAttributes(['class' => 'full-url']);
}
return $ctx;
}
)

Методы onChange

С помощью методов onChangeMethod() и onChangeUrl() можно добавить логику при изменении значений полей.

Методы onChangeUrl() или onChangeMethod() присутствуют у всех полей, кроме полей отношений HasOne и HasMany.

onChangeUrl()

onChangeUrl(
Closure $url,
HttpMethod $method = HttpMethod::GET,
array $events = [],
?string $selector = null,
?AsyncCallback $callback = null
)
onChangeUrl(
Closure $url,
HttpMethod $method = HttpMethod::GET,
array $events = [],
?string $selector = null,
?AsyncCallback $callback = null
)
  • $url - url запроса,
  • $method - метод асинхронного запроса,
  • $events - вызываемые AlpineJS события после успешного запроса,
  • $selector - selector элемента у которого будет изменяться контент,
  • $callback - js callback функция после получения ответа.
Switcher::make('Active')
->onChangeUrl(fn() => '/endpoint')
Switcher::make('Active')
->onChangeUrl(fn() => '/endpoint')

Если требуется заменить область с html после успешного запроса, вы можете в ответе вернуть HTML контент или json с ключом html.

Switcher::make('Active')
->onChangeUrl(fn() => '/endpoint', selector: '#my-selector')
Switcher::make('Active')
->onChangeUrl(fn() => '/endpoint', selector: '#my-selector')

onChangeMethod()

Метод onChangeMethod() позволяет асинхронно вызывать метод ресурса или страницы при изменении поля без необходимости создавать дополнительные контроллеры.

onChangeMethod(
string $method,
array|Closure $params = [],
?string $message = null,
?string $selector = null,
array $events = [],
?AsyncCallback $callback = null,
?PageContract $page = null,
?ResourceContract $resource = null
)
onChangeMethod(
string $method,
array|Closure $params = [],
?string $message = null,
?string $selector = null,
array $events = [],
?AsyncCallback $callback = null,
?PageContract $page = null,
?ResourceContract $resource = null
)
  • $method - наименование метода,
  • $params - параметры для запроса,
  • $message - сообщения,
  • $selector - selector элемента у которого будет изменяться контент,
  • $events - вызываемые AlpineJS события после успешного запроса,
  • $callback - js callback функция после получения ответа,
  • $page - страница содержащая метод,
  • $resource - ресурс содержащий метод.
Switcher::make('Active')
->onChangeMethod('someMethod')
Switcher::make('Active')
->onChangeMethod('someMethod')
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\Contracts\Core\DependencyInjection\CrudRequestContract;
#[AsyncMethod]
public function someMethod(CrudRequestContract $request): void
{
// Logic
}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\Contracts\Core\DependencyInjection\CrudRequestContract;
#[AsyncMethod]
public function someMethod(CrudRequestContract $request): void
{
// Logic
}

Изменение render поля

Чтобы полностью изменить render поля, можно воспользоваться методом changeRender().

changeRender(Closure $callback)
changeRender(Closure $callback)

В данном поле Select трансформируется в текст:

Select::make('Links')->options([
'/images/1.png' => 'Picture 1',
'/images/2.png' => 'Picture 2',
])
->multiple()
->changeRender(
fn(?array $values, Select $ctx) => Text::make($ctx->getLabel())->fill(implode(',', $values))
)
Select::make('Links')->options([
'/images/1.png' => 'Picture 1',
'/images/2.png' => 'Picture 2',
])
->multiple()
->changeRender(
fn(?array $values, Select $ctx) => Text::make($ctx->getLabel())->fill(implode(',', $values))
)

Методы для значений

Получение значение из исходного

Метод fromRaw() позволяет добавить замыкание для получения итоговое значение из исходного.

/**
* @param Closure(mixed $raw, static): mixed $callback
* @return $this
*/
fromRaw(Closure $callback)
/**
* @param Closure(mixed $raw, static): mixed $callback
* @return $this
*/
fromRaw(Closure $callback)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use App\Enums\StatusEnum;
use MoonShine\UI\Fields\Enum;
Enum::make('Status')
->attach(StatusEnum::class)
->fromRaw(fn(string $raw, Enum $ctx) => StatusEnum::tryFrom($raw))
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use App\Enums\StatusEnum;
use MoonShine\UI\Fields\Enum;
Enum::make('Status')
->attach(StatusEnum::class)
->fromRaw(fn(string $raw, Enum $ctx) => StatusEnum::tryFrom($raw))

Получения необработанного значения

Метод modifyRawValue() позволяет добавить замыкание для получения необработанного значения.

/**
* @param Closure(mixed $raw, mixed $data, static): mixed $callback
* @return $this
*/
modifyRawValue(Closure $callback)
/**
* @param Closure(mixed $raw, mixed $data, static): mixed $callback
* @return $this
*/
modifyRawValue(Closure $callback)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use App\Enums\StatusEnum;
use MoonShine\UI\Fields\Enum;
Enum::make('Status')
->attach(StatusEnum::class)
->modifyRawValue(fn(StatusEnum $raw, Order $data, Enum $ctx) => $raw->value))
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use App\Enums\StatusEnum;
use MoonShine\UI\Fields\Enum;
Enum::make('Status')
->attach(StatusEnum::class)
->modifyRawValue(fn(StatusEnum $raw, Order $data, Enum $ctx) => $raw->value))

Редактирование в режиме preview

Редактирование в режиме preview доступно для полей Text, Number, Checkbox, Select и Date.

Для редактирования полей в режиме preview, например в таблице или в любом другом IterableComponent, существуют следующие методы.

updateOnPreview

Метод updateOnPreview() позволяет редактировать поле в режиме предварительного просмотра. После внесения изменений (по событию onChange), значение поля будет сохранено для конкретного элемента.

updateOnPreview(
?Closure $url = null,
?ResourceContract $resource = null,
mixed $condition = null,
array $events = []
)
updateOnPreview(
?Closure $url = null,
?ResourceContract $resource = null,
mixed $condition = null,
array $events = []
)
  • $url - (опционально) url запроса,
  • $resource - (опционально) ресурс содержащий updateOnPreview,
  • $condition - (опционально) условие установки поля в режим updateOnPreview,
  • $events - (опционально) вызываемые AlpineJS события после успешного запроса.

Параметры не являются обязательными, но должны быть заданы, если поле находится вне ресурса или же вы хотите указать полностью свой endpoint (тогда и ресурс не нужен).

Text::make('Name')->updateOnPreview()
Text::make('Name')->updateOnPreview()

withUpdateRow

withUpdateRow() работает по аналогии с updateOnPreview(), но при этом может полностью обновить строку в таблице без перезагрузки страницы.

withUpdateRow(string $component)
withUpdateRow(string $component)
  • $component - имя компонента, в котором присутствует данная строка.
Text::make('Name')
->withUpdateRow('index-table-post-resource')
Text::make('Name')
->withUpdateRow('index-table-post-resource')

withUpdateRow() может использовать все параметры updateOnPreview(), например для изменения url запроса, для этого их необходимо вызвать вместе.

Text::make('Name')
->updateOnPreview(url: '/my/url')
->withUpdateRow()
Text::make('Name')
->updateOnPreview(url: '/my/url')
->withUpdateRow()

updateInPopover

Метод updateInPopover() работает аналогично методу withUpdateRow(), но теперь все значения для редактирования появляются в отдельном окне.

updateInPopover(string $component)
updateInPopover(string $component)
  • $component - имя компонента, в котором присутствует данная строка.
Text::make('Name')
->updateInPopover('index-table-post-resource')
Text::make('Name')
->updateInPopover('index-table-post-resource')

Методы updateOnPreview(), withUpdateRow() и updateInPopover() формируют нужные endpoints и передают методу setUpdateOnPreviewUrl(), который работает с onChangeUrl().

Ассеты

Для добавления ассетов к полю можно использовать метод addAssets().

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use Illuminate\Support\Facades\Vite;
use MoonShine\AssetManager\Css;
Text::make('Name')
->addAssets([
new Css(Vite::asset('resources/css/text-field.css'))
])
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use Illuminate\Support\Facades\Vite;
use MoonShine\AssetManager\Css;
Text::make('Name')
->addAssets([
new Css(Vite::asset('resources/css/text-field.css'))
])

Если вы реализуете собственное поле, то объявить набор ассетов в нем можно двумя способами.

  1. Через метод assets():
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\AssetManager\Css;
use MoonShine\AssetManager\Js;
/**
* @return list<AssetElementContract>
*/
protected function assets(): array
{
return [
Js::make('/js/custom.js'),
Css::make('/css/styles.css')
];
}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\AssetManager\Css;
use MoonShine\AssetManager\Js;
/**
* @return list<AssetElementContract>
*/
protected function assets(): array
{
return [
Js::make('/js/custom.js'),
Css::make('/css/styles.css')
];
}
  1. Через метод booted():
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\AssetManager\Css;
use MoonShine\AssetManager\Js;
protected function booted(): void
{
parent::booted();
$this->getAssetManager()
->add(Css::make('/css/app.css'))
->append(Js::make('/js/app.js'));
}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:2]
use MoonShine\AssetManager\Css;
use MoonShine\AssetManager\Js;
protected function booted(): void
{
parent::booted();
$this->getAssetManager()
->add(Css::make('/css/app.css'))
->append(Js::make('/js/app.js'));
}

Трейт Macroable

Всем полям доступен трейт Illuminate\Support\Traits\Macroable с методами mixin() и macro(). С помощью этого трейта вы можете расширять возможности полей, добавляя в них новый функционал без использования наследования.

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Field;
Field::macro('myMethod', fn() => /*реализация*/)
Text::make()->myMethod()
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Field;
Field::macro('myMethod', fn() => /*реализация*/)
Text::make()->myMethod()
Field::mixin(new MyNewMethods())
Field::mixin(new MyNewMethods())

Реактивность

Метод reactive() позволяет реактивно изменять поля.

reactive(
?Closure $callback = null,
bool $lazy = false,
int $debounce = 0,
int $throttle = 0,
bool|Closure $silent = false,
bool|Closure $silentSelf = false,
)
reactive(
?Closure $callback = null,
bool $lazy = false,
int $debounce = 0,
int $throttle = 0,
bool|Closure $silent = false,
bool|Closure $silentSelf = false,
)
  • $callback - callback функция,
  • $lazy - отложенный вызов функции,
  • $debounce - время между вызовами функций (ms.),
  • $throttle - интервал вызова функций (ms.),
  • $silent - пропустить перерендеринг поля при изменениях,
  • $silentSelf - пропустить перерендеринг поля, если оно в данный момент редактируется.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:3]
use MoonShine\UI\Collections\Fields;
use MoonShine\UI\Components\FormBuilder;
use MoonShine\UI\Fields\Text;
FormBuilder::make()
->name('my-form')
->fields([
Text::make('Title')
->reactive(function(Fields $fields, ?string $value): Fields {
return tap($fields, static fn ($fields) => $fields
->findByColumn('slug')
?->setValue(str($value ?? '')->slug()->value())
);
}),
Text::make('Slug')
->reactive()
])
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:3]
use MoonShine\UI\Collections\Fields;
use MoonShine\UI\Components\FormBuilder;
use MoonShine\UI\Fields\Text;
FormBuilder::make()
->name('my-form')
->fields([
Text::make('Title')
->reactive(function(Fields $fields, ?string $value): Fields {
return tap($fields, static fn ($fields) => $fields
->findByColumn('slug')
?->setValue(str($value ?? '')->slug()->value())
);
}),
Text::make('Slug')
->reactive()
])

В данном пример реализовано формирование slug-поля на основе заголовка. Slug будет генерироваться в процессе ввода текста.

Реактивное поле может менять состояние других полей, но не изменяет свое состояние!

Для изменения состояния поля инициирующего реактивность удобно воспользоваться параметрами callback-функции.

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:3]
use MoonShine\UI\Fields\Field;
use MoonShine\UI\Fields\Select;
use MoonShine\UI\Collections\Fields;
Select::make('Category', 'category_id')
->reactive(function(Fields $fields, ?string $value, Field $field, array $values): Fields {
$field->setValue($value);
return tap($fields, static fn ($fields) =>
$fields
->findByColumn('article_id')
?->options(
Article::where('category_id', $value)
->get()
->pluck('title', 'id')
->toArray()
);
);
})
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:3]
use MoonShine\UI\Fields\Field;
use MoonShine\UI\Fields\Select;
use MoonShine\UI\Collections\Fields;
Select::make('Category', 'category_id')
->reactive(function(Fields $fields, ?string $value, Field $field, array $values): Fields {
$field->setValue($value);
return tap($fields, static fn ($fields) =>
$fields
->findByColumn('article_id')
?->options(
Article::where('category_id', $value)
->get()
->pluck('title', 'id')
->toArray()
);
);
})

Пропуск перерендеринга поля

Параметр silentSelf позволяет пропустить перерендеринг поля, если оно в данный момент редактируется. Это полезно, когда вы не хотите, чтобы редактируемое поле теряло фокус или сбрасывало введённые данные.

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Select;
Select::make('Select 1')->reactive(silentSelf: true),
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Select;
Select::make('Select 1')->reactive(silentSelf: true),

Параметр silent позволяет полностью пропустить перерендеринг поля при любых изменениях.

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Select;
Select::make('Select 2')->reactive(silent: true),
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Select;
Select::make('Select 2')->reactive(silent: true),

Оба параметра также могут принимать callback-функцию для условного управления:

// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Select;
// Пропустить перерендеринг себя при определённом значении
Select::make('Select 1')->reactive(
silentSelf: fn(string $value, array $values, Select $ctx): bool => $value === 'Option 2'
),
// Пропустить перерендеринг при определённом значении другого поля
Select::make('Select 2')->reactive(
silent: fn(string $value, array $values, Select $ctx): bool => $values['select1'] === 'Option 2'
),
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:1]
use MoonShine\UI\Fields\Select;
// Пропустить перерендеринг себя при определённом значении
Select::make('Select 1')->reactive(
silentSelf: fn(string $value, array $values, Select $ctx): bool => $value === 'Option 2'
),
// Пропустить перерендеринг при определённом значении другого поля
Select::make('Select 2')->reactive(
silent: fn(string $value, array $values, Select $ctx): bool => $values['select1'] === 'Option 2'
),

Динамическое отображение

Поля можно скрывать или показывать динамически, в зависимости от значений других полей в реальном времени без перезагрузки страницы и запросов к серверу. Для этого используются методы showWhen() и showWhenDate().

Метод showWhen

Метод showWhen() позволяет задать условие отображения поля в зависимости от значения другого поля.

showWhen(
string $column,
mixed $operator = null,
mixed $value = null
)
showWhen(
string $column,
mixed $operator = null,
mixed $value = null
)
  • $column - имя поля, от которого зависит отображение,
  • $operator - оператор сравнения (необязательный),
  • $value - значение для сравнения.

Параметр $column работает на основе атрибута name поля в DOM. Если форма добавляет префиксы к полям (например, в фильтрах), то name будет иметь вид filter[column], и в showWhen нужно указывать 'filter.column'. Для итерируемых элементов с индексами (например, name="attributes[0][column]") параметр $column должен соответствовать структуре: 'attributes.0.column'.

Text::make('Name')
->showWhen('category_id', 1)
Text::make('Name')
->showWhen('category_id', 1)

В этом примере поле "Name" будет отображаться только если значение поля "category_id" равно 1.

Если в функции showWhen передается только два параметра, то по умолчанию используется оператор '='.

Text::make('Name')
->showWhen('category_id', 'in', [1, 2, 3])
Text::make('Name')
->showWhen('category_id', 'in', [1, 2, 3])

В этом примере поле "Name" будет отображаться только если значение поля "category_id" равно 1, 2 или 3.

Когда на поле присутствует условие showWhen, то при скрытии этого поля, на его DOM элемент устанавливается значение display: none и удаляется атрибут name, чтобы значение этого скрытого поля не попадало в итоговый запрос. Если вы не хотите, чтобы атрибут name удалялся, необходимо в вашем ресурсе установить флаг $submitShowWhen в значение true.

class ArticleResource extends ModelResource
{
protected bool $submitShowWhen = true;
// ...
}
class ArticleResource extends ModelResource
{
protected bool $submitShowWhen = true;
// ...
}

Метод showWhenDate

Метод showWhenDate() позволяет задать условие отображения поля в зависимости от значения поля типа date. Логика для работы с датами была вынесена в отдельный метод из-за специфики конвертации и сравнения типа date и datetime на backend и frontent.

showWhenDate(
string $column,
mixed $operator = null,
mixed $value = null
)
showWhenDate(
string $column,
mixed $operator = null,
mixed $value = null
)
  • $column - имя поля с датой, от которого зависит отображение,
  • $operator - оператор сравнения (необязательный),
  • $value - значение даты для сравнения.
Text::make('Content')
->showWhenDate('created_at', '>', '2024-09-15 10:00')
Text::make('Content')
->showWhenDate('created_at', '>', '2024-09-15 10:00')

В этом примере поле "Content" будет отображаться только если значение поля "created_at" больше '2024-09-15 10:00'.

Если в функции showWhenDate передается только два параметра, то по умолчанию используется оператор '='.

Вы можете использовать любой формат даты, который может быть распознан функцией strtotime().

Метод showWhenRow

Экспериментальная функция.

Метод showWhenRow() позволяет задать условие отображения поля внутри Json (табличный режим) в зависимости от значения другого поля в той же строке таблицы.

showWhenRow(
string $column,
mixed $operator = null,
mixed $value = null
)
showWhenRow(
string $column,
mixed $operator = null,
mixed $value = null
)
  • $column - имя поля в той же строке, от которого зависит отображение,
  • $operator - оператор сравнения (необязательный),
  • $value - значение для сравнения.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:3]
use MoonShine\UI\Fields\Json;
use MoonShine\UI\Fields\Select;
use MoonShine\UI\Fields\Text;
Json::make('Options')->fields([
Select::make('Type')->options([
1 => 'First',
2 => 'Second',
]),
Text::make('Value')->showWhenRow('type', 1),
])
// torchlight! {"summaryCollapsedIndicator": "namespaces"}
// [tl! collapse:3]
use MoonShine\UI\Fields\Json;
use MoonShine\UI\Fields\Select;
use MoonShine\UI\Fields\Text;
Json::make('Options')->fields([
Select::make('Type')->options([
1 => 'First',
2 => 'Second',
]),
Text::make('Value')->showWhenRow('type', 1),
])

В этом примере поле "Value" будет отображаться только в тех строках, где значение поля "Type" равно 1.

Если в функции showWhenRow передается только два параметра, то по умолчанию используется оператор '='.

Метод showWhenRow() работает только внутри поля Json в табличном режиме.

Вложенные поля

Методы showWhen() и showWhenDate() поддерживают работу с вложенными полями, например для работы с полем Json. Для обращения к вложенным полям используется точечная нотация.

Text::make('Parts')
->showWhen('attributes.1.size', '!=', 2)
Text::make('Parts')
->showWhen('attributes.1.size', '!=', 2)

В этом примере поле "Parts" будет отображаться только если значение вложенного поля "size" во втором элементе массива "attributes" не равно 2.

showWhen() работает и для вложенных полей типа Json:

Json::make('Attributes', 'attributes')->fields([
Text::make('Size'),
Text::make('Parts')
->showWhen('category_id', 3),
Json::make('Settings', 'settings')->fields([
Text::make('Width')
->showWhen('category_id', 3),
Text::make('Height'),
])
]),
Json::make('Attributes', 'attributes')->fields([
Text::make('Size'),
Text::make('Parts')
->showWhen('category_id', 3),
Json::make('Settings', 'settings')->fields([
Text::make('Width')
->showWhen('category_id', 3),
Text::make('Height'),
])
]),

В данном примере весь столбец Parts внутри attributes и весь столбец Width внутри attributes.[n].settings будет отображаться только если значение поля category_id равно 3.

Множественные условия

Методы showWhen() и showWhenDate() могут быть вызваны несколько раз для одного поля, что позволяет задать несколько условий отображения.

BelongsTo::make('Category', 'category', resource: CategoryResource::class)
->showWhenDate('created_at', '>', '2024-08-05 10:00')
->showWhenDate('created_at', '<', '2024-08-05 19:00')
BelongsTo::make('Category', 'category', resource: CategoryResource::class)
->showWhenDate('created_at', '>', '2024-08-05 10:00')
->showWhenDate('created_at', '<', '2024-08-05 19:00')

В этом примере поле category будет отображаться только если значение поля created_at находится в диапазоне между '2024-08-05 10:00' и '2024-08-05 19:00'.

При использовании нескольких условий они объединяются логическим "И" (AND). Поле будет отображаться только если выполняются все заданные условия.

Поддерживаемые операторы

  • =
  • !=
  • >
  • <
  • >=
  • <=
  • in
  • not in

Оператор in проверяет, содержится ли значение в массиве. Оператор not in проверяет, не содержится ли значение в массиве.

Кастомное поле

Вы можете создать собственное поле, со своим view и логикой и использовать его в административной панели MoonShine. Для этого воспользуйтесь командой:

php artisan moonshine:field
php artisan moonshine:field

О всех поддерживаемых опциях можно узнать в разделе Команды.