- Основы
- Создание раздела
- Основные свойства раздела
- Объявление раздела в системе
- Текущий элемент/модель
- Модальные окна
- Перенаправления
- Активные действия
- Кнопки
- Модификация
- Компоненты
- Загрузка
Основы
В сердце любой админ-панели лежат разделы для редактирования данных. MoonShine не является исключением и использует модели Eloquent для работы с базой данных, а для разделов используются стандартные ресурсные контроллеры и ресурсные маршруты Laravel.
Если бы вы разрабатывали самостоятельно, то создание ресурсных контроллеров и ресурсных маршрутов могло бы выглядеть так:
php artisan make:controller Controller --resourcephp artisan make:controller Controller --resource
Route::resource('resources', Controller::class);Route::resource('resources', Controller::class);
Однако эту работу можно доверить админ-панели MoonShine, которая сгенерирует и объявит их самостоятельно.
ModelResource является основным компонентом для создания раздела в админ-панели при работе с базой данных.
Создание раздела
php artisan moonshine:resource Postphp artisan moonshine:resource Post
- измените имя ресурса, если требуется
- выберите тип ресурса
При создании ModelResource доступно несколько вариантов:
- Ресурс модели по умолчанию - ресурс модели с общими полями
- Отдельный ресурс модели - ресурс модели с разделением полей
- Ресурс модели со страницами - ресурс модели со страницами.
В результате будет создан класс PostResource, который станет основой нового раздела в панели. По умолчанию он располагается в директории app/MoonShine/Resources.
MoonShine автоматически, на основе имени, свяжет ресурс с моделью app/Models/Post. Заголовок раздела также будет сгенерирован автоматически и будет "Posts".
Вы можете сразу указать привязку модели и заголовок раздела для команды:
php artisan moonshine:resource Post --model=CustomPost --title="Articles"php artisan moonshine:resource Post --model=CustomPost --title="Articles"
php artisan moonshine:resource Post --model="App\Models\CustomPost" --title="Articles"php artisan moonshine:resource Post --model="App\Models\CustomPost" --title="Articles"
Основные свойства раздела
Основные параметры, которые можно изменить для ресурса, чтобы настроить его работу
namespace App\MoonShine\Resources;use App\Models\Post;use MoonShine\Resources\ModelResource;class PostResource extends ModelResource{protected string $model = Post::class; // Модельprotected string $title = 'Posts'; // Заголовок разделаprotected array $with = ['category']; // Жадная загрузкаprotected string $column = 'id'; // Поле для отображения значений в ссылках и хлебных крошках//...}namespace App\MoonShine\Resources;use App\Models\Post;use MoonShine\Resources\ModelResource;class PostResource extends ModelResource{protected string $model = Post::class; // Модельprotected string $title = 'Posts'; // Заголовок разделаprotected array $with = ['category']; // Жадная загрузкаprotected string $column = 'id'; // Поле для отображения значений в ссылках и хлебных крошках//...}

Объявление раздела в системе
Зарегистрировать ресурс в системе и сразу добавить ссылку на раздел в навигационное меню можно с помощью сервис-провайдера MoonShineServiceProvider.
namespace App\Providers;use App\MoonShine\Resources\PostResource;use MoonShine\Providers\MoonShineApplicationServiceProvider;class MoonShineServiceProvider extends MoonShineApplicationServiceProvider{//...protected function menu(): array{return [MenuItem::make('Posts', new PostResource())];}//...}namespace App\Providers;use App\MoonShine\Resources\PostResource;use MoonShine\Providers\MoonShineApplicationServiceProvider;class MoonShineServiceProvider extends MoonShineApplicationServiceProvider{//...protected function menu(): array{return [MenuItem::make('Posts', new PostResource())];}//...}
О расширенных настройках вы можете узнать в разделе Меню.
Если вам нужно только зарегистрировать ресурс в системе, не добавляя его в навигационное меню:
namespace App\Providers;use App\MoonShine\Resources\PostResource;use MoonShine\Providers\MoonShineApplicationServiceProvider;class MoonShineServiceProvider extends MoonShineApplicationServiceProvider{protected function resources(): array{return [new PostResource()];}//...}namespace App\Providers;use App\MoonShine\Resources\PostResource;use MoonShine\Providers\MoonShineApplicationServiceProvider;class MoonShineServiceProvider extends MoonShineApplicationServiceProvider{protected function resources(): array{return [new PostResource()];}//...}
Текущий элемент/модель
Если url страницы детального просмотра или редактирования содержит параметр resourceItem, то в ресурсе вы можете получить доступ к текущему элементу через метод getItem().
$this->getItem();$this->getItem();
Вы можете получить доступ к модели через метод getModel().
$this->getModel();$this->getModel();
Модальные окна
Возможность добавления, редактирования и просмотра записей прямо на странице со списком в модальном окне.
namespace App\MoonShine\Resources;use App\Models\Post;use MoonShine\Resources\ModelResource;class PostResource extends ModelResource{protected string $model = Post::class;protected string $title = 'Posts';protected bool $createInModal = false;protected bool $editInModal = false;protected bool $detailInModal = false;//...}namespace App\MoonShine\Resources;use App\Models\Post;use MoonShine\Resources\ModelResource;class PostResource extends ModelResource{protected string $model = Post::class;protected string $title = 'Posts';protected bool $createInModal = false;protected bool $editInModal = false;protected bool $detailInModal = false;//...}
Перенаправления
По умолчанию при создании и редактировании записи выполняется редирект на страницу с формой, но этим поведением можно управлять.
// Через свойство в ресурсеprotected ?PageType $redirectAfterSave = PageType::FORM;// или через методы (также доступен редирект после удаления)public function redirectAfterSave(): string{return '/';}public function redirectAfterDelete(): string{return to_page(CustomPage::class);}// Через свойство в ресурсеprotected ?PageType $redirectAfterSave = PageType::FORM;// или через методы (также доступен редирект после удаления)public function redirectAfterSave(): string{return '/';}public function redirectAfterDelete(): string{return to_page(CustomPage::class);}
Активные действия
Часто бывает, что необходимо создать ресурс, в котором будет исключена возможность удаления, или добавления, или редактирования. Причем речь идет не об авторизации, а о глобальном исключении этих разделов. Делается это предельно просто с помощью метода getActiveActions в ресурсе.
namespace MoonShine\Resources;class PostResource extends ModelResource{//...public function getActiveActions(): array{return ['create', 'view', 'update', 'delete', 'massDelete'];}//...}namespace MoonShine\Resources;class PostResource extends ModelResource{//...public function getActiveActions(): array{return ['create', 'view', 'update', 'delete', 'massDelete'];}//...}
Кнопки
По умолчанию на странице индекса ресурса модели есть только кнопка создания.
Метод actions() позволяет добавить дополнительные кнопки.
namespace MoonShine\Resources;class PostResource extends ModelResource{//...public function actions(): array{return [ActionButton::make('Refresh', '#')->dispatchEvent(AlpineJs::event(JsEvent::TABLE_UPDATED, 'index-table'))];}//...}namespace MoonShine\Resources;class PostResource extends ModelResource{//...public function actions(): array{return [ActionButton::make('Refresh', '#')->dispatchEvent(AlpineJs::event(JsEvent::TABLE_UPDATED, 'index-table'))];}//...}
Отображение
Вы также можете изменить отображение кнопок, отображать их в строке или в выпадающем меню для экономии места.
namespace MoonShine\Resources;class PostResource extends ModelResource{//...public function actions(): array{return [ActionButton::make('Button 1', '/')->showInLine(),ActionButton::make('Button 2', '/')->showInDropdown()];}//...}namespace MoonShine\Resources;class PostResource extends ModelResource{//...public function actions(): array{return [ActionButton::make('Button 1', '/')->showInLine(),ActionButton::make('Button 2', '/')->showInDropdown()];}//...}
Модификация
Для модификации основных компонентов страниц IndexPage, FormPage или DetailPage из ресурса можно переопределить соответствующие методы modifyListComponent(), modifyFormComponent() и modifyDetailComponent().
public function modifyListComponent(MoonShineRenderable $component): MoonShineRenderable{return parent::modifyListComponent($component)->customAttributes(['data-my-attr' => 'value']);}public function modifyListComponent(MoonShineRenderable $component): MoonShineRenderable{return parent::modifyListComponent($component)->customAttributes(['data-my-attr' => 'value']);}
public function modifyFormComponent(MoonShineRenderable $component): MoonShineRenderable{return parent::modifyFormComponent($component)->fields([FlexibleRender::make('Top'),...parent::modifyFormComponent($component)->getFields()->toArray(),FlexibleRender::make('Bottom'),])->submit('Go');}public function modifyFormComponent(MoonShineRenderable $component): MoonShineRenderable{return parent::modifyFormComponent($component)->fields([FlexibleRender::make('Top'),...parent::modifyFormComponent($component)->getFields()->toArray(),FlexibleRender::make('Bottom'),])->submit('Go');}
public function modifyDetailComponent(MoonShineRenderable $component): MoonShineRenderable{return parent::modifyDetailComponent($component)->customAttributes(['data-my-attr' => 'value']);}public function modifyDetailComponent(MoonShineRenderable $component): MoonShineRenderable{return parent::modifyDetailComponent($component)->customAttributes(['data-my-attr' => 'value']);}
Компоненты
Лучший способ изменить компоненты страниц - это опубликовать страницы и взаимодействовать через них, но если вы хотите быстро добавить компоненты на страницы, то можете использовать методы ресурса pageComponents, indexPageComponents, formPageComponents, detailPageComponents.
// или indexPageComponents/formPageComponents/detailPageComponentspublic function pageComponents(): array{return [Modal::make('My Modal'components: PageComponents::make([FormBuilder::make()->fields([Text::make('Title')])]))->name('demo-modal')];}// или indexPageComponents/formPageComponents/detailPageComponentspublic function pageComponents(): array{return [Modal::make('My Modal'components: PageComponents::make([FormBuilder::make()->fields([Text::make('Title')])]))->name('demo-modal')];}
Компоненты будут добавлены в bottomLayer
Загрузка
Если вам нужно добавить логику в работу ресурса, когда он активен и загружен, то используйте метод onBoot.
namespace App\MoonShine\Resources;use App\Models\Post;use MoonShine\Resources\ModelResource;class PostResource extends ModelResource{// ...protected function onBoot(): void{//}// ...}namespace App\MoonShine\Resources;use App\Models\Post;use MoonShine\Resources\ModelResource;class PostResource extends ModelResource{// ...protected function onBoot(): void{//}// ...}
Рецепт: Изменение хлебных крошек из ресурса.
Вы также можете подключить трейт к ресурсу и внутри трейта добавить метод по соглашению об именовании - boot{TraitName} и через трейт получить доступ к загрузке ресурса
namespace App\MoonShine\Resources;use App\Models\Post;use MoonShine\Resources\ModelResource;use App\Traits\WithPermissions;class PostResource extends ModelResource{use WithPermissions;}namespace App\MoonShine\Resources;use App\Models\Post;use MoonShine\Resources\ModelResource;use App\Traits\WithPermissions;class PostResource extends ModelResource{use WithPermissions;}
trait WithPermissions{protected function bootWithPermissions(): void{$this->getPages()->findByUri(PageType::FORM->value)->pushToLayer(layer: Layer::BOTTOM,component: Permissions::make(label: 'Permissions',resource: $this,));}}trait WithPermissions{protected function bootWithPermissions(): void{$this->getPages()->findByUri(PageType::FORM->value)->pushToLayer(layer: Layer::BOTTOM,component: Permissions::make(label: 'Permissions',resource: $this,));}}