BelongsToMany

# Основы

Поле BelongsToMany предназначено для работы с одноименным отношением в Laravel и включает в себя все базовые методы.

Для создания данного поля используется статический метод make().

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

Наличие ресурса модели, на которую ссылается отношение, обязательно!
Ресурс также необходимо зарегистрировать в сервис провайдере MoonShineServiceProvider в методе menu() или resources(). Иначе, будет 404 ошибка.

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', 'categories', resource: new CategoryResource())
];
}
 
//...

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

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
];
}
 
//...

Можно не указывать $resource, если ресурс модели соответствует названию отношения.

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', 'categories')
];
}
 
//...

По умолчанию для отображения значения используется поле в связанной таблице, которое задано свойством $column в ресурсе модели.
Аргумент $formatted позволяет это переопределить.

namespace App\MoonShine\Resources;
 
use MoonShine\Resources\ModelResource;
 
class CategoryResource extends ModelResource
{
//...
 
public string $column = 'title';
 
//...
}

Если необходимо задать более сложное значение для отображения, то аргументу $formatted можно передать callback функцию.

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make(
'Categories',
'categories',
fn($item) => "$item->id. $item->title"
)
];
}
 
//...

# Заголовок столбца

По умолчанию в качестве заголовка столбца таблицы используется свойство $title ресурса модели отношения.
Метод columnLabel() позволяет переопределить заголовок.

columnLabel(string $label)
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->columnLabel('Title')
];
}
 
//...

# Pivot

Метод fields() используется для реализации pivot полей у отношения BelongsToMany.

fields(Fields|Closure|array $fields)
use MoonShine\Fields\Relationships\BelongsToMany;
use MoonShine\Fields\Text;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Contacts', resource: new ContactResource())
->fields([
Text::make('Contact', 'text'),
])
];
}
 
//...

У отношения необходимо указать какие pivot поля используются в промежуточной таблице!
Подробнее в официальной документации Laravel .

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

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

creatable(
Closure|bool|null $condition = null,
?ActionButton $button = null,
)
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->creatable()
];
}
 
//...

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

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->creatable(
button: ActionButton::make('Custom button', '')
)
];
}
 
//...

# Select

Поле BelongsToMany можно отобразить в виде выпадающего списка, для этого необходимо воспользоваться методом selectMode().

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->selectMode()
];
}
 
//...

# Опции

Все опции choices доступны для изменения через data attributes:

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Countries', resource: new CountryResource())
->selectMode()
->customAttributes([
'data-max-item-count' => 2
])
];
}
 
//...

За более подробной информацией обратитесь к Choices .

# Placeholder

Метод placeholder() позволяет задать у поля атрибут placeholder.

placeholder(string $value)
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Countries', 'countries')
->nullable()
->placeholder('Countries')
];
}
 
//...

Метод placeholder() используется только, если поле отображается в виде выпадающего списка selectMode()!

# Tree

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

tree(string $parentColumn)
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->tree('parent_id')
];
}
 
//...

# Preview

По умолчанию в preview поле будет отображаться в виде таблицы.

Для того чтобы изменить отображение в preview можно воспользоваться следующими методами.

onlyCount

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

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->onlyCount()
];
}
 
//...
inLine

Метод inLine() позволяет отобразить значения поля в виде строки.

inLine(string $separator = '', Closure|bool $badge = false, ?Closure $link = null)

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

  • separator - разделитель между элементами;
  • badge - замыкание или булево значение, отвечающее за отображение элемента в виде badge;
  • $link - замыкание которое должно вернуть url ссылки или компонент.

При передаче булевого значения true в параметр badge будет использоваться цвет Primary . Для изменения цвета, отображаемого badge, используйте замыкание и возвращайте компонент Badge::make().

use MoonShine\Components\Link;
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->inLine(
separator: ' ',
badge: fn($model, $value) => Badge::make($value, 'color'),
link: fn(Category $category, $value, $field) => Link::make(
(new CategoryResource())->detailPageUrl($category),
$value
)
)
];
}
 
//...

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

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

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

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

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->onlyLink()
];
}
 
//...
linkRelation

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

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->onlyLink('category')
];
}
 
//...
condition

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

use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->onlyLink(condition: function (int $count, Field $field): bool {
return $count > 10;
})
];
}
 
//...

# Запрос для значений

Методом valuesQuery() позволяет изменить запрос на получение значений.

valuesQuery(Closure $callback)
use Illuminate\Contracts\Database\Eloquent\Builder;
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', 'categories', resource: new CategoryResource())
->valuesQuery(fn(Builder $query, Field $field) => $query->where('active', true))
];
}
 
