ewk/moonshine-resource-kit
Composer 安装命令:
composer require ewk/moonshine-resource-kit
包简介
Drag & drop sorting and activity toggling toolkit for MoonShine 4 resources.
README 文档
README
Тулкит для ресурсов MoonShine 4: drag & drop сортировка и переключатель активности.
Извлечён из паттернов, повторяющихся в реальных проектах: колонка sort_order с перетаскиванием строк в админской таблице и флаг is_active с переключением по одной записи и массово. Пакет — тонкий клей над встроенными механизмами MoonShine (reorderable()-таблицы на SortableJS, updateOnPreview() у переключателей): без собственного JS, всё настраивается на уровне модели/ресурса.
Требования
- PHP 8.3+
- Laravel 12/13
- MoonShine 4.15+
Установка
composer require ewk/moonshine-resource-kit
Сервис-провайдер подключается автоматически. При необходимости опубликуйте конфиг и переводы:
php artisan vendor:publish --tag=moonshine-resource-kit-config php artisan vendor:publish --tag=moonshine-resource-kit-lang
Сортировка
Модель
Добавьте колонку sort_order ($table->unsignedInteger('sort_order')->nullable();) и трейт:
use Ewk\MoonShineResourceKit\Concerns\Sortable; class Article extends Model { use Sortable; }
Новые записи получают позицию max + 1 автоматически. Также трейт даёт:
Article::query()->orderedBySort()->get(); // ... ->orderedBySortDesc() $article->moveUp(); $article->moveDown(); $article->moveToStart(); $article->moveToEnd(); $article->moveToPosition(7);
Позиции плотные (всегда 1..N), перемещение дешёвое: один UPDATE со сдвигом диапазона плюс один UPDATE с установкой позиции — независимо от размера таблицы.
Своя колонка — переопределите в модели (глобальный дефолт задаётся в конфиге):
public function getSortColumn(): string { return 'position'; }
Групповые последовательности — независимая сортировка внутри каждой группы (например, блоки внутри страницы):
public function getSortGroupColumns(): array { return ['page_id']; }
Ресурс
use Ewk\MoonShineResourceKit\MoonShine\Concerns\WithReorderable; class ArticleResource extends ModelResource { use WithReorderable; }
Дальше включите drag & drop на индексной странице — либо трейтом страницы:
use Ewk\MoonShineResourceKit\MoonShine\Concerns\ReorderableIndex; class ArticleIndexPage extends IndexPage { use ReorderableIndex; }
либо вручную в modifyListComponent():
protected function modifyListComponent(ComponentContract $component): ComponentContract { return $this->getResource()->applyReorderable($component, $this); }
Пагинация и большие таблицы
Drag & drop достаёт только до строк текущей страницы — и это нормально: когда таблица отсортирована по колонке сортировки, страница занимает непрерывный срез позиций, и пакет перераспределяет ровно этот срез. Остальные страницы не затрагиваются.
Чтобы переносить записи между страницами, добавьте кнопки перемещения на индексную страницу:
use Ewk\MoonShineResourceKit\MoonShine\Buttons\ReorderButtons; protected function buttons(): ListOf { return parent::buttons()->prepend(...ReorderButtons::for($this->getResource())); }
Вы получите «вверх / вниз», «в начало / в конец» и модалку «на позицию».
Каждое перемещение — два UPDATE, так что решение масштабируется на большие
таблицы без перезаписи всех строк.
Ручка перетаскивания
По умолчанию тянется вся строка. Чтобы перетаскивать только за ручку:
use Ewk\MoonShineResourceKit\MoonShine\Fields\SortHandle; protected function fields(): iterable { return [ SortHandle::make(), ID::make(), // ... ]; } protected function reorderableWithHandle(): bool // на индексной странице с ReorderableIndex { return true; }
Вложенные таблицы
Для таблиц HasMany, которые рендерятся внутри формы другого ресурса:
HasMany::make('Blocks', resource: BlockResource::class) ->modifyTable(app(BlockResource::class)->reorderableTableModifier()),
Переключатель активности
Модель
Добавьте boolean-колонку ($table->boolean('is_active')->default(true);) и трейт:
use Ewk\MoonShineResourceKit\Concerns\Activatable; class Article extends Model { use Activatable; }
Вы получите activate() / deactivate() / toggleActive() / isActive(),
скоупы active() / inactive() и boolean-каст. Чтобы использовать другую
колонку, переопределите getActiveColumn().
Ресурс
use Ewk\MoonShineResourceKit\MoonShine\Concerns\WithActivatable; class ArticleResource extends ModelResource { use WithActivatable; }
Переключение прямо из индексной таблицы:
use Ewk\MoonShineResourceKit\MoonShine\Fields\ActiveSwitcher; protected function fields(): iterable { return [ // ... ActiveSwitcher::make('Активность'), ]; }
Кнопки массовой активации/деактивации:
use Ewk\MoonShineResourceKit\MoonShine\Buttons\ActivityButtons; protected function buttons(): ListOf { return parent::buttons()->prepend(...ActivityButtons::for($this->getResource())); }
Глобальные скоупы (opt-in)
ActiveScope (скрывает неактивные записи) и SortOrderScope (неявная
сортировка) поставляются в пакете, но никогда не регистрируются
автоматически — глобальный скоуп, зависящий от текущего URL, стреляет в ногу
в очередях, Octane и artisan. Регистрируйте их там, где ограничение реально
нужно:
use Ewk\MoonShineResourceKit\Scopes\ActiveScope; protected static function booted(): void { static::addGlobalScope(new ActiveScope()); } // обходной путь: Article::query()->withInactive()->get();
Состояния фабрик
use Ewk\MoonShineResourceKit\Concerns\HasActiveFactoryStates; class ArticleFactory extends Factory { use HasActiveFactoryStates; } ArticleFactory::new()->active()->create(); ArticleFactory::new()->inactive()->create(); ArticleFactory::new()->randomActive()->create();
Конфигурация
config/moonshine-resource-kit.php:
| Ключ | По умолчанию | Назначение |
|---|---|---|
sort_column |
sort_order |
Глобальный дефолт для трейта Sortable |
active_column |
is_active |
Глобальный дефолт для трейта Activatable |
handle_class |
msrk-handle |
CSS-класс ячейки-ручки перетаскивания |
Переопределения на уровне модели (getSortColumn(), getSortGroupColumns(),
getActiveColumn()) всегда приоритетнее конфига.
Разработка
composer test # arch + unit + feature composer phpstan # level max, только src/ composer format # PHP-CS-Fixer (PER 3.0)
Лицензия
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-07-07