Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use of advanced-nova-media-library fields within nova-flexible-content fields #33

Closed
reinvanoyen opened this issue Jun 14, 2019 · 28 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@reinvanoyen
Copy link

Hi there,

First of all thanks for this wonderful package!

I'm trying to use the fields provided by advanced-nova-media-library (https://github.com/ebess/advanced-nova-media-library/) in a nova-flexible-content. So far I'm having no success. The media library package works on top of spatie's media library.

It would be great if we could add photos by using your package.
Images::make('Photo', 'photo')

I'm using a custom resolver and have no clue what to return in the get method or how to save the data in the set method. I keep getting the error: "Call to a member function getMedia() on array" whenever I try to access my resource in the Nova backend.

I know this might not really be an issue with this package, but since the community around Nova and these packages is so small, I figured I should just ask here.

Thanks in advance.

@voidgraphics
Copy link
Member

We'll take a look and see if we can get it working. We'd also accept a PR if anyone wants to give it a go.

toonvandenbos added a commit that referenced this issue Aug 2, 2019
…ead of attributes array). References #33. References #7
@toonvandenbos
Copy link
Member

Hi @reinvanoyen,

I pushed a commit that should solve a similar issue we had with another package. Could you check if the problem still exists when using "whitecube/nova-flexible-content": "dev-master" ?

Thanks!

@toonvandenbos toonvandenbos added the help wanted Extra attention is needed label Aug 12, 2019
@chrispage1
Copy link
Contributor

Hi @Nyratas @reinvanoyen - I've just come across this myself and I'm having the same issue, even with the dev-master branch. I'll see if I can dig about...

@chrispage1
Copy link
Contributor

Hi @Nyratas @reinvanoyen - I've just come across this myself and I'm having the same issue, even with the dev-master branch. I'll see if I can dig about...

