HasMany

# Basics

The HasMany field is designed to work with the relation of the same name in Laravel and includes all the basic methods.

To create this field, use the static make() method.

HasMany::make(
Closure|string $label,
?string $relationName = null,
Closure|string|null $formatted = null,
?ModelResource $resource = null
)
  • $label - label, field header,
  • $relationName - name of the relationship,
  • $resource - the model resource referenced by the relation.

The $formatted parameter is not used in the HasMany field!

The presence of the model resource referenced by the relation is mandatory!
The resource also needs to be registered with the service provider MoonShineServiceProvider in the method menu() or resources(). Otherwise, there will be a 404 error.

use MoonShine\Fields\Relationships\HasMany;
 
//...
 
public function fields(): array
{
return [
HasMany::make('Comments', 'comments', resource: new CommentResource())
];
}
 
//...

If you do not specify $relationName, then the relation name will be determined automatically based on $label.

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

You can omit $resource if the model resource matches the name of the relationship.

use MoonShine\Fields\Relationships\HasMany;
 
//...
 
public function fields(): array
{
return [
HasMany::make('Comments', 'comments')
];
}
 
//...

# Fields

The fields() method allows you to set the fields that will be displayed in the preview.

fields(Fields|Closure|array $fields)
use MoonShine\Fields\Relationships\BelongsTo;
use MoonShine\Fields\Relationships\HasMany;
use MoonShine\Fields\Text;
 
//...
 
public function fields(): array
{
return [
HasMany::make('Comments', resource: new CommentResource())
->fields([
BelongsTo::make('User'),
Text::make('Text'),
])
];
}
 
//...

# Creating a Relationship Object

The creatable() method allows you to create a new relation object through a modal window.

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

You can customize the create button by passing the button parameter to the method.

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

# Number of records

The limit() method allows you to limit the number of records displayed in preview.

limit(int $limit)
use MoonShine\Fields\Relationships\HasMany;
 
//...
 
public function fields(): array
{
return [
HasMany::make('Comments', resource: new CommentResource())
->limit(1)
];
}
 
//...

The onlyLink() method will allow you to display the relationship as a link with the number of elements.

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

You can pass optional parameters to the method:

  • linkRelation - relation reference;
  • condition - closure or boolean value, responsible for displaying the relationship as a link.

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

To retrieve relation values for a parent resource, You must set the $parentRelations property in the relationship resource.

namespace App\MoonShine\Resources;
 
use MoonShine\Resources\ModelResource;
 
class CommentResource extends ModelResource
{
//...
 
protected array $parentRelations = ['user'];
 
//...
}

The route will be available:
/resource/comment-resource/index-page/user-{id}

The linkRelation parameter allows you to create a link to a relation with a parent resource binding.

use MoonShine\Fields\Relationships\HasMany;
 
//...
 
public function fields(): array
{
return [
HasMany::make('Comments', resource: new CommentResource())
->onlyLink('user')
];
}
 
//...
condition

The condition parameter via a closure will allow you to change the display method depending on the conditions.

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

# Parent ID

If the relationship has a resource, and you want to get the ID of the parent element, then you can use the ResourceWithParent trait.

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

When using a trait, it is necessary to define methods:

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

To get the parent ID, use the getParentId() method.

$this->getParentId();

Recipe: saving files HasMany connections in the directory with the parent ID.

# Modify

The HasMany field has methods that can be used to modify the edit (add) button, change TableBuilder for preview and form, and change onlyLink button.

modifyOnlyLinkButton()

The modifyOnlyLinkButton() method allows you to change the onlyLink button.

use MoonShine\Fields\Relationships\HasMany;
 
//...
 
public function fields(): array
{
return [
HasMany::make('Comments', resource: new CommentResource())
->onlyLink()
->modifyOnlyLinkButton(
fn(ActionButton $button, bool $preview) => $button
->when(
$preview,
fn(ActionButton $btn) => $btn->primary()
fn(ActionButton $btn) => $btn->secondary()
)
)
];
}
 
//...
modifyCreateButton() / modifyEditButton()

modifyCreateButton() and modifyEditButton() methods allow you to change the create and edit buttons.

use MoonShine\Fields\Relationships\HasMany;
 
//...
 
public function fields(): array
{
return [
HasMany::make('Comments', resource: new CommentResource())
->modifyCreateButton(
fn(ActionButton $button) => $button->setLabel('Custom create button')
)
->modifyEditButton(
fn(ActionButton $button) => $button->setLabel('Custom edit button')
)
->creatable(true)
];
}
 
//...
modifyTable()

The modifyTable() method allows you to change the TableBuilder for the preview and form.

use MoonShine\Fields\Relationships\HasMany;
 
//...
 
public function fields(): array
{
return [
HasMany::make('Comments', resource: new CommentResource())
->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']))
)
];
}
 
//...

# Advanced

Relation via JSON field

The HasMany field is displayed outside the main resource form by default.
If you need to display relation fields inside the main form, then you can use the JSON field in the asRelation() mode.

//...
 
public function fields(): array
{
return [
Json::make('Comments', 'comments')
->asRelation(new CommentResource())
//...
]
}
 
//...

For more detailed information, please refer to the section Json field .

Relationship via Template field

Using the Template field you can construct a field for HasMany relationships using fluent interface during the declaration process.

For more detailed information, please refer to the section Template field .

HasMany field tabs

In Moonshine you can customize the form page and place HasMany fields in tabs using the Tabs and Tab decorations.

class PostFormPage extends FormPage
{
public function components(): array
{
if(! $this->getResource()->getItemID()) {
return parent::components();
}
 
$bottomComponents = $this->getLayerComponents(Layer::BOTTOM);
$imagesComponent = collect($bottomComponents)->filter(fn($component) => $component->getName() === 'images')->first();
$commentsComponent = collect($bottomComponents)->filter(fn($component) => $component->getName() === 'comments')->first();
 
$tabLayer = [
Block::make('', [
Tabs::make([
Tab::make('Edit', $this->mainLayer()),
Tab::make('Images', [$imagesComponent]),
Tab::make('Comments', [$commentsComponent])
])
])
];
 
return [
...$this->getLayerComponents(Layer::TOP),
...$tabLayer,
];
}
}

For more details you can read the article Form page customization. Moon Shine 2.0 .