Основы
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 и TableBuilderBottomLayer
- используется для отображения дополнительной информации
Для настройки слоев используются соответствующие методы: 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, ) );}