Models Resources

Страницы

Основы

MoonShine предоставляет возможность настройки страниц crud ModelResource, для этого необходимо при создании ресурса через команду выбрать тип ресурса Model resource with pages.

Это создаст класс ресурса модели и дополнительные классы для страниц индекса, детального просмотра и формы. Классы страниц по умолчанию будут располагаться в директории app/MoonShine/Pages.

В созданном ресурсе модели страницы crud будут зарегистрированы в методе pages().

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use App\MoonShine\Pages\Post\PostIndexPage;
use App\MoonShine\Pages\Post\PostFormPage;
use App\MoonShine\Pages\Post\PostDetailPage;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
//...
 
public function pages(): array
{
return [
PostIndexPage::make($this->title()),
PostFormPage::make(
$this->getItemID()
? __('moonshine::ui.edit')
: __('moonshine::ui.add')
),
PostDetailPage::make(__('moonshine::ui.show')),
];
}
 
//...
}

PageType

Для указания типа страницы в ModelResource используется enum класс PageType.

Доступны следующие типы страниц:

  • INDEX - страница индекса,
  • FORM - страница формы,
  • DETAIL - страница детального просмотра.
use MoonShine\Enums\PageType;
 
//...
 
PageType::INDEX;
PageType::FORM;
PageType::DETAIL;

Добавление полей

Поля в MoonShine используются не только для ввода данных, но и для их вывода.
Метод fields() в классе страницы crud позволяет указать необходимые поля.

namespace App\MoonShine\Pages\Post;
 
use MoonShine\Pages\Crud\IndexPage;
 
class PostIndexPage extends IndexPage
{
public function fields(): array
{
return [
ID::make(),
Text::make('Title'),
];
}
 
//...
}

Основные компоненты

В админ-панели MoonShine можно быстро изменить основной компонент на странице.

IndexPage

Метод itemsComponent() позволяет изменить основной компонент страницы индекса.

itemsComponent(iterable $items, Fields $fields)
  • $items - значения полей,
  • $fields - поля.
use MoonShine\Components\TableBuilder;
use MoonShine\Contracts\MoonShineRenderable;
use MoonShine\Fields\Fields;
use MoonShine\Pages\Crud\IndexPage;
 
class ArticleIndexPage extends IndexPage
{
// ...
 
protected function itemsComponent(iterable $items, Fields $fields): MoonShineRenderable
{
return TableBuilder::make(items: $items)
->name($this->listComponentName())
->fields($fields)
->cast($this->getResource()->getModelCast())
->withNotFound()
->when(
! is_null($this->getResource()->trAttributes()),
fn (TableBuilder $table): TableBuilder => $table->trAttributes(
$this->getResource()->trAttributes()
)
)
->when(
! is_null($this->getResource()->tdAttributes()),
fn (TableBuilder $table): TableBuilder => $table->tdAttributes(
$this->getResource()->tdAttributes()
)
)
->buttons($this->getResource()->getIndexItemButtons())
->customAttributes([
'data-click-action' => $this->getResource()->getClickAction(),
])
->when($this->getResource()->isAsync(), function (TableBuilder $table): void {
$table->async()->customAttributes([
'data-pushstate' => 'true',
]);
});
}
}

Пример страницы индекса с компонентом CardsBuilder в разделе Рецепты

DetailPage

Метод detailComponent() позволяет изменить основной компонент страницы детального просмотра.

detailComponent(?Model $item, Fields $fields)

-$item - Eloquent Model -$fields - поля

use Illuminate\Database\Eloquent\Model;
use Illuminate\View\ComponentAttributeBag;
use MoonShine\Components\TableBuilder;
use MoonShine\Contracts\MoonShineRenderable;
use MoonShine\Fields\Fields;
use MoonShine\Pages\Crud\DetailPage;
 
class ArticleDetailPage extends DetailPage
{
// ...
 
protected function detailComponent(?Model $item, Fields $fields): MoonShineRenderable
{
return TableBuilder::make($fields)
->cast($this->getResource()->getModelCast())
->items([$item])
->vertical()
->simple()
->preview()
->tdAttributes(fn (
$data,
int $row,
int $cell,
ComponentAttributeBag $attributes
): ComponentAttributeBag => $attributes->when(
$cell === 0,
fn (ComponentAttributeBag $attr): ComponentAttributeBag => $attr->merge([
'class' => 'font-semibold',
'width' => '20%',
])
));
}
}