No joy :( It'd take a long time to truly understand what's going on there for me

@reinvanoyen
Copy link
Author

reinvanoyen commented Aug 20, 2019

Hi @reinvanoyen,

I pushed a commit that should solve a similar issue we had with another package. Could you check if the problem still exists when using "whitecube/nova-flexible-content": "dev-master" ?

Thanks!

Hi @Nyratas,

Thanks for looking into this. However, this doesn't solve the issue. I wasn't really expecting it to, tbh. The problem is more that we just don't have a way to use the advanced-nova-media-library fields by using a custom Resolver.

For example, this is my "get" method in my ContentBlockResolver:

class ContentBlockResolver extends Resolver implements ResolverInterface
{
    public function get($resource, $attribute, $layouts)
    {
        $blocks = $resource->blocks()->orderBy('sort_index')->get();
        return $blocks->map(function($block) use ($layouts) {
            $layout = $layouts->find($block->type);
            if( !$layout) {
                return;
            }
            return $layout->duplicateAndHydrate($block->id, [
                'id' => $block->id,
                'title' => $block->title,
                'subtitle' => $block->subtitle,
                'text' => $block->text,
                'url' => $block->url,
                'lat' => $block->lat,
                'lng' => $block->lng,
                'video_id' => $block->video_id,
            ]);
        })->filter();
    }
}

There's just no way the media field will be able to call the "getMedia" method, since it's an array we're returning. This "getMedia" method is how we retrieve our media (https://docs.spatie.be/laravel-medialibrary/v7/basic-usage/retrieving-media/).

@toonvandenbos
Copy link
Member

Hi @reinvanoyen & @chrispage1,

I'm not sure where we're returning an array, because it seems to me we're returning a collection. Inside the map closure, we're returning layout objects.

This means both returned values are objects, which is good news since you could adapt the one getMedia should be called on.

I'm not sure which one is used by the media library, but I'm guessing it's not the collection (since its mainly used internally). In case I'm wrong and it is the collection, you could transform your get resolver in order to return a custom collection, which could contain a getMedia method (I have no idea what it should do, however).

It would make more sense if the getMedia method was called on the returned Layout objects, which is good news because you could assign custom layout classes containing the required method.

Hope this helps, but in case I'm not looking at the right spot, could you specify where the getMedia method is called on an array? Thanks!

@chrispage1
Copy link
Contributor

So it's triggered on line 198 of Layouts/Layout.php. The reason being is that the $empty flag is set to true. This forces the resolver to pass an empty array but the resolve method on Advanced Nova Media Library requires its first attribute to be the resource - it won't accept anything else.

So I wonder if in this case the fault is more with Nova Media Libraries resolve method? Either way - how can we work out that the specific series of images belongs to that particular flexible field?

@toonvandenbos
Copy link
Member

We had to pass an array in order to resolve conflicts with a Translatable field (#7) a few months back. Meanwhile we added the Arrayable interface to Layouts, so maybe we don't need to use the $empty flag anymore and pass the Layout resource to the resolver anyway.

I'll have to give it a look.

@chrispage1
Copy link
Contributor

@Nyratas - it would be great if we could get a fix to get it working properly with flexible content. It's a bit of a blocker for us at the minute - we'd be happy to send a bit of money your way to buy yourself some beautiful Belgium beers!

@tomhatzer
Copy link

For the Translatable field (#7) stuff, it's not working with the spatie/nova-translatable package.

The first problem: spatie/nova-translatable is not returning a nova field, instead it's returning a collection of nova fields. Nova flexible content is unable to use this with the current version. We can extend the constructor of Layouts/Layout.php file and loop over the collection and add the fields on their own which will allow us to output the fields. But then we come to problem 2.

The second problem: After the first problem is solved, we see all the additional fields. BUT we can not save them and we also can not see their values. There's some talk about fields with json values inside the issue from above. I haven't been able to resolve this using a custom resolver yet as I don't know the system of flexible content good enough to dig in deeper.

I'm not sure if this is of any help for your problem though (and sorry for hooking into your issue).

I'd be also willing to spend some money on a solution for this (and/or the translation stuff) as I'd need it in a custom package I'm building right now.

Thanks!

@voidgraphics
Copy link
Member

Hi @tomhatzer, a solution to this issue is in the works as we speak and we're pretty close to have it fully working with advanced-nova-media-library fields.

If you have noticed problems with Spatie's nova-translatable package I would suggest opening a new issue unless you can confirm that the problem is related to this one, which I don't believe it is.

That being said, I have not tried using Spatie's translatable field in Flexible contents before, since we use mrmonat's field, which works fine. If you're in a hurry and can't afford to wait for a potential fix to Spatie's field, I suggest using this alternative which has worked very well for us.

@toonvandenbos
Copy link
Member

Alright everyone, we got it (nearly) working. This was really a hard issue to solve and it could still have some issues since I didn't have the time to test it more extensively.

First things first: why is it nearly working? Because we have to wait for a fix on advanced-nova-media-library. I'd suggest you give the existing PR a thumbs up over there to get it moving faster.

How does it work?

  1. Spatie's MediaLibrary\HasMedia\HasMedia interface & MediaLibrary\HasMedia\HasMediaTrait should both be implemented on the resource model (not on the Flexible layout!) ;
  2. You can now use Whitecube\NovaFlexibleContent\Concerns\HasMediaLibrary and implement Spatie\MediaLibrary\HasMedia\HasMedia interface on your custom layout :
namespace App\Nova\Flexible\Layouts;

use Whitecube\NovaFlexibleContent\Layouts\Layout;
use Whitecube\NovaFlexibleContent\Concerns\HasMediaLibrary;
use Spatie\MediaLibrary\HasMedia\HasMedia;

class MyCustomLayout extends Layout implements HasMedia
{
    use HasMediaLibrary;

    // ...
}

I sincerely hope the PR on advanced-nova-media-library will be merged soon and that this will fix this issue.

toonvandenbos added a commit that referenced this issue Aug 22, 2019
@toonvandenbos
Copy link
Member

Released in v0.1.10, still waiting an update of advanced-nova-media-library.

If you need a quick fix, you could use a fork of advanced-nova-media-library that changes line 105 of src/Fields/Media.php to:

$attr = $request['__media__'] ?? [];

@chrispage1
Copy link
Contributor

chrispage1 commented Aug 22, 2019

Thanks so much for doing this but I'm getting some issues with this unfortunately. I've forked advanced-nova-media-library and made the recommended modification. nova-flexible-content v0.1.10.

I've got a layout called GallerySection -

<?php

namespace App\Nova\Flexible\Layouts;

use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
use Spatie\MediaLibrary\HasMedia\HasMedia;
use Whitecube\NovaFlexibleContent\Concerns\HasMediaLibrary;

class GallerySection extends Layout implements HasMedia
{
    use HasMediaLibrary;

    /**
     * The layout's unique identifier
     *
     * @var string
     */
    protected $name = 'gallery';

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

    /**
     * Get the fields displayed by the layout.
     *
     * @return array
     */
    public function fields()
    {
        return [
            Images::make('Gallery Images')
                ->conversionOnDetailView('small'),
        ];
    }
}

This is for my Post model which has implements Spatie HasMedia & uses HasMediaTrait.

Now in Nova when going to create a post, if I include this layout I get a load failure -

{
    "message": "No query results for model [App\\Models\\Post].",
    "exception": "Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException",
    "file": "/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php",
    "line": 204,
    "trace": [
        {
            "file": "/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php",
            "line": 180,
            "function": "prepareException",
            "class": "Illuminate\\Foundation\\Exceptions\\Handler",
            "type": "->"
        },
        {
            "file": "/var/www/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 83,
            "function": "render",
            "class": "Illuminate\\Foundation\\Exceptions\\Handler",
            "type": "->"
        },
        {
            "file": "/var/www/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 32,
            "function": "handleException",
            "class": "Illuminate\\Routing\\Pipeline",
            "type": "->"
        },
        {
            "file": "/var/www/vendor/whitecube/nova-flexible-content/src/Http/Middleware/InterceptFlexibleAttributes.php",
            "line": 33,
            "function": "Illuminate\\Routing\\{closure}",
            "class": "Illuminate\\Routing\\Pipeline",
            "type": "->"
        },
        {
            "file": "/var/www/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
            "line": 163,
            "function": "handle",
            "class": "Whitecube\\NovaFlexibleContent\\Http\\Middleware\\InterceptFlexibleAttributes",
            "type": "->"
        },
        {
            "file": "/var/www/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php",
            "line": 53,
            "function": "Illuminate\\Pipeline\\{closure}",
            "class": "Illuminate\\Pipeline\\Pipeline",
            "type": "->"
        }
       ...
}

@toonvandenbos
Copy link
Member

Hi @chrispage1,

Indeed, sorry about that. Am working on a fix as we speak.

@toonvandenbos
Copy link
Member

Fixed in v0.1.11.

@GarethSomers
Copy link
Contributor

Any progress on #64

@bernhardh
Copy link
Contributor

I still get the Call to a member function getMedia() on array error. I am on 0.1.13 of nova-flexible-content and on 2.9.1 of advanced-nova-media-library which are both the most recent I think.

My setup for this is:

use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
use Spatie\MediaLibrary\HasMedia\HasMedia;
use Whitecube\NovaFlexibleContent\Concerns\HasMediaLibrary;

class HtmlLayout extends Layout  implements HasMedia {
    use HasMediaLibrary;
    
    public function fields() {
        return [
            Images::make("Image", "my_image")        
        ];    
    }
}

The fun thing is, that I can see the field and upload files and they are shown as well. But I get the Call to a member function getMedia() on array in the notification bubble twice (vendor/ebess/advanced-nova-media-library/src/Fields/Media.php:223).

@cgarofalo
Copy link

@voidgraphics @Nyratas I have encountered the exact same bug as @bernhardh. For some reason, resolveForDisplay() is being called twice (or so it seems). The first time it gets the proper data and the second time, it fails. I have been trying to track down exactly where it's being called twice, but I haven't had any luck. It is definitely happening within the vendor files.

@buttjer
Copy link

buttjer commented Jan 27, 2020

Same behaviour here.

@alex-osborn
Copy link

alex-osborn commented Feb 20, 2020

Hi all.

We have had the same issue Call to a member function getMedia() on array which we have resolved in our code.

Hard to provide a full working example as we have custom layout classes and a custom resolver (which saves to Laravel models).

However, below is the relevant function we needed to extend in our layout:

    /**
     * Resolve the field for display and return the result.
     *
     * Note, we're extending the method from
     * Whitecube\NovaFlexibleContent\Layouts\Layout
     *
     * We need to override the logic to provide an actual resource (this model)
     * to each field for resolveForDisplay().
     *
     * The parent layout class is
     * calling getAttributes() and then passing an array of attributes to each
     * field, which doesn't work with Spatie\MediaLibrary (requires a model)
     *
     * @return array
     */
    public function getResolvedForDisplay()
    {
        $this->fields->each(function ($field) {
            $field->resolveForDisplay($this);
        });

        return $this->getResolvedValue();
    }

We traced the issue to a conflict between Laravel\Nova\Fields\Field::resolveForDisplay() and Whitecube\NovaFlexibleContent\Layouts\Layout::resolveForDisplay(). The standard nova field expects a $resource, but the layout is passing through an array of attributes from $this->getAttributes(), hence the Call to a member function getMedia() on array.

@jornwildenbeest
Copy link

Hi @alex-osborn, did you ever get this to work?

@ineghi
Copy link

ineghi commented May 14, 2020

On my side, everything seems to work exept attributes field is somehow empty.

@apepindev
Copy link

On my side, everything seems to work exept attributes field is somehow empty.

Same here

@RVxLab
Copy link

RVxLab commented Jun 15, 2020

I ran into exactly this issue. The attributes field is empty which then causes the cast to return null, see src/Concerns/HasFlexible.php:134.

I worked around it by overriding that method and removing that null check in a custom cast.

@rbijkercom
Copy link

rbijkercom commented Oct 13, 2020

Hi all,

I have been trying to make advanced-nova-media-library fields with nova-flexible-content work for a long time now.
I read this tread, and many others regarding this issue, and tried many suggestions but still no luck.
This is my setup:
"laravel/framework": "8.10",
"laravel/nova": "3.11.1",
"spatie/laravel-medialibrary": "8.10.1",
"ebess/advanced-nova-media-library": "3.3.0",
"whitecube/nova-flexible-content": "0.2.5"

This is how I've added de media to the flexible layout:

namespace App;

use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Whitecube\NovaFlexibleContent\Concerns\HasFlexible;

class Page extends Model implements HasMedia
{
    use HasFlexible;
    use InteractsWithMedia;

    protected $guarded = [ 'id' ];

    public function registerMediaCollections(): void {
        $this->addMediaCollection( 'flexible_images' );
    }
namespace App\Nova;

use App\Nova\Flexible\Layouts\ImageText;
use Illuminate\Http\Request;
use Whitecube\NovaFlexibleContent\Flexible;

class Page extends Resource
{
    public static $model = \App\Page::class;

    public function fields(Request $request)
    {
        return [
            Flexible::make('Body Flexible')
                    ->addLayout( ImageText::class )
        ];
    }
}
namespace App\Nova\Flexible\Layouts;

use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
use Spatie\MediaLibrary\HasMedia;
use Whitecube\NovaFlexibleContent\Concerns\HasMediaLibrary;
use Whitecube\NovaFlexibleContent\Layouts\Layout;

class ImageText extends Layout implements HasMedia
{
    use HasMediaLibrary;
    protected $name = 'image_text';
    protected $title = 'Image Text';
    public function fields() {
        return [
            Images::make('Images', 'flexible_images'),
        ];
   }
}

In the view I loop through the flexible content but it doesn't get the image. I doesn't event run the foreach because it doesn't find a layout.

@foreach($page->flexible('body_flexible') as $layout)
       {{ $layout->getMedia('flexible_images') }}
@endforeach

This is what gets stored in the database in the table: pages, column: body_flexible :
[{"layout":"image_text","key":"P0DZKyRuxxncY4t4","attributes":[]}]

The image is also correctly uploaded to the table: media, collection_name: image_text_P0DZKyRuxxncY4t4

The image is also visible the Nova CMS in the flexible content box so somehow Nova knows how to get the image.

Any suggestions on how to display this image in the view?

@GarethSomers
Copy link
Contributor

Hi @rbijkercom you need to use the layout key to get the media. I use something like this;
app(MediaRepository::class)->getCollection($model, 'flexible_images_' . $layout_key, []);

@mouradsm
Copy link

mouradsm commented Nov 6, 2023

Has anyone managed to get this to work? I'm trying to use the field inside the flexible content but no success =(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests