MoonShine предоставляет возможность настройки CRUD
страниц.
Для этого необходимо при создании ресурса через команду выбрать тип ресурса Model resource with pages
.
Это создаст класс ресурса модели и дополнительные классы для страниц индекса, детального просмотра и формы.
Классы страниц по умолчанию будут располагаться в директории app/MoonShine/Pages
.
В созданном ресурсе модели страницы CRUD
будут зарегистрированы в методе pages()
.
namespace App\MoonShine\Resources;
use App\MoonShine\Pages\Post\PostIndexPage;
use App\MoonShine\Pages\Post\PostFormPage;
use App\MoonShine\Pages\Post\PostDetailPage;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected function pages(): array
{
return [
PostIndexPage::class,
PostFormPage::class,
PostDetailPage::class,
];
}
}
namespaces
namespace App\MoonShine\Resources;
use App\MoonShine\Pages\Post\PostIndexPage;
use App\MoonShine\Pages\Post\PostFormPage;
use App\MoonShine\Pages\Post\PostDetailPage;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
// ...
protected function pages(): array
{
return [
PostIndexPage::class,
PostFormPage::class,
PostDetailPage::class,
];
}
}
namespace App\MoonShine\Resources;
use App\MoonShine\Pages\Post\PostIndexPage;
use App\MoonShine\Pages\Post\PostFormPage;
use App\MoonShine\Pages\Post\PostDetailPage;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
// ...
protected function pages(): array
{
return [
PostIndexPage::class,
PostFormPage::class,
PostDetailPage::class,
];
}
}
namespaces
namespace App\MoonShine\Resources;
use App\MoonShine\Pages\Post\PostIndexPage;
use App\MoonShine\Pages\Post\PostFormPage;
use App\MoonShine\Pages\Post\PostDetailPage;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
// ...
protected function pages(): array
{
return [
PostIndexPage::class,
PostFormPage::class,
PostDetailPage::class,
];
}
}
namespace App\MoonShine\Resources;
use App\MoonShine\Pages\Post\PostIndexPage;
use App\MoonShine\Pages\Post\PostFormPage;
use App\MoonShine\Pages\Post\PostDetailPage;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
// ...
protected function pages(): array
{
return [
PostIndexPage::class,
PostFormPage::class,
PostDetailPage::class,
];
}
}
Для указания типа страницы в ModelResource
используется enum
класс PageType
.
use MoonShine\Support\Enums\PageType;
PageType::INDEX; PageType::FORM; PageType::DETAIL;
namespaces
use MoonShine\Support\Enums\PageType;
PageType::INDEX; // Страница индекса
PageType::FORM; // Страница формы
PageType::DETAIL; // Страница детального просмотра
use MoonShine\Support\Enums\PageType;
PageType::INDEX; // Страница индекса
PageType::FORM; // Страница формы
PageType::DETAIL; // Страница детального просмотра
namespaces
use MoonShine\Support\Enums\PageType;
PageType::INDEX; // Страница индекса
PageType::FORM; // Страница формы
PageType::DETAIL; // Страница детального просмотра
use MoonShine\Support\Enums\PageType;
PageType::INDEX; // Страница индекса
PageType::FORM; // Страница формы
PageType::DETAIL; // Страница детального просмотра
Поля в MoonShine используются не только для ввода данных, но и для их вывода.
Метод fields()
в классе страницы CRUD
позволяет указать необходимые поля.
namespace App\MoonShine\Pages\Post;
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Text;
class PostIndexPage extends IndexPage
{
protected function fields(): iterable
{
return [
ID::make(),
Text::make('Title'),
];
}
}
namespaces
namespace App\MoonShine\Pages\Post;
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Text;
class PostIndexPage extends IndexPage
{
// ...
protected function fields(): iterable
{
return [
ID::make(),
Text::make('Title'),
];
}
}
namespace App\MoonShine\Pages\Post;
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Text;
class PostIndexPage extends IndexPage
{
// ...
protected function fields(): iterable
{
return [
ID::make(),
Text::make('Title'),
];
}
}
namespaces
namespace App\MoonShine\Pages\Post;
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Text;
class PostIndexPage extends IndexPage
{
// ...
protected function fields(): iterable
{
return [
ID::make(),
Text::make('Title'),
];
}
}
namespace App\MoonShine\Pages\Post;
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Text;
class PostIndexPage extends IndexPage
{
// ...
protected function fields(): iterable
{
return [
ID::make(),
Text::make('Title'),
];
}
}
В MoonShine можно быстро изменить основной компонент на странице.
IndexPage
Метод getItemsComponent()
позволяет изменить основной компонент страницы индекса.
getItemsComponent(iterable $items, Fields $fields)
getItemsComponent(iterable $items, Fields $fields)
getItemsComponent(iterable $items, Fields $fields)
getItemsComponent(iterable $items, Fields $fields)
getItemsComponent(iterable $items, Fields $fields)
$items
- значения полей,
$fields
- поля.
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Contracts\UI\TableBuilderContract;
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Components\Table\TableBuilder;
class ArticleIndexPage extends IndexPage
{
protected function getItemsComponent(iterable $items, Fields $fields): ComponentContract
{
return TableBuilder::make(items: $items)
->name($this->getListComponentName())
->fields($fields)
->cast($this->getResource()->getCaster())
->withNotFound()
->when(
! is_null($head = $this->getResource()->getHeadRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->headRows($head)
)
->when(
! is_null($body = $this->getResource()->getRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->rows($body)
)
->when(
! is_null($foot = $this->getResource()->getFootRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->footRows($foot)
)
->when(
! is_null($this->getResource()->getTrAttributes()),
fn (TableBuilderContract $table): TableBuilderContract => $table->trAttributes(
$this->getResource()->getTrAttributes()
)
)
->when(
! is_null($this->getResource()->getTdAttributes()),
fn (TableBuilderContract $table): TableBuilderContract => $table->tdAttributes(
$this->getResource()->getTdAttributes()
)
)
->buttons($this->getResource()->getIndexButtons())
->clickAction($this->getResource()->getClickAction())
->when($this->getResource()->isAsync(), static function (TableBuilderContract $table): void {
$table->async()->pushState();
})
->when($this->getResource()->isStickyTable(), function (TableBuilderContract $table): void {
$table->sticky();
})
->when($this->getResource()->isColumnSelection(), function (TableBuilderContract $table): void {
$table->columnSelection();
});
}
}
namespaces
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Contracts\UI\TableBuilderContract;
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Components\Table\TableBuilder;
class ArticleIndexPage extends IndexPage
{
// ...
protected function getItemsComponent(iterable $items, Fields $fields): ComponentContract
{
return TableBuilder::make(items: $items)
->name($this->getListComponentName())
->fields($fields)
->cast($this->getResource()->getCaster())
->withNotFound()
->when(
! is_null($head = $this->getResource()->getHeadRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->headRows($head)
)
->when(
! is_null($body = $this->getResource()->getRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->rows($body)
)
->when(
! is_null($foot = $this->getResource()->getFootRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->footRows($foot)
)
->when(
! is_null($this->getResource()->getTrAttributes()),
fn (TableBuilderContract $table): TableBuilderContract => $table->trAttributes(
$this->getResource()->getTrAttributes()
)
)
->when(
! is_null($this->getResource()->getTdAttributes()),
fn (TableBuilderContract $table): TableBuilderContract => $table->tdAttributes(
$this->getResource()->getTdAttributes()
)
)
->buttons($this->getResource()->getIndexButtons())
->clickAction($this->getResource()->getClickAction())
->when($this->getResource()->isAsync(), static function (TableBuilderContract $table): void {
$table->async()->pushState();
})
->when($this->getResource()->isStickyTable(), function (TableBuilderContract $table): void {
$table->sticky();
})
->when($this->getResource()->isColumnSelection(), function (TableBuilderContract $table): void {
$table->columnSelection();
});
}
}
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Contracts\UI\TableBuilderContract;
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Components\Table\TableBuilder;
class ArticleIndexPage extends IndexPage
{
// ...
protected function getItemsComponent(iterable $items, Fields $fields): ComponentContract
{
return TableBuilder::make(items: $items)
->name($this->getListComponentName())
->fields($fields)
->cast($this->getResource()->getCaster())
->withNotFound()
->when(
! is_null($head = $this->getResource()->getHeadRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->headRows($head)
)
->when(
! is_null($body = $this->getResource()->getRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->rows($body)
)
->when(
! is_null($foot = $this->getResource()->getFootRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->footRows($foot)
)
->when(
! is_null($this->getResource()->getTrAttributes()),
fn (TableBuilderContract $table): TableBuilderContract => $table->trAttributes(
$this->getResource()->getTrAttributes()
)
)
->when(
! is_null($this->getResource()->getTdAttributes()),
fn (TableBuilderContract $table): TableBuilderContract => $table->tdAttributes(
$this->getResource()->getTdAttributes()
)
)
->buttons($this->getResource()->getIndexButtons())
->clickAction($this->getResource()->getClickAction())
->when($this->getResource()->isAsync(), static function (TableBuilderContract $table): void {
$table->async()->pushState();
})
->when($this->getResource()->isStickyTable(), function (TableBuilderContract $table): void {
$table->sticky();
})
->when($this->getResource()->isColumnSelection(), function (TableBuilderContract $table): void {
$table->columnSelection();
});
}
}
namespaces
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Contracts\UI\TableBuilderContract;
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Components\Table\TableBuilder;
class ArticleIndexPage extends IndexPage
{
// ...
protected function getItemsComponent(iterable $items, Fields $fields): ComponentContract
{
return TableBuilder::make(items: $items)
->name($this->getListComponentName())
->fields($fields)
->cast($this->getResource()->getCaster())
->withNotFound()
->when(
! is_null($head = $this->getResource()->getHeadRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->headRows($head)
)
->when(
! is_null($body = $this->getResource()->getRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->rows($body)
)
->when(
! is_null($foot = $this->getResource()->getFootRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->footRows($foot)
)
->when(
! is_null($this->getResource()->getTrAttributes()),
fn (TableBuilderContract $table): TableBuilderContract => $table->trAttributes(
$this->getResource()->getTrAttributes()
)
)
->when(
! is_null($this->getResource()->getTdAttributes()),
fn (TableBuilderContract $table): TableBuilderContract => $table->tdAttributes(
$this->getResource()->getTdAttributes()
)
)
->buttons($this->getResource()->getIndexButtons())
->clickAction($this->getResource()->getClickAction())
->when($this->getResource()->isAsync(), static function (TableBuilderContract $table): void {
$table->async()->pushState();
})
->when($this->getResource()->isStickyTable(), function (TableBuilderContract $table): void {
$table->sticky();
})
->when($this->getResource()->isColumnSelection(), function (TableBuilderContract $table): void {
$table->columnSelection();
});
}
}
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Contracts\UI\TableBuilderContract;
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Components\Table\TableBuilder;
class ArticleIndexPage extends IndexPage
{
// ...
protected function getItemsComponent(iterable $items, Fields $fields): ComponentContract
{
return TableBuilder::make(items: $items)
->name($this->getListComponentName())
->fields($fields)
->cast($this->getResource()->getCaster())
->withNotFound()
->when(
! is_null($head = $this->getResource()->getHeadRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->headRows($head)
)
->when(
! is_null($body = $this->getResource()->getRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->rows($body)
)
->when(
! is_null($foot = $this->getResource()->getFootRows()),
fn (TableBuilderContract $table): TableBuilderContract => $table->footRows($foot)
)
->when(
! is_null($this->getResource()->getTrAttributes()),
fn (TableBuilderContract $table): TableBuilderContract => $table->trAttributes(
$this->getResource()->getTrAttributes()
)
)
->when(
! is_null($this->getResource()->getTdAttributes()),
fn (TableBuilderContract $table): TableBuilderContract => $table->tdAttributes(
$this->getResource()->getTdAttributes()
)
)
->buttons($this->getResource()->getIndexButtons())
->clickAction($this->getResource()->getClickAction())
->when($this->getResource()->isAsync(), static function (TableBuilderContract $table): void {
$table->async()->pushState();
})
->when($this->getResource()->isStickyTable(), function (TableBuilderContract $table): void {
$table->sticky();
})
->when($this->getResource()->isColumnSelection(), function (TableBuilderContract $table): void {
$table->columnSelection();
});
}
}
Пример страницы индекса с компонентом CardsBuilder
в разделе Рецепты.
DetailPage
Метод getDetailComponent()
позволяет изменить основной компонент страницы детального просмотра.
getDetailComponent(?DataWrapperContract $item, Fields $fields)
getDetailComponent(?DataWrapperContract $item, Fields $fields)
getDetailComponent(?DataWrapperContract $item, Fields $fields)
getDetailComponent(?DataWrapperContract $item, Fields $fields)
getDetailComponent(?DataWrapperContract $item, Fields $fields)
$item
- данные,
$fields
- поля.
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Laravel\Collections\Fields;
use MoonShine\UI\Components\Table\TableBuilder;
class ArticleDetailPage extends DetailPage
{
protected function getDetailComponent(?DataWrapperContract $item, Fields $fields): ComponentContract
{
return TableBuilder::make($fields)
->cast($this->getResource()->getCaster())
->items([$item])
->vertical()
->simple()
->preview();
}
}
namespaces
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Laravel\Collections\Fields;
use MoonShine\UI\Components\Table\TableBuilder;
class ArticleDetailPage extends DetailPage
{
// ...
protected function getDetailComponent(?DataWrapperContract $item, Fields $fields): ComponentContract
{
return TableBuilder::make($fields)
->cast($this->getResource()->getCaster())
->items([$item])
->vertical()
->simple()
->preview();
}
}
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Laravel\Collections\Fields;
use MoonShine\UI\Components\Table\TableBuilder;
class ArticleDetailPage extends DetailPage
{
// ...
protected function getDetailComponent(?DataWrapperContract $item, Fields $fields): ComponentContract
{
return TableBuilder::make($fields)
->cast($this->getResource()->getCaster())
->items([$item])
->vertical()
->simple()
->preview();
}
}
namespaces
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Laravel\Collections\Fields;
use MoonShine\UI\Components\Table\TableBuilder;
class ArticleDetailPage extends DetailPage
{
// ...
protected function getDetailComponent(?DataWrapperContract $item, Fields $fields): ComponentContract
{
return TableBuilder::make($fields)
->cast($this->getResource()->getCaster())
->items([$item])
->vertical()
->simple()
->preview();
}
}
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Laravel\Collections\Fields;
use MoonShine\UI\Components\Table\TableBuilder;
class ArticleDetailPage extends DetailPage
{
// ...
protected function getDetailComponent(?DataWrapperContract $item, Fields $fields): ComponentContract
{
return TableBuilder::make($fields)
->cast($this->getResource()->getCaster())
->items([$item])
->vertical()
->simple()
->preview();
}
}
FormPage
Метод getFormComponent()
позволяет изменить основной компонент на странице с формой.
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Laravel\Collections\Fields;
getFormComponent(
string $action,
?DataWrapperContract $item,
Fields $fields,
bool $isAsync = true,
)
namespaces
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Laravel\Collections\Fields;
getFormComponent(
string $action,
?DataWrapperContract $item,
Fields $fields,
bool $isAsync = true,
)
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Laravel\Collections\Fields;
getFormComponent(
string $action,
?DataWrapperContract $item,
Fields $fields,
bool $isAsync = true,
)
namespaces
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Laravel\Collections\Fields;
getFormComponent(
string $action,
?DataWrapperContract $item,
Fields $fields,
bool $isAsync = true,
)
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Laravel\Collections\Fields;
getFormComponent(
string $action,
?DataWrapperContract $item,
Fields $fields,
bool $isAsync = true,
)
$action
- endpoint,
$item
- данные,
$fields
- поля,
$isAsync
- асинхронный режим.
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Contracts\UI\FormBuilderContract;
use MoonShine\Laravel\Collections\Fields;
use MoonShine\Laravel\Pages\Crud\FormPage;
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
use MoonShine\UI\Components\FormBuilder;
use MoonShine\UI\Fields\Hidden;
class ArticleFormPage extends FormPage
{
protected function getFormComponent(
string $action,
?DataWrapperContract $item,
Fields $fields,
bool $isAsync = true,
): ComponentContract {
$resource = $this->getResource();
return FormBuilder::make($action)
->cast($this->getResource()->getCaster())
->fill($item)
->fields([
...$fields
->when(
! is_null($item),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_method')->setValue('PUT')
)
)
->when(
! $resource->isItemExists() && ! $resource->isCreateInModal(),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_force_redirect')->setValue(true)
)
)
->toArray(),
])
->when(
! $resource->hasErrorsAbove(),
fn (FormBuilderContract $form): FormBuilderContract => $form->errorsAbove($resource->hasErrorsAbove())
)
->when(
$isAsync,
static fn (FormBuilderContract $formBuilder): FormBuilderContract => $formBuilder
->async(events: array_filter([
$resource->getListEventName(
request()->input('_component_name', 'default'),
$isAsync && $resource->isItemExists() ? array_filter([
'page' => request()->input('page'),
'sort' => request()->input('sort'),
]) : []
),
! $resource->isItemExists() && $resource->isCreateInModal()
? AlpineJs::event(JsEvent::FORM_RESET, $resource->getUriKey())
: null,
]))
)
->when(
$resource->isPrecognitive() || (moonshineRequest()->isFragmentLoad('crud-form') && ! $isAsync),
static fn (FormBuilderContract $form): FormBuilderContract => $form->precognitive()
)
->when(
$resource->isSubmitShowWhen(),
static fn (FormBuilderContract $form): FormBuilderContract => $form->submitShowWhenAttribute()
)
->name($resource->getUriKey())
->submit(__('moonshine::ui.save'), ['class' => 'btn-primary btn-lg'])
->buttons($resource->getFormBuilderButtons());
}
}
namespaces
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Contracts\UI\FormBuilderContract;
use MoonShine\Laravel\Collections\Fields;
use MoonShine\Laravel\Pages\Crud\FormPage;
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
use MoonShine\UI\Components\FormBuilder;
use MoonShine\UI\Fields\Hidden;
class ArticleFormPage extends FormPage
{
// ...
protected function getFormComponent(
string $action,
?DataWrapperContract $item,
Fields $fields,
bool $isAsync = true,
): ComponentContract {
$resource = $this->getResource();
return FormBuilder::make($action)
->cast($this->getResource()->getCaster())
->fill($item)
->fields([
...$fields
->when(
! is_null($item),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_method')->setValue('PUT')
)
)
->when(
! $resource->isItemExists() && ! $resource->isCreateInModal(),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_force_redirect')->setValue(true)
)
)
->toArray(),
])
->when(
! $resource->hasErrorsAbove(),
fn (FormBuilderContract $form): FormBuilderContract => $form->errorsAbove($resource->hasErrorsAbove())
)
->when(
$isAsync,
static fn (FormBuilderContract $formBuilder): FormBuilderContract => $formBuilder
->async(events: array_filter([
$resource->getListEventName(
request()->input('_component_name', 'default'),
$isAsync && $resource->isItemExists() ? array_filter([
'page' => request()->input('page'),
'sort' => request()->input('sort'),
]) : []
),
! $resource->isItemExists() && $resource->isCreateInModal()
? AlpineJs::event(JsEvent::FORM_RESET, $resource->getUriKey())
: null,
]))
)
->when(
$resource->isPrecognitive() || (moonshineRequest()->isFragmentLoad('crud-form') && ! $isAsync),
static fn (FormBuilderContract $form): FormBuilderContract => $form->precognitive()
)
->when(
$resource->isSubmitShowWhen(),
static fn (FormBuilderContract $form): FormBuilderContract => $form->submitShowWhenAttribute()
)
->name($resource->getUriKey())
->submit(__('moonshine::ui.save'), ['class' => 'btn-primary btn-lg'])
->buttons($resource->getFormBuilderButtons());
}
}
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Contracts\UI\FormBuilderContract;
use MoonShine\Laravel\Collections\Fields;
use MoonShine\Laravel\Pages\Crud\FormPage;
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
use MoonShine\UI\Components\FormBuilder;
use MoonShine\UI\Fields\Hidden;
class ArticleFormPage extends FormPage
{
// ...
protected function getFormComponent(
string $action,
?DataWrapperContract $item,
Fields $fields,
bool $isAsync = true,
): ComponentContract {
$resource = $this->getResource();
return FormBuilder::make($action)
->cast($this->getResource()->getCaster())
->fill($item)
->fields([
...$fields
->when(
! is_null($item),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_method')->setValue('PUT')
)
)
->when(
! $resource->isItemExists() && ! $resource->isCreateInModal(),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_force_redirect')->setValue(true)
)
)
->toArray(),
])
->when(
! $resource->hasErrorsAbove(),
fn (FormBuilderContract $form): FormBuilderContract => $form->errorsAbove($resource->hasErrorsAbove())
)
->when(
$isAsync,
static fn (FormBuilderContract $formBuilder): FormBuilderContract => $formBuilder
->async(events: array_filter([
$resource->getListEventName(
request()->input('_component_name', 'default'),
$isAsync && $resource->isItemExists() ? array_filter([
'page' => request()->input('page'),
'sort' => request()->input('sort'),
]) : []
),
! $resource->isItemExists() && $resource->isCreateInModal()
? AlpineJs::event(JsEvent::FORM_RESET, $resource->getUriKey())
: null,
]))
)
->when(
$resource->isPrecognitive() || (moonshineRequest()->isFragmentLoad('crud-form') && ! $isAsync),
static fn (FormBuilderContract $form): FormBuilderContract => $form->precognitive()
)
->when(
$resource->isSubmitShowWhen(),
static fn (FormBuilderContract $form): FormBuilderContract => $form->submitShowWhenAttribute()
)
->name($resource->getUriKey())
->submit(__('moonshine::ui.save'), ['class' => 'btn-primary btn-lg'])
->buttons($resource->getFormBuilderButtons());
}
}
namespaces
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Contracts\UI\FormBuilderContract;
use MoonShine\Laravel\Collections\Fields;
use MoonShine\Laravel\Pages\Crud\FormPage;
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
use MoonShine\UI\Components\FormBuilder;
use MoonShine\UI\Fields\Hidden;
class ArticleFormPage extends FormPage
{
// ...
protected function getFormComponent(
string $action,
?DataWrapperContract $item,
Fields $fields,
bool $isAsync = true,
): ComponentContract {
$resource = $this->getResource();
return FormBuilder::make($action)
->cast($this->getResource()->getCaster())
->fill($item)
->fields([
...$fields
->when(
! is_null($item),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_method')->setValue('PUT')
)
)
->when(
! $resource->isItemExists() && ! $resource->isCreateInModal(),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_force_redirect')->setValue(true)
)
)
->toArray(),
])
->when(
! $resource->hasErrorsAbove(),
fn (FormBuilderContract $form): FormBuilderContract => $form->errorsAbove($resource->hasErrorsAbove())
)
->when(
$isAsync,
static fn (FormBuilderContract $formBuilder): FormBuilderContract => $formBuilder
->async(events: array_filter([
$resource->getListEventName(
request()->input('_component_name', 'default'),
$isAsync && $resource->isItemExists() ? array_filter([
'page' => request()->input('page'),
'sort' => request()->input('sort'),
]) : []
),
! $resource->isItemExists() && $resource->isCreateInModal()
? AlpineJs::event(JsEvent::FORM_RESET, $resource->getUriKey())
: null,
]))
)
->when(
$resource->isPrecognitive() || (moonshineRequest()->isFragmentLoad('crud-form') && ! $isAsync),
static fn (FormBuilderContract $form): FormBuilderContract => $form->precognitive()
)
->when(
$resource->isSubmitShowWhen(),
static fn (FormBuilderContract $form): FormBuilderContract => $form->submitShowWhenAttribute()
)
->name($resource->getUriKey())
->submit(__('moonshine::ui.save'), ['class' => 'btn-primary btn-lg'])
->buttons($resource->getFormBuilderButtons());
}
}
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Contracts\UI\ComponentContract;
use MoonShine\Contracts\UI\FormBuilderContract;
use MoonShine\Laravel\Collections\Fields;
use MoonShine\Laravel\Pages\Crud\FormPage;
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
use MoonShine\UI\Components\FormBuilder;
use MoonShine\UI\Fields\Hidden;
class ArticleFormPage extends FormPage
{
// ...
protected function getFormComponent(
string $action,
?DataWrapperContract $item,
Fields $fields,
bool $isAsync = true,
): ComponentContract {
$resource = $this->getResource();
return FormBuilder::make($action)
->cast($this->getResource()->getCaster())
->fill($item)
->fields([
...$fields
->when(
! is_null($item),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_method')->setValue('PUT')
)
)
->when(
! $resource->isItemExists() && ! $resource->isCreateInModal(),
static fn (Fields $fields): Fields => $fields->push(
Hidden::make('_force_redirect')->setValue(true)
)
)
->toArray(),
])
->when(
! $resource->hasErrorsAbove(),
fn (FormBuilderContract $form): FormBuilderContract => $form->errorsAbove($resource->hasErrorsAbove())
)
->when(
$isAsync,
static fn (FormBuilderContract $formBuilder): FormBuilderContract => $formBuilder
->async(events: array_filter([
$resource->getListEventName(
request()->input('_component_name', 'default'),
$isAsync && $resource->isItemExists() ? array_filter([
'page' => request()->input('page'),
'sort' => request()->input('sort'),
]) : []
),
! $resource->isItemExists() && $resource->isCreateInModal()
? AlpineJs::event(JsEvent::FORM_RESET, $resource->getUriKey())
: null,
]))
)
->when(
$resource->isPrecognitive() || (moonshineRequest()->isFragmentLoad('crud-form') && ! $isAsync),
static fn (FormBuilderContract $form): FormBuilderContract => $form->precognitive()
)
->when(
$resource->isSubmitShowWhen(),
static fn (FormBuilderContract $form): FormBuilderContract => $form->submitShowWhenAttribute()
)
->name($resource->getUriKey())
->submit(__('moonshine::ui.save'), ['class' => 'btn-primary btn-lg'])
->buttons($resource->getFormBuilderButtons());
}
}
Для удобства все страницы crud разделены на три слоя, которые отвечают за отображение определенной области на странице.
TopLayer
- используется для отображения метрик на странице индекса и для дополнительных кнопок на странице редактирования,
MainLayer
- этот слой используется для отображения основной информации с помощью FormBuilder и TableBuilder,
BottomLayer
- используется для отображения дополнительной информации.
Для настройки слоев используются соответствующие методы: topLayer()
, mainLayer()
и bottomLayer()
.
Методы должны возвращать массив Компонентов.
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Components\Heading;
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()
];
}
}
namespaces
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Components\Heading;
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()
];
}
}
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Components\Heading;
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()
];
}
}
namespaces
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Components\Heading;
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()
];
}
}
use MoonShine\Laravel\Pages\Crud\IndexPage;
use MoonShine\UI\Components\Heading;
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\Support\Enums\Layer;
$this->getFormPage()->getLayerComponents(Layer::BOTTOM);
$this->getLayerComponents(Layer::BOTTOM);
namespaces
use MoonShine\Support\Enums\Layer;
// ...
// Resource
$this->getFormPage()->getLayerComponents(Layer::BOTTOM);
// Page
$this->getLayerComponents(Layer::BOTTOM);
use MoonShine\Support\Enums\Layer;
// ...
// Resource
$this->getFormPage()->getLayerComponents(Layer::BOTTOM);
// Page
$this->getLayerComponents(Layer::BOTTOM);
namespaces
use MoonShine\Support\Enums\Layer;
// ...
// Resource
$this->getFormPage()->getLayerComponents(Layer::BOTTOM);
// Page
$this->getLayerComponents(Layer::BOTTOM);
use MoonShine\Support\Enums\Layer;
// ...
// Resource
$this->getFormPage()->getLayerComponents(Layer::BOTTOM);
// Page
$this->getLayerComponents(Layer::BOTTOM);
Если вам нужно добавить компонент для указанной страницы в нужный слой через ресурс, то используйте метод onLoad()
ресурса и pushToLayer()
страницы.
use MoonShine\Permissions\Components\Permissions;
use MoonShine\Support\Enums\Layer;
protected function onLoad(): void
{
$this->getFormPage()
->pushToLayer(
layer: Layer::BOTTOM,
component: Permissions::make(
'Permissions',
$this,
)
);
}
namespaces
use MoonShine\Permissions\Components\Permissions;
use MoonShine\Support\Enums\Layer;
protected function onLoad(): void
{
$this->getFormPage()
->pushToLayer(
layer: Layer::BOTTOM,
component: Permissions::make(
'Permissions',
$this,
)
);
}
use MoonShine\Permissions\Components\Permissions;
use MoonShine\Support\Enums\Layer;
protected function onLoad(): void
{
$this->getFormPage()
->pushToLayer(
layer: Layer::BOTTOM,
component: Permissions::make(
'Permissions',
$this,
)
);
}
namespaces
use MoonShine\Permissions\Components\Permissions;
use MoonShine\Support\Enums\Layer;
protected function onLoad(): void
{
$this->getFormPage()
->pushToLayer(
layer: Layer::BOTTOM,
component: Permissions::make(
'Permissions',
$this,
)
);
}
use MoonShine\Permissions\Components\Permissions;
use MoonShine\Support\Enums\Layer;
protected function onLoad(): void
{
$this->getFormPage()
->pushToLayer(
layer: Layer::BOTTOM,
component: Permissions::make(
'Permissions',
$this,
)
);
}
Мы не рекомендуем использовать CRUD-страницы на произвольных URL.
Однако, если вы хорошо понимаете их логику, можете применять CRUD-страницы на нестандартных маршрутах, эмулируя нужные URL.
class HomeController extends Controller
{
public function __invoke(FormArticlePage $page, ArticleResource $resource)
{
return $page->simulateRoute($page, $resource);
}
}
class HomeController extends Controller
{
public function __invoke(FormArticlePage $page, ArticleResource $resource)
{
return $page->simulateRoute($page, $resource);
}
}
class HomeController extends Controller
{
public function __invoke(FormArticlePage $page, ArticleResource $resource)
{
return $page->simulateRoute($page, $resource);
}
}
class HomeController extends Controller
{
public function __invoke(FormArticlePage $page, ArticleResource $resource)
{
return $page->simulateRoute($page, $resource);
}
}
class HomeController extends Controller
{
public function __invoke(FormArticlePage $page, ArticleResource $resource)
{
return $page->simulateRoute($page, $resource);
}
}