Основы

Вы просматриваете документацию старой версии MoonShine. Рассмотрите возможность обновления вашего проекта до MoonShine 2.x.

Поля один из важнейших разделов вместе с ресурсами. В разделе ресурсы мы уже рассмотрели как регистрировать поля, а сейчас разберемся как их настраивать под свои нужды! Для удобства используется fluent интерфейс

# Make

Для начала разберемся в методе make при создании экземпляра поля

Text::make(string $label = null, string $field = null, ResourceContract|string|null $resource = null)

$label - Лейбл, заголовок поля
$field - Поле в базе (например name) или отношение (например countries)
$resource - В случае если $field - отношение, то в этом параметре необходимо указать поле в связанной таблице, которое будет отображаться во view

$resource также может быть Resource классом в котором если будет указано свойство $titleField, то поле у отношения будет определено через него

//...
class MoonShineUserResource extends Resource
{
public static string $model = MoonshineUser::class;
 
public static string $title = 'Администраторы';
 
public string $titleField = 'name';
//...

# Отображение

Поля отображаются на странице со списком (главная страница ресурса) и страница создания/редактирования. Чтобы исключить вывод поля на главной либо на странице с формой, можно воспользоваться методами hideOnIndex/hideOnForm/hideOnDetail, обратные методы showOnIndex/showOnForm/showOnDetail. Чтобы исключить только со страницы редактирования или добавления - hideOnCreate/hideOnUpdate/showOnCreate/showOnUpdate

//...
 
public function fields(): array
{
return [
Block::make('Block title', [
ID::make(),
Text::make('Заголовок', 'title')
 
->hideOnIndex()
->hideOnForm()
 
,
])
];
}
 
//...

# Отображение с условием

Метод также принимает bool, либо Closure

//...
 
public function fields(): array
{
return [
Block::make('Block title', [
ID::make(),
Text::make('Заголовок', 'title')
 
->hideOnIndex(auth()->check())
 
,
])
];
}
 
//...

# Аттрибуты

Так как на форме рендерится html элемент, то также есть возможность управлять базовыми html аттрибутами. Такими как disabled, autocomplete, readonly, multiple и тд.

//...
 
public function fields(): array
{
return [
Block::make('Block title', [
Text::make('Заголовок', 'title')
->disabled()
->hidden()
->readonly(),
];
])
}
 
//...

# Произвольные аттрибуты

//...
 
public function fields(): array
{
return [
Block::make('Block title', [
Password::make('Пароль', 'password')
->customAttributes(['autocomplete' => 'off'])
])
];
}
 
//...

# Обязательное поле

Чтобы сделать поле обязательным к заполнению, необходимо воспользоваться методом required

//...
 
public function fields(): array
{
return [
Block::make('Block title', [
Text::make('Заголовок', 'title')
->required()
])
];
}
 
//...

# Динамическое значение

//...
 
public function fields(): array
{
return [
Block::make('Block title', [
Text::make('Имя', 'first_name', fn($item) => $item->first_name . ' ' . $item->last_name)
 
// Пример если нужно разделить логику для главной и для редактирования
Text::make('Price', resource: function ($item) {
if(request()->routeIs('*.index')) {
return $item->price;
}
 
return $item->exists ? $item->price->raw() : 0;
}),
])
];
}
 
//...

# Подсказка

Полю можно добавить подсказку с описанием вызвав метод hint

//...
 
public function fields(): array
{
return [
Number::make('Rating')
->hint('From 0 to 5')
->min(0)
->max(5)
->stars()
];
}
 
//...

Полю можно добавить ссылку (например с инструкциями) addLink(string $name, string $link, bool $blank = false)

//...
 
public function fields(): array
{
return [
Text::make('Link')
->addLink('CutCode', 'https://cutcode.dev', true)
// или с анонимной функцией
->addLink('Test', function() {
if(!$this->getItem()) {
return route('admin.brands.index');
}
 
return route('admin.brands.edit', $this->getItem()->brand_id);
}),
];
}
 
//...

# Nullable

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

# Сортировка

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

//...
 
public function fields(): array
{
return [
Text::make('Заголовок', 'title')
->sortable()
];
}
 
//...

# Скрыть label

Метод fieldContainer скроет Label поля для экономии места, особенно удобно использовать совместно с декорацией Flex

//...
 
public function fields(): array
{
return [
Text::make('Заголовок', 'title')
->fieldContainer(false)
];
}
 
//...

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

Метод default если необходимо указать значение по умолчанию для поля

//...
 
public function fields(): array
{
return [
Text::make('Заголовок', 'title')
->default('-')
];
}
 
//...

# Условие отображения

Может возникнуть потребность отображать поле только в том случае, если значение у другого поля в форме имеет определенное значение (Например: отображать телефон, только если стоит галочка, что телефон есть). Для этих целей используется метод showWhen($column, $operator, $value)

Доступные операторы:

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

Если оператор не указан, то будет использоваться =

//...
 
public function fields(): array
{
return [
Phone::make('Phone', 'phone')
->showWhen('has_phone','=', 1)
// или
Phone::make('Phone', 'phone')
->showWhen('has_phone', 1)
];
}
 
//...

Если оператор имеет значение in или not in, то в $value необходимо передать массив

//...
 
public function fields(): array
{
return [
Select::make('List', 'list')->multiple()->options([
'value 1' => 'Option Label 1',
'value 2' => 'Option Label 2',
'value 3' => 'Option Label 3',
]),
 
Text::make('Name', 'name')
->showWhen('list', 'not in', ['value 1', 'value 3']),
 
Textarea::make('Content', 'content')
->showWhen('list', 'in', ['value 2', 'value 3'])
];
}
 
//...

# Возможность сохранения

//...
 
public function fields(): array
{
return [
Text::make('Заголовок', 'title')
->canSave(false)
// или
->canSave(fn() => false)
];
}
 
//...

# События

При написании собственных Fields может возникнуть потребность взаимодействовать с событиями до и после сохранения, для этого в вашем кастомном поле необходимо реализовать соответствующие методы

public function beforeSave(Model $item): void
{
//
}
 
public function afterSave(Model $item): void
{
//
}

# Смена view

Иногда имеет смысл изменить view с помощью fluent interface (Как пример если используете фильтры или поля вне MoonShine)

Text::make('Title')
->customView('fields.my-custom-input'),

# Методы по условию

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

Text::make('Slug')
->when(isset($this->getItem()->id), fn(Text $field) => $field->locked()),

Экземпляр поля, будет передан в функции callback.

Методу when может быть передан второй callback, он будет выполнен, когда первый аргумент, переданный методу, имеет значение false.

Text::make('Slug')
->when(
isset($this->getItem()->id),
fn(Text $field) => $field->locked(),
fn(Text $field) => $field->hidden()
),

Метод unless обратный методу when и выполнит первый callback, когда первый аргумент имеет значение false, иначе будет выполнен второй callback, если он передан методу.

Text::make('Slug')
->unless(
auth('moonshine')->user()->moonshine_user_role_id === 1,
fn(Text $field) => $field->readonly()->hideOnCreate(),
fn(Text $field) => $field->locked()
),