epartment / nova-dependency-container

A Laravel Nova field container allowing to depend on other fields values
MIT License
382 stars 163 forks source link

Detail view and compatibility with Flexible Content #102

Open dividy opened 4 years ago

dividy commented 4 years ago

Hello,

I'm using Nova Dependency Container inside Flexible Content.

Any of you using these 2 together successfully ?

I'm having 2 issues :

Problem 1 - If I add 2 products to my "product" layout, values are saved correctly in DB but on the edit form, the products's fields have the last product's values (eg. in DB: sale_price: 1 / sale_price: 3 gives sale_price: 3 / sale_price: 3 in the edit form).

Problem 2 - It won't show dependent fields on the detail view when values are matched...

Any idea ?

wize-wiz commented 4 years ago

@dividy I need a working setup on how you use both packages.

The dependency container still has some minor problems when used within a flexible content layout. The overall problem of the dependency container not behaving correctly on index/detail/etc is already known and I'm currently working out some solutions.

dividy commented 4 years ago

Hello @wize-wiz !

I use this Flexible Content preset :


<?php
namespace App\Nova\Flexible\Presets;

use Whitecube\NovaFlexibleContent\Flexible;
use Whitecube\NovaFlexibleContent\Layouts\Preset;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Fields\Textarea;
use Laravel\Nova\Fields\Number;
use Laravel\Nova\Fields\Image;
use Laravel\Nova\Fields\Markdown;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Fields\HasMany;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\Select;
use Titasgailius\SearchRelations\SearchesRelations;
use Laravel\Nova\Fields\Status;
use Laravel\Nova\Fields\Badge;
use Sloveniangooner\SearchableSelect\SearchableSelect;
use Epartment\NovaDependencyContainer\HasDependencies;
use Epartment\NovaDependencyContainer\NovaDependencyContainer;
use Illuminate\Support\Facades\Route;

class ProductPreset extends Preset
{
    use HasDependencies;

    /**
     * Create a new preset instance
     *
     * @return void
     */
    public function __construct()
    {
    }

    /**
     * Execute the preset configuration
     *
     * @return void
     */
    public function handle(Flexible $field)
    {
        $field->button('Ajouter un produit');
        $field->confirmRemove($label = 'Confirmez la suppression du produit : ', $yes = 'Supprimer', $no = 'Annuler');
        $field->hideFromIndex();

        $fields = [
            Select::make('Type de contrat', 'type')->options([
                'L' => 'Location',
                'R' => 'Relevé',
                'V' => 'Vente',
                'VU' => 'Vente unique',
                'VL' => 'Vente & Location',
            ])->displayUsingLabels()->rules('required'),

            NovaDependencyContainer::make([ Text::make('Prix en Location (htva)', 'price_rent') ])->dependsOn('type', 'L'),
            NovaDependencyContainer::make([ Text::make('Prix en Location (htva)', 'price_rent') ])->dependsOn('type', 'VL'),
            NovaDependencyContainer::make([ Text::make('Prix de Vente (htva)', 'price_sale') ])->dependsOn('type', 'V'),
            NovaDependencyContainer::make([ Text::make('Prix de Vente (htva)', 'price_sale') ])->dependsOn('type', 'VU'),
            NovaDependencyContainer::make([ Text::make('Prix de Vente (htva)', 'price_sale') ])->dependsOn('type', 'VL'),
            NovaDependencyContainer::make([ Text::make('Prix du Relevé (htva)', 'price_reading') ])->dependsOn('type', 'R'),

        ];

        $field->addLayout('Produit', 'product', $fields);

    }
}
wize-wiz commented 4 years ago

@dividy This is a general problem. What you are basically doing is declaring multiple fields with the same name. All fields have to be present though.

