PHPackages                             grandcreation/nova-nested-many - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. grandcreation/nova-nested-many

ActiveLibrary

grandcreation/nova-nested-many
==============================

Laravel Nova - Nested Many

07PHP

Since Dec 4Pushed 2y agoCompare

[ Source](https://github.com/grandcreation/nova-nested-many)[ Packagist](https://packagist.org/packages/grandcreation/nova-nested-many)[ RSS](/packages/grandcreation-nova-nested-many/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

[![](https://github.com/Lupennat/nova-nested-many/raw/main/demo.gif)](https://github.com/Lupennat/nova-nested-many/blob/main/demo.gif)

1. [Requirements](#Requirements)
2. [Installation](#Installation)
3. [Usage](#Usage)
4. [HasNestedMany Field](#HasNestedMany-field)
    1. [DependsOn](#depends-on)
    2. [Propagate](#propagate)
    3. [Default Children](#default-children)
    4. [Additional options](#additional-options)
    5. [Hooks](#hooks)
5. [Nestable Resource](#nestable-resource)
    1. [Nestable Title](#nestable-title)
    2. [Nestable Authorization](#nestable-authorization)
    3. [Nestable Actions](#nestable-actions)
        1. [Nestable Basic Actions](#nestable-basic-actions)
        2. [Nestable Soft Delete Action](#Nestable-soft-delete-action)
        3. [Nestable Custom Actions](#nestable-custom-actions)
        4. [Difference With Nova Actions](#difference-with-nova-actions)
        5. [Nested Object](#nested-object)
6. [Changelog](CHANGELOG.md)
7. [Credits](#credits)

Requirements
------------

[](#requirements)

- `php: ^7.4 | ^8`
- `laravel/nova: ^4`

Installation
------------

[](#installation)

```
composer require lupennat/nova-nested-many

```

Usage
-----

[](#usage)

Register Trait `HasNestedResource` globally on Resources.

```
namespace App\Nova;

use Laravel\Nova\Resource as NovaResource;
use Lupennat\NestedMany\HasNestedResource;

abstract class Resource extends NovaResource
{
    use HasNestedResource;
}
```

Use `HasManyNested` Field like `HasMany`

```
namespace App\Nova;

use Laravel\Nova\Fields\ID;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Fields\Gravatar;
use Laravel\Nova\Fields\Password;
// Add use statement here.
use Lupennat\NestedMany\Fields\HasManyNested;

class User extends Resource
{

    public function fields(Request $request)
    {
        return [
            ID::make()->sortable(),

            Gravatar::make(),

            Text::make('Name')
                ->sortable()
                ->rules('required', 'max:255'),

            Text::make('Email')
                ->sortable()
                ->rules('required', 'email', 'max:254')
                ->creationRules('unique:users,email')
                ->updateRules('unique:users,email,{{resourceId}}'),

            Password::make('Password')
                ->onlyOnForms()
                ->creationRules('required', 'string', 'min:6')
                ->updateRules('nullable', 'string', 'min:6'),

            // Add HasManyNested here.
            HasManyNested::make('Posts'),
        ];
    }

}
```

> HasManyNested is visible by deafult on DetailPage, UpdatePage and CreatePage. HasManyNested is not available on IndexPage.

Implements contract `Nestable` and use trait `HasNested` for every related model that will be used with `HasNestedMany`.

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Lupennat\NestedMany\Models\Contracts\Nestable;
use Lupennat\NestedMany\Models\HasNested;

class Post extends Model implements Nestable
{
    use HasNested;

}
```

HasNestedMany Field
-------------------

[](#hasnestedmany-field)

### Depends On

[](#depends-on)

`HasNestedMany` Field support Nova `dependsOn`.

```
HasNestedMany::make('Posts', Post::class)
    ->dependsOn('name', function(HasNestedMany $field, NovaRequest $novaRequest, FormData $formData) {
        if ($formData->name === 'xxx') {
            $field->show();
        } else {
            $field->hide();
        }
    })
```

### Propagate

[](#propagate)

`HasNestedMany` Field can propagate parent field value to related resource.

```
HasNestedMany::make('Posts', Post::class)->propagate(['name'])
```

On related resource propagated fields can be retrieved through `getNestedPropagated` method on Request

```
namespace App\Nova;

use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\Select;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\NovaRequest;

class Post extends Resource
{

    public function fields(NovaRequest $request)
    {
        return array_filter([
            ID::make(),
            BelongsTo::make(__('User'), 'user', User::class),
            Select::section(__('Section'), 'section')
                ->options(['sport' => 'Sport', 'news' => 'News'])
                ->rules('required'),
            Text::title(__('Title'), 'title')
            ->rules('required'),
            $request->getNestedPropagated('name') === 'xxx' ?
                Text::make(__('Extra Field'), 'extra')->hide() : null
        ]);
    }

}
```

### Default Children

[](#default-children)

You can use `defaultChildren` method to generate a default set of related resource when children are empty.

> defaultChildren works only on Create Page.

```
HasNestedMany::make('Posts', Post::class)
    ->defaultChildren([
        ['title' => 'first post', 'section' => 'sport'],
        ['title' => 'second post', 'section' => 'news'],
    ])
```

if you want to overwrite existing children you can use

```
HasNestedMany::make('Posts', Post::class)
    ->defaultChildren([
        ['title' => 'first post', 'section' => 'sport'],
        ['title' => 'second post', 'section' => 'news'],
    ], true)
```

### Additional options

[](#additional-options)

functiondescriptiondefault`->collapsedChildrenByDefault()`Collapse Children on Panel Viewfalse`->useTabs(bool = true)`switch display mode to tabs instead of panelsfalse`->active(int = 0)`set default active item by index0`->activeTitle(string)`set default active item by titlenull`->canChangeViewType(bool = true)`enable switch view type buttonfalse`->hideFields(array)`Hide fields on related resource\[\]`->lock(bool = true)`Disable Add/Remove buttons for related resourcefalse`->min(int = null)`Set Min childrennull`->max(int = null)`Set Max childrennull### Hooks

[](#hooks)

You can specify callbacks before and after `HasNestedMany` fill the database.

```
namespace App\Nova;

use Illuminate\Http\Request;
use Lupennat\NestedMany\Fields\HasManyNested;
use Laravel\Nova\Http\Requests\NovaRequest;

class User extends Resource
{

    public function fields(Request $request)
    {
        return [
            HasNestedMany::make('Posts', Post::class)
                ->beforeFill(function(\App\Models\User $user, NovaRequest $request) {
                    // do stuff
                })
                ->afterFill(function(\App\Models\User $user, NovaRequest $request) {
                    // do stuff
                })
        ];
    }

}
```

Nestable Resource
-----------------

[](#nestable-resource)

Resource trait `HasNestedResource`, provide new functionality related to Nested.

### Nestable Title

[](#nestable-title)

Both panel and tab views, use `nestedTitle` method to retrieve the title of the resource.

> if method not found it will fallback to original nova resource title

```
namespace App\Nova;

class User extends Resource
{

    public function nestedTitle()
    {
        return $this->resource->name;
    }

}
```

### Nestable Authorization

[](#nestable-authorization)

Nested Many will use laravel nova resource authorizations for create/update/delete. You can define different policies only for Nested Many within 3 new methods

```
namespace App\Nova;

class User extends Resource
{

    public static function authorizedToCreateNested(Request $request)
    {
        return true;
    }

    public function authorizedToUpdateNested(Request $request)
    {
        return false;
    }

    public function authorizedToDeleteNested(Request $request)
    {
        return $this->authorizedToDelete($request);
    }

}
```

Nestable Actions
----------------

[](#nestable-actions)

You can define Nested Actions to manipulate related content through the server.\\

> `Nested` Actions can keep the modal open after action is run through the property `$keepOpened` or the method `keepOpened()`.

### Nestable Basic actions

[](#nestable-basic-actions)

By Default NestedMany has 3 Basic actions `NestedBasicAddAction`, `NestedBasicDeleteAction`, `NestedBasicRestoreAction`, and it is possible to customize them through 3 methods on resource.

```
namespace App\Nova;

use Lupennat\NestedMany\Actions\Basics\NestedBasicAddAction;
use Lupennat\NestedMany\Actions\Basics\NestedBasicDeleteAction;
use Lupennat\NestedMany\Actions\Basics\NestedBasicRestoreAction;
use Laravel\Nova\Http\Requests\NovaRequest;

class Post extends Resource
{

    /**
     * Get the nested create action on the entity.
     */
    public function nestedAddAction(NovaRequest $request): NestedBasicAddAction
    {
        return new \App\Nova\NestedActions\MyCustomAddActionExtendsBasicAddAction();
    }

    /**
     * Get the nested delete action on the entity.
     */
    public function nestedDeleteAction(NovaRequest $request): NestedBasicDeleteAction
    {
        return parent::nestedDeleteAction($request)->withConfirmation();
    }

    /**
     * Get the nested delete action on the entity.
     */
    public function nestedRestoreAction(NovaRequest $request): NestedBasicRestoreAction
    {
        return parent::nestedRestoreAction($request)->withConfirmation();
    }

}
```

### Nestable Soft Delete Action

[](#nestable-soft-delete-action)

NestedDeleteAction automatically support `softDelete` logic (is not a real elouquent softDelete), to enable softdelete/restore logic you need to set `protected $nestedHasSoftDelete = true` on the related model.

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Lupennat\NestedMany\Models\Contracts\Nestable;
use Lupennat\NestedMany\Models\HasNested;

class Post extends Model implements Nestable
{
    use HasNested;

    protected $nestedHasSoftDelete = true;

}
```

### Nestable Custom actions

[](#nestable-custom-actions)

Nested actions may be generated using the nested-many:action Artisan command. By default, all actions are placed in the app/Nova/NestedActions directory:

```
php artisan nested-many:action DuplicatePost
```

You may generate a destructive action by passing the --destructive option:

```
php artisan nested-many:action DeleteAllPosts --destructive
```

Nested Actions have a lot in common with Nova Actions, the main difference is that `handle` method should always return a collection of `NestedObject`.

You can generate new `NestedObject` with method `$this->getNewNested()`.

To learn how to define Nova actions, let's look at an example. In this example, we'll define an action that will duplicate a post:

```
