Поля

HasMany

Основы

Поле HasMany предназначено для работы с одноименной связью в Laravel и включает все Базовые методы.

HasMany::make(
Closure|string $label,
?string $relationName = null,
Closure|string|null $formatted = null,
ModelResource|string|null $resource = null,
)
  • $label - метка, заголовок поля,
  • $relationName - имя отношения,
  • $resource - ModelResource, на который ссылается отношение.

Параметр $formatted не используется в поле HasMany!

Наличие ModelResource, на который ссылается отношение, обязательно. Ресурс также необходимо зарегистрировать в сервис-провайдере MoonShineServiceProvider в методе $core->resources(). В противном случае будет ошибка 500.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make(
'Comments',
'comments',
resource: CommentResource::class
)

has_many has_many_dark

Вы можете опустить $resource, если ModelResource совпадает с названием связи.

use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', 'comments')

Если вы не указываете $relationName, тогда имя отношения будет определено автоматически на основе $label (по правилам camelCase).

use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments')

По умолчанию поле отображается вне основной формы. Если вы хотите изменить это поведение и отобразить его внутри основной формы, воспользуйтесь методом disableOutside().

use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments')->disableOutside()

Поля

Метод fields() позволяет установить поля, которые будут отображаться в preview.

fields(FieldsContract|Closure|iterable $fields)
 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\BelongsTo;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\UI\Fields\Text;
 
HasMany::make('Comments', resource: CommentResource::class)
->fields([
BelongsTo::make('User'),
Text::make('Text'),
])

has_many_fields has_many_fields_dark

Создание объекта отношения

Метод creatable() позволяет создать новый объект отношения через модальное окно.

creatable(
Closure|bool|null $condition = null,
?ActionButtonContract $button = null,
)
 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', resource: CommentResource::class)
->creatable()

has_many_creatable has_many_creatable_dark

Вы можете настроить кнопку создания, передав параметр button в метод.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\UI\Components\ActionButton;
 
HasMany::make('Comments', resource: CommentResource::class)
->creatable(
button: ActionButton::make('Custom button', '')
)

Количество записей

Метод limit() позволяет ограничить количество записей, отображаемых в preview.

limit(int $limit)
 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', resource: CommentResource::class)
->limit(1)

Метод relatedLink() позволит отобразить отношение в виде ссылки с количеством элементов. Ссылка будет вести на IndexPage дочернего ресурса из отношения HasMany, в котором буду показаны только данные элементы.

relatedLink(?string $linkRelation = null, Closure|bool $condition = null)

Вы можете передать в метод необязательные параметры:

  • linkRelation - ссылка на отношение,
  • condition - замыкание или булево значение, отвечающее за отображение отношения в виде ссылки.

Не забудьте добавить отношение в свойство $with ресурса.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', resource: CommentResource::class)
->relatedLink()

has_many_link has_many_link_dark

Параметр linkRelation позволяет создать ссылку на отношение с привязкой родительского ресурса.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', resource: CommentResource::class)
->relatedLink('comment')

Параметр condition через замыкание позволит изменить метод отображения в зависимости от условий.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\UI\Fields\Field;
 
HasMany::make('Comments', resource: CommentResource::class)
->relatedLink(condition: function (int $count, Field $field): bool {
return $count > 10;
})

ID родителя

Если у отношения есть ресурс, и вы хотите получить ID родительского элемента, то Вы можете использовать трейт ResourceWithParent.

 namespaces
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Traits\Resource\ResourceWithParent;
 
class PostImageResource extends ModelResource
{
use ResourceWithParent;
 
// ...
}

При использовании трейта необходимо определить методы:

protected function getParentResourceClassName(): string
{
return PostResource::class;
}
 
protected function getParentRelationName(): string
{
return 'post';
}

Для получения ID родителя используйте метод getParentId().

$this->getParentId();

Рецепт: сохранение файлов связей HasMany в директории с ID родителя.

Кнопка редактирования

Метод changeEditButton() позволяет полностью переопределить кнопку редактирования.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\UI\Components\ActionButton;
 
HasMany::make('Comments', 'comments', resource: CommentResource::class)
->changeEditButton(
ActionButton::make(
'Edit',
fn(Comment $comment) => app(CommentResource::class)->formPageUrl($comment)
)
)

Модальное окно

По умолчанию создание и редактирование записи поля HasMany происходит в модальном окне, метод withoutModals() позволяет отключить это поведение.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', 'comments', resource: CommentResource::class)
->withoutModals()

Модификация

Поле HasMany имеет методы, которые можно использовать для модификации кнопок, изменения TableBuilder для предпросмотра и формы, а также изменения кнопки relatedLink.

searchable()

По умолчанию на странице формы для поля HasMany доступно поле поиска. Чтобы его отключить, можно воспользоваться методом searchable().

public function searchable(Closure|bool|null $condition = null): static
 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', 'comments', resource: CommentResource::class)
->searchable(false) // отключает поле поиска

modifyItemButtons()

Метод modifyItemButtons() позволяет изменить кнопки просмотра, редактирования, удаления и массового удаления.

/**
* @param Closure(ActionButtonContract $detail, ActionButtonContract $edit, ActionButtonContract $delete, ActionButtonContract $massDelete, static $ctx): array $callback
*/
modifyItemButtons(Closure $callback)
 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\UI\Components\ActionButton;
 
HasMany::make('Comments', resource: CommentResource::class)
->modifyItemButtons(
fn(ActionButton $detail, $edit, $delete, $massDelete, HasMany $ctx) => [$detail]
)

modifyRelatedLink()

Метод modifyRelatedLink() позволяет изменить кнопку relatedLink.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\UI\Components\ActionButton;
 