But from what I can read from your code, maybe this is what you try to accomplish?

    public function handle(Flexible $field)
    {
        $field->button('Ajouter un produit');
        $field->confirmRemove($label = 'Confirmez la suppression du produit : ', $yes = 'Supprimer', $no = 'Annuler');
        $field->hideFromIndex();

        $fields = [
            Select::make('Type de contrat', 'type')->options([
                'L' => 'Location',
                'R' => 'Relevé',
                'V' => 'Vente',
                'VU' => 'Vente unique',
                'VL' => 'Vente & Location',
            ])->displayUsingLabels()->rules('required'),

            NovaDependencyContainer::make([ Text::make('Prix en Location (htva)', 'price_rent') ])
                ->dependsOn('type', 'VL')
                ->dependsOn('type', 'L'),
            NovaDependencyContainer::make([ Text::make('Prix de Vente (htva)', 'price_sale') ])
                ->dependsOn('type', 'V')
                ->dependsOn('type', 'VU')
                ->dependsOn('type', 'VL'),
            NovaDependencyContainer::make([ Text::make('Prix du Relevé (htva)', 'price_reading') ])  
                ->dependsOn('type', 'R'),
        ];

        $field->addLayout('Produit', 'product', $fields);
    }

Chaining dependsOn always result in an or statement.

dividy commented 4 years ago

Yes that's intended. If you select 'L' or 'VL', I want the input field 'Prix en Location' to be displayed. If you select 'R' I want the input field 'Relevé' to be displayed. If you select 'V' or 'VU' or 'VL', I want the input field 'Prix de Vente' to be displayed.

_I noticed the dependent input fields id are called "price_rent", "price_sale" and "price_reading" instead of eg. "02d76404b3373b65__pricerent" is it intended ?

Do you have any idea why saving is OK but editing shows the value of the last item ?

dividy commented 4 years ago

Any idea @wize-wiz ? :)

wize-wiz commented 4 years ago

@dividy I have to rebuild the setup your using and try to understand the problem. This won't happen until the first week of the new year.

Happy holiday :)

dividy commented 4 years ago

Would be great because I can't deliver my app to the customer next week without this.

dividy commented 4 years ago

Hi @wize-wiz, happy new year !

Any chance for an update in the next days ?

bernhardh commented 4 years ago

Same here. I have a similar problem, with an easier setup:

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Flexible::make("Data")
            ->addLayout("Simple Layout", "html", [
                Select::make("Type", "type")->options([
                    "html" => "HTML",
                    "plain" => "Plaintext"
                ]),
                NovaDependencyContainer::make([
                    Trix::make('Content', 'html_content')
                ])->dependsOn('type', "html"),
                NovaDependencyContainer::make([
                    Textarea::make('Content', 'plain_content')
                ])->dependsOn('type', "plain")
            ])
    ];
}

If you now have for example the following input data:

You get DB entry like this:

[{
    "layout": "html",
    "key": "2244b3b27a11678a",
    "attributes": {
        "type": "html",
        "html_content": "<div>html 1<\/div>"
    }
}, {
    "layout": "html",
    "key": "8852edff81ca0ed3",
    "attributes": {
        "type": "plain",
        "plain_content": "Plain 1"
    }
}, {
    "layout": "html",
    "key": "668ca9a911074e49",
    "attributes": {
        "type": "plain",
        "plain_content": "Plain 2"
    }
}]

But I get a result like this, on the edit form

and on detail view as well:

image

patrickleemsantos commented 4 years ago

Any update on this?

iBet7o commented 4 years ago

I have the following Preset which works fine when creating a record.

image

But the log detail shows the following error.

image

And when editing the resource, the first field doesn't display correctly.

image

Does anyone know if the problem is already identified?

Regards,

deckchan commented 4 years ago

Any update?

apepindev commented 4 years ago

@iBet7o I'm getting the same property of non-object error with a layout using flexible-content. In the resolveForDisplay method in the NovaDependencyContainer class, the $resource var being passed through is an array where is should be a resource instance. I have the HasDependencies trait on my resource.

This is my layout using Nova 2.12.0, felxible-content 0.2.3 and 1.2.11 of this package.

<?php

namespace App\Nova\Flexible\Layouts;

use Epartment\NovaDependencyContainer\NovaDependencyContainer;
use Laravel\Nova\Fields\Select;
use Laravel\Nova\Fields\Text;
use OwenMelbz\RadioField\RadioButton;
use Whitecube\NovaFlexibleContent\Layouts\Layout;

class Button extends Layout
{
    /**
     * The layout's unique identifier
     *
     * @var string
     */
    protected $name = 'button';

    /**
     * The displayed title
     *
     * @var string
     */
    protected $title = 'Button';

    /**
     * Get the fields displayed by the layout.
     *
     * @return array
     */
    public function fields()
    {
        return [
            Text::make('Button Label', 'btnlabel'),
            RadioButton::make('Type', 'type')
                ->options([
                    1 => ['Route' => 'Choose from a pre-defined set of site routes.'],
                    2 => ['URL' => 'Define a full URL for the link.']
                ])
                ->default('')
                ->rules('required')
                ->stack()
                ->marginBetween()
                ->skipTransformation(),
            NovaDependencyContainer::make([
                Select::make('Route', 'route')->options([
                    'home' => 'Homepage',
                    'login' => 'Login',
                    'register' => 'Registration'
                ])
            ])->dependsOn('type', 1),
            NovaDependencyContainer::make([
                Text::make('URL', 'url')
            ])->dependsOn('type', 2),
            Select::make('Alignment', 'align')
                ->options([
                    'start' => 'Left',
                    'center' => 'Middle'
                ])
        ];
    }
}
wize-wiz commented 4 years ago

@Paradiddley try to use the development branch, only branch so far that supports flexible content and inline relationship.

apepindev commented 4 years ago

@wize-wiz I've updated the package to use that branch but I get another error Call to undefined method stdClass::getAttribute(). There's a MorphTo fix in there that's expecting the $resource to be a Resource instance but it's type casted to an stdClass. I've cloned that branch and had a look and just added a condition before it. This has fixed it for me. Let me know if you're happy for me to push into the same branch.

if ($resource instanceof Resource) {
    // @todo: quickfix for MorphTo
    $morphable_attribute = $resource->getAttribute($dependency['property'].'_type');
    if ($morphable_attribute !== null && Str::endsWith($morphable_attribute, '\\'.$dependency['value'])) {
        $this->meta['dependencies'][$index]['satisfied'] = true;
        continue;
    }
}
wize-wiz commented 4 years ago

@Paradiddley sure PR would be great 👍

apepindev commented 4 years ago

@wize-wiz sure thing, here you go #123

albertgpdevtrioteca commented 4 years ago

@wize-wiz any update?

albertgpdevtrioteca commented 4 years ago

Hello @dividy, @bernhardh, @wize-wiz.

After 5 days of hard fight against the bug, we have managed to solve it. The problem comes because NovaDependencyContainer within flexible overwrites the values of its fields with the value of the last one. To solve this, what we have done is to pass to the Fleixble constructor the fields to null. In the layout extension file we have done the following:

   /*
     * Get a cloned instance with set values
     *
     * @param  string  $key
     * @param  array  $attributes
     * @return \Whitecube\NovaFlexibleContent\Layouts\Layout
     */
    public function duplicateAndHydrate($key, array $attributes = [])
    {
        return new static(
            $this->title,
            $this->name,
            null,
            $key,
            $attributes
        );
    }

I hope it helps you. Greetings

martijn94 commented 4 years ago

Running into the same issue, the fixes (including the open PR) seem to fix the issue. Any ETA on a release?

Blindmikey commented 3 years ago

I'm getting the same issue I believe, though the error message nova throws is now Attempt to read property "override" on array

Blindmikey commented 3 years ago

Resolved with @albertgpdevtrioteca 's suggestion combined with @Paradiddley 's And a typecast of the array to an object with

...
if ( is_array( $resource ) ) { $resource = (object)$resource; }
if ($dependency['value'] == $resource->{$dependency['property']}) {
...
mateusgalasso commented 3 years ago

Hello @dividy, @bernhardh, @wize-wiz.

After 5 days of hard fight against the bug, we have managed to solve it. The problem comes because NovaDependencyContainer within flexible overwrites the values of its fields with the value of the last one. To solve this, what we have done is to pass to the Fleixble constructor the fields to null. In the layout extension file we have done the following:

   /*
     * Get a cloned instance with set values
     *
     * @param  string  $key
     * @param  array  $attributes
     * @return \Whitecube\NovaFlexibleContent\Layouts\Layout
     */
    public function duplicateAndHydrate($key, array $attributes = [])
    {
        return new static(
            $this->title,
            $this->name,
            null,
            $key,
            $attributes
        );
    }

I hope it helps you. Greetings

How and where did you do that?

kbellpostman commented 3 years ago

@stonkeep copy pasted that code into my layout... works :D Thanks @albertgpdevtrioteca !!! image