Основы

# Основы

В основе любой админ-панели лежат разделы для редактирования данных. MoonShine не является исключением в этом и для работы с базой данных использует Eloquent модели, а для разделов стандартные Laravel ресурс контроллеры и ресурс маршруты.

Если бы вы разрабатывали самостоятельно, то создать ресурс контроллеры и ресурс маршруты можно следующим образом:

php artisan make:controller Controller --resource
Route::resource('resources', Controller::class);

Но эту работу можно поручить админ-панели MoonShine, которая будет их генерировать и объявлять самостоятельно.

ModelResource является основным компонентом для создания раздела в админ-панели при работе с базой данных.

# Создание раздела

php artisan moonshine:resource Post

  • измените название вашего ресурса, если требуется
  • выберите тип ресурса

При создания ModelResource доступно несколько вариантов:

В результате создастся класс PostResource, который будет основой нового раздела в панели.
Располагается он, по умолчанию, в директории app/MoonShine/Resources.
MoonShine автоматически, исходя из названия, привяжет ресурс к модели app/Models/Post.
Заголовок раздела так же сгенерируется автоматически и будет "Posts".

Можно сразу указать команде привязку к модели и заголовок раздела:

php artisan moonshine:resource Post --model=CustomPost --title="Статьи"
php artisan moonshine:resource Post --model="App\Models\CustomPost" --title="Статьи"

# Основные свойства раздела

Основные параметры, которые можно менять у ресурса, чтобы кастомизировать его работу

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']; // Eager load
 
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 resources(): array
{
return [
new PostResource()
];
}
 
//...
}

# Текущий элемент/модель

Если в url детальной страницы или страницы редактирования присутствует параметр resourceItem, то в ресурсе вы можете получить доступ к текущему элементу через метод getItem().

$this->getItem();

Через метод 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;
 
//...
}

# Редиректы

По умолчанию при создании и редактировании записи осуществляется редирект на страницу с формой, но это поведение можно контролировать

// Через свойство в ресурсе
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'];
}
 
//...
}

# Кнопки

По умолчанию на индексной странице ресурса модели присутствует только кнопка для создания.
Метод 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('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 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'
]);
}

# Компоненты

Лучший способ изменять компоненты страниц это опубликовать страницы и взаимодействовать через них, но если вы хотите быстро добавить компоненты на страницы, то можете воспользоваться методами ресурса pageComponents, indexPageComponents, formPageComponents, detailPageComponents

// or indexPageComponents/formPageComponents/detailPageComponents
public function pageComponents(): array
{
return [
Modal::make(
'My Modal',
components: PageComponents::make([
FormBuilder::make()->fields([
Text::make('Title')
])
])
)
->name('demo-modal')
];
}

Компоненты будут добавлены в bottomLayer

# Boot

Если Вам необходимо добавить логику в работу ресурса в момент когда он активен и загружен, то воспользуйтесь методом onBoot

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
// ...
protected function onBoot(): void
{
//
}
// ...
}

Вы также можете подключить trait к ресурсу и внутри trait добавить метод согласно конвенции наименований - boot{TraitName} и через трейт обратится к boot ресурса

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,
)
);
}
}