HasMany::make('Comments', resource: CommentResource::class)
->relatedLink()
->modifyRelatedLink(
fn(ActionButton $button, bool $preview) => $button
->when($preview, fn(ActionButton $btn) => $btn->primary())
->unless($preview, fn(ActionButton $btn) => $btn->secondary())
)

modifyCreateButton() / modifyEditButton()

Методы modifyCreateButton() и modifyEditButton() позволяют изменить кнопки создания и редактирования.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\UI\Components\ActionButton;
 
HasMany::make('Comments', resource: CommentResource::class)
->modifyCreateButton(
fn(ActionButton $button) => $button->setLabel('Custom create button')
)
->modifyEditButton(
fn(ActionButton $button) => $button->setLabel('Custom edit button')
)
->creatable(true)

modifyTable()

Метод modifyTable() позволяет изменить TableBuilder для предпросмотра и формы.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\UI\Components\Table\TableBuilder;
 
HasMany::make('Comments', resource: CommentResource::class)
->modifyTable(
fn(TableBuilder $table, bool $preview) => $table
->when($preview, fn(TableBuilder $tbl) => $tbl->customAttributes(['style' => 'background: blue']))
->unless($preview, fn(TableBuilder $tbl) => $tbl->customAttributes(['style' => 'background: green']))
)

Редирект после изменения

Метод redirectAfter() позволяет редирект после сохранения/добавления/удаления.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', resource: CommentResource::class)
->redirectAfter(fn(int $parentId) => route('home'))

Модификация QueryBuilder

Метод modifyBuilder() позволяет модифицировать запрос через QueryBuilder.

 namespaces
use App\MoonShine\Resources\CommentResource;
use Illuminate\Database\Eloquent\Relations\Relation;
use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', resource: CommentResource::class)
->modifyBuilder(fn(Relation $query, HasMany $ctx) => $query)

Активные действия

Есть возможность быстро включать/выключать определенные действия в рамках HasMany.

Метод activeActions() явно задаёт список доступных действий.

HasMany::make('Comments')
->activeActions(
Action::VIEW,
Action::UPDATE,
)

Метод withoutActions() позволяет исключить отдельные действия.

HasMany::make('Comments')
->withoutActions(
Action::VIEW
)

Добавление ActionButtons

indexButtons()

Метод indexButtons() позволяет добавить дополнительные ActionButtons для работы с элементами HasMany.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', 'comments', resource: CommentResource::class)
->indexButtons([
ActionButton::make('Custom button')
])

formButtons()

Метод formButtons() позволяет добавить дополнительные ActionButtons внутри формы при создании или редактировании элемента HasMany.

 namespaces
use App\MoonShine\Resources\CommentResource;
use MoonShine\Laravel\Fields\Relationships\HasMany;
use MoonShine\UI\Components\ActionButton;
 
HasMany::make('Comments', 'comments', resource: CommentResource::class)
->formButtons([
ActionButton::make('Custom form button')
])

Отображение

Отображение внутри Tabs

Поля отношений в MoonShine по умолчанию отображаются внизу, отдельно от формы, и следуют друг за другом. Чтобы изменить отображение поля и добавить его в Tabs, можно использовать метод tabMode().

tabMode(Closure|bool|null $condition = null)

В следующем примере будет создан компонент Tabs с двумя вкладками Comments и Covers.

use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', 'comments', resource: CommentResource::class)
->tabMode(),
HasMany::make('Covers', 'covers', resource: CoverResource::class)
->tabMode()

tabMode не будет работать при использовании метода disableOutside()

Отображение внутри модального окна

Для того чтобы HasMany поле было отображено в модальном окне, которое вызывается по кнопке, можно использовать режим modalMode().

public function modalMode(
Closure|bool|null $condition = null,
?Closure $modifyButton = null,
?Closure $modifyModal = null
)

В данном примере вместо таблицы теперь будет ActionButton, который вызывает Modal.

use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', 'comments', resource: CommentResource::class)
->modalMode(),

Чтобы модифицировать ActionButton и Modal, можно воспользоваться параметрами метода $modifyButton и $modifyModal, в которые можно передать замыкание.

use MoonShine\Laravel\Fields\Relationships\HasMany;
 
HasMany::make('Comments', 'comments', resource: CommentResource::class)
->modalMode(
modifyButton: function (ActionButtonContract $button, HasMany $ctx) {
$button->warning();
return $button;
},
modifyModal: function (Modal $modal, ActionButtonContract $ctx) {
$modal->autoClose(false);
return $modal;
}
)

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

Местоположение поля

Поле используется только внутри CRUD-страниц, так как получает ресурс и страницу из URL. Однако вы можете использовать его и на других страницах, указав местоположение через метод nowOn().

HasMany::make('Comments', resource: CommentResource::class)
->creatable()
->nowOn(page: $resource->getFormPage(), resource: $resource, params: ['resourceItem' => $item->getKey()])
->fillCast($item, new ModelCaster(Article::class)),

Отношение через RelationRepeater поле

Поле HasMany по умолчанию отображается вне основной формы ресурса. Если вам нужно отобразить поля отношения внутри основной формы, то вы можете использовать поле RelationRepeater.

Для более подробной информации обратитесь к разделу Поле RelationRepeater.

 namespaces
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Fields\Relationships\RelationRepeater;
 
RelationRepeater::make('Characteristics', 'characteristics')
->fields([
ID::make(),
Text::make('Name', 'name'),
Text::make('Value', 'value'),
])

Отношение через поле Template

Используя поле Template, вы можете построить поле для отношений HasMany, используя fluent интерфейс в процессе декларации.

Для более подробной информации обратитесь к разделу Поле Template.