//...

Для реализации асинхронного поиска значений воспользуйтесь методом asyncSearch().

asyncSearch(
string $asyncSearchColumn = null,
int $asyncSearchCount = 15,
?Closure $asyncSearchQuery = null,
?Closure $asyncSearchValueCallback = null,
?string $associatedWith = null,
?string $url = null,
bool $replaceQuery = false,
)
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Countries', 'countries', resource: new CountryResource())
->asyncSearch()
];
}
 
//...

Поиск будет осуществляться по полю отношения ресурса column. По умолчанию column=id.

В метод asyncSearch() можно передавать параметры:

  • $asyncSearchColumn - поле по которому происходит поиск;
  • $asyncSearchCount - количество элементов в выдаче;
  • $asyncSearchQuery - callback-функция для фильтрации значений;
  • $asyncSearchValueCallback - callback-функция для кастомизации вывода;
  • $associatedWith - поле с которым необходимо установить связь;
  • $url - url для обработки асинхронного запроса,
  • $replaceQuery - заменить запрос.
use Illuminate\Contracts\Database\Eloquent\Builder;
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Countries', 'countries', resource: new CountryResource())
->asyncSearch(
'title',
10,
asyncSearchQuery: function (Builder $query, Request $request, Field $field) {
return $query->where('id', '!=', 2);
},
asyncSearchValueCallback: function ($country, Field $field) {
return $country->id . ' | ' . $country->title;
},
'https://moonshine-laravel.com/async'
)
];
}
 
//...

При построении запроса в asyncSearchQuery() можно использовать текущие значения формы. Для этого необходимо передать Request в callback-функции.

use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use MoonShine\Fields\Relationships\BelongsToMany;
use MoonShine\Fields\Select;
 
//...
 
public function fields(): array
{
return [
Select::make('Country', 'country_id'),
BelongsToMany::make('Cities', 'cities', resource: new CityResource())
->asyncSearch(
'title',
asyncSearchQuery: function (Builder $query, Request $request, Field $field): Builder {
return $query->where('country_id', $request->get('country_id'));
}
)
];
}
 
//...

При построении запроса в asyncSearchQuery() исходное состояние builder сохраняется.
Если вам требуется заменить на свой builder, то воспользуйтесь флагом replaceQuery.

use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use MoonShine\Fields\Relationships\BelongsToMany;
use MoonShine\Fields\Select;
 
//...
 
public function fields(): array
{
return [
Select::make('Country', 'country_id'),
BelongsToMany::make('Cities', 'cities', resource: new CityResource())
->asyncSearch(
'title',
asyncSearchQuery: function (Builder $query, Request $request, Field $field): Builder {
return $query->where('country_id', $request->get('country_id'));
},
replaceQuery: true
)
];
}
 
//...

Запросы необходимо кастомизировать через метод asyncSearch(). Не используйте valuesQuery()!

# Связанные поля

Для связывания значений селектов между полями можно воспользоваться методом associatedWith().

associatedWith(string $column, ?Closure $asyncSearchQuery = null)
  • $column - поле с которым устанавливается связь;
  • $asyncSearchQuery - callback-функция для фильтрации значений.
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Cities', 'cities', resource: new CityResource())
->associatedWith('country_id')
];
}
 
//...

Для более сложной настройки можно использовать asyncSearch().

# Значения с изображением

Метод withImage() позволяет добавить изображение к значению.

withImage(
string $column,
string $disk = 'public',
string $dir = ''
)
  • $column - поле с изображением;
  • $disk - диск файловой системы;
  • $dir - директория относительно корня диска.
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make(Countries, resource: new CountryResource())
->withImage('thumb', 'public', 'countries')->selectMode()
];
}
 
//...

# Кнопки

Метод buttons() позволяет добавить дополнительные кнопки к полю BelongsToMany.

buttons(array $buttons)
use MoonShine\ActionButtons\ActionButton;
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->buttons([
ActionButton::make('Check all', '')
->onClick(fn() => 'checkAll', 'prevent'),
 
ActionButton::make('Uncheck all', '')
->onClick(fn() => 'uncheckAll', 'prevent')
])
];
}
 
//...
withCheckAll

Метод withCheckAll() позволяет добавить кнопки checkAll/uncheckAll к полю BelongsToMany аналогично предыдущему примеру.

use MoonShine\ActionButtons\ActionButton;
use MoonShine\Fields\Relationships\BelongsToMany;
 
//...
 
public function fields(): array
{
return [
BelongsToMany::make('Categories', resource: new CategoryResource())
->withCheckAll()
];
}
 
//...