4
votes

I am a beginner with using amazon s3 with laravel and I am having trouble with calling the url() method to retrieve the full url from an s3 file.

I am on Laravel version 5.8.29 and have the appropriate composer packages installed for s3

I am testing retrieving the url after uploading a file into the bucket. uploading is succesful.

use Illuminate\Support\Facades\Storage;

$url = Storage::url('file.jpg');

$url = Storage::disk('s3')->url('image.png');

using Storage::url('file.jpg') is okay but

using Storage::disk('s3')->url('image.png') and I will get an error saying "undefined method 'url'" even though it is in laravel official docs and I am not sure why.

1
pls write the exact error you getGiacomo M

1 Answers

4
votes

I'm also p*ssed with this "error". VSCode and Intelephense keep saying Undefined method 'url' for any Storage::disk('s3')->url('path.ext');, even knowing that this is the method suggested on the Laravel docs File Storage. For docs specific to 5.8, look here.

Apparently, there's more than one way to handle this and I'm not sure about which one would the proper way to choose without changing the Laravel itself. I'll tell you what I think it's the best, at least to me, since I'm trying to solve the same thing.

Some of the ways suggested outhere, are:

  • Use the default cloud filesystem, like this:

    Storage::cloud()->url('filename.ext');
    

    But I admit I don't like it, since I prefer to specify the disk name. Remember that to use this, you'll have define the cloud config at config/filesystems.php, like this: 'cloud' => env('FILESYSTEM_CLOUD', 's3'). But if there's something that we can learn with the cloud method, is that it is returning the right type to IDE's when it's reading the code (and we'll use this).

  • According to the cloud method above, it returns \Illuminate\Filesystem\FilesystemManager. So, we can use this to specify it in a variable comment, like this:

    /** @var \Illuminate\Filesystem\FilesystemManager $disk */
    $disk = Storage::disk('s3');
    $url = $disk->url('filename.ext');
    

    Greg mentioned that here. I really like this implementation and I'll probably use this. Remember that you can also always create a method to return that anywhere to avoid repeated code:

    /**
     * Return the s3 storage disk.
     *
     * @return \Illuminate\Filesystem\FilesystemAdapter 
     */
    private function getDisk()
    {
        return Storage::disk('s3');
    }
    
  • Another robust way is to generate the url directly with some more hidden methods Laravel uses under the table:
    $s3 = Storage::disk('s3')->getAdapter()->getClient();
    $url = $s3->getObjectUrl(env('AWS_BUCKET'), 'filename.ext');
    
    This will probably generate the url even without having to set the filesystem url at the configs but, as people commented, it may not work to non public s3 directories. And as far as I've tested, if you have url set at the configs it'll just disconsider it. Personally, after all this reasons, I don't like this.
  • There's also another way like extending the facade, but I also don't like and I'll prefer to not publish it here, first because it's too many code for something trivial, second to not recommend it. But of course, if you'd like to deal with this on a centralized way, that maybe the path.

So as you can see, the quicker and clean way nowadays is to use the @var notation.

Hope someone fixes this in a near future or another better way appears. If anyone knows something better, please let me know in the comments, I'll be more than happy to update it here.

Info related:

If this was helpful, remember to consider accepting the answer or thumbing it up.