FormPage

Метод formComponent() позволяет изменить основной компонент на странице с формой.

formComponent(
string $action,
?Model $item,
Fields $fields,
bool $isAsync = false,
): MoonShineRenderable

-$action - действие, -$item - Eloquent Model, -$fields - поля, -$isAsync - асинхронный режим.

use Illuminate\Database\Eloquent\Model;
use Illuminate\View\ComponentAttributeBag;
use MoonShine\Components\FormBuilder;
use MoonShine\Contracts\MoonShineRenderable;
use MoonShine\Enums\JsEvent;
use MoonShine\Fields\Fields;
use MoonShine\Fields\Hidden;
use MoonShine\Pages\Crud\FormPage;
use MoonShine\Support\AlpineJs;
 
class ArticleFormPage extends FormPage
{
// ...
 
protected function formComponent(
string $action,
?Model $item,
Fields $fields,
bool $isAsync = false,
): MoonShineRenderable {
$resource = $this->getResource();
 
return FormBuilder::make($action)
->fillCast(
$item,
$resource->getModelCast()
)
->fields(
$fields
->when(
! is_null($item),
fn (Fields $fields): Fields => $fields->push(
Hidden::make('_method')->setValue('PUT')
)
)
->when(
! $item?->exists && ! $resource->isCreateInModal(),
fn (Fields $fields): Fields => $fields->push(
Hidden::make('_force_redirect')->setValue(true)
)
)
->toArray()
)
->when(
$isAsync,
fn (FormBuilder $formBuilder): FormBuilder => $formBuilder
->async(asyncEvents: [
$resource->listEventName(request('_component_name', 'default')),
AlpineJs::event(JsEvent::FORM_RESET, 'crud'),
])
)
->when(
$resource->isPrecognitive() || (moonshineRequest()->isFragmentLoad('crud-form') && ! $isAsync),
fn (FormBuilder $form): FormBuilder => $form->precognitive()
)
->name('crud')
->submit(__('moonshine::ui.save'), ['class' => 'btn-primary btn-lg']);
}
}

Слои на странице

Для удобства все страницы crud разделены на три слоя, которые отвечают за отображение определенной области на странице.

  • TopLayer - используется для отображения метрик на странице индекса и для дополнительных кнопок на странице редактирования
  • MainLayer - этот слой используется для отображения основной информации с помощью FormBuilder и TableBuilder
  • BottomLayer - используется для отображения дополнительной информации

Для настройки слоев используются соответствующие методы: topLayer(), mainLayer() и bottomLayer(). Методы должны возвращать массив Компонентов.

namespace App\MoonShine\Pages\Post;
 
use MoonShine\Decorations\Heading;
use MoonShine\Pages\Crud\IndexPage;
 
class PostIndexPage extends IndexPage
{
//...
 
protected function topLayer(): array
{
return [
Heading::make('Custom top'),
...parent::topLayer()
];
}
 
protected function mainLayer(): array
{
return [
Heading::make('Custom main'),
...parent::mainLayer()
];
}
 
protected function bottomLayer(): array
{
return [
Heading::make('Custom bottom'),
...parent::bottomLayer()
];
}
 
//...
}

Если вам нужно получить доступ к компонентам определенного слоя через ресурс или страницу, то используйте метод getLayerComponents.

use MoonShine\Enums\Layer;
use MoonShine\Enums\PageType;
 
// ...
 
// Resource
$this->getPages()
->findByType(PageType::FORM)
->getLayerComponents(Layer::BOTTOM);
 
// Page
$this->getLayerComponents(Layer::BOTTOM);

Если вам нужно добавить компонент для указанной страницы в нужный слой через ресурс, то используйте метод onBoot ресурса и pushToLayer страницы.

protected function onBoot(): void
{
$this->getPages()
->findByUri(PageType::FORM->value)
->pushToLayer(
layer: Layer::BOTTOM,
component: Permissions::make(
'Permissions',
$this,
)
);
}