PHPackages                             lupennat/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. [Framework](/categories/framework)
4. /
5. lupennat/nova-nested-many

ActiveLibrary[Framework](/categories/framework)

lupennat/nova-nested-many
=========================

Laravel Nova - Nested Many

v2.2.5(9mo ago)1557.2k↑20.4%8[8 issues](https://github.com/Lupennat/nova-nested-many/issues)MITPHPPHP ^7.4|^8.0CI passing

Since Sep 21Pushed 9mo ago1 watchersCompare

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

READMEChangelogDependencies (2)Versions (35)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 Custom Validation](#nestable-custom-validation)
    3. [Nestable Authorization](#nestable-authorization)
    4. [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. [Recursivity](#recursivity)
7. [Changelog](CHANGELOG.md)
8. [Credits](#credits)

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

[](#requirements)

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

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

[](#installation)

```
composer require lupennat/nova-nested-many:^2.0

```

NOVAPACKAGE&lt;4.29.51.x&gt;4.29.62.xUsage
-----

[](#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'])

// you can also propagate custom key/value to related resource.
HasNestedMany::make('Posts', Post::class)->propagate(['not_a_field' => 'test'])
```

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 Custom Validation

[](#nestable-custom-validation)

Field validation on nestable resources are automatically managed by `NestedMany`, for each validation error the attribute key is reprocessed and mapped to show feedback to the user in the specific field of the resource generating the error.

When validation is done by adding errors in the validator (e.g., using the afterValidation method), HasManyNested is unable to intercept and remap these errors. On related resource the correct prefix to prepend to the error attribute can be retrieved through `getNestedValidationKeyPrefix` method on Request.

```
namespace App\Nova;

class User extends Resource
{
    /**
     * Handle any post-validation processing.
     *
     * @param \Illuminate\Validation\Validator $validator
     *
     * @return void
     */
    protected static function afterValidation(NovaRequest $request, $validator)
    {
        // do logic to detect error
        $isDisposableEmail = true;
        if($isDisposableEmail) {
            $validator
                ->errors()
                ->add(
                    $request->getNestedValidationKeyPrefix() . 'email',
                    'Temporary emails are forbidden.'
                );
        }
    }
```

### 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:

```
