Search code examples
phplaravellaravel-medialibrary

Laravel spatie medialibrary custom directory structure /year/month/date not working as expected


I am using laravel spatie medialibrary and I want to store files in a directory structure like /year/month/date

I read here https://spatie.be/docs/laravel-medialibrary/v11/advanced-usage/using-a-custom-directory-structure

and I created this file in /app/Services/MediaLibrary/CustomPathGenerator.php which I list below.

Now files are stored in the correct place as I want.

But my problem is that when I try to READ the file, this CANNOT BE FOUND, because same rule applies when trying to read the file location and the date has changed and then it points to different path that does not exist.

Any idea how to solve this?

Thanks!

Here is my file /app/Services/MediaLibrary/CustomPathGenerator.php:

<?php

namespace App\Services\MediaLibrary;

use \Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\MediaLibrary\Support\PathGenerator\PathGenerator as BasePathGenerator;

class CustomPathGenerator implements BasePathGenerator
{
    
   
    
    /**
     * Get the path for the given media, relative to the root storage path.
     *
     * @param \Spatie\MediaLibrary\MediaCollections\Models\Media $media
     *
     * @return string
     */
    public function getPath(Media $media): string
    {   
        //return $this->getBasePath($media).'/';
        //return md5($media->id . config('app.key')) . '/';
        $md5_var=md5($media->id . config('app.key'));
        $myPath=date("Y").'/'.date("m").'/'.substr($md5_var,0,4). '/'.substr($md5_var,4,4) . '/'.substr($md5_var,8,4).'/'.$md5_var.'/'; 
        return $myPath;    
    }

    /**
     * Get the path for conversions of the given media, relative to the root storage path.
     *
     * @param \Spatie\MediaLibrary\MediaCollections\Models\Media $media
     *
     * @return string
     */
    public function getPathForConversions(Media $media): string
    {
        //return $this->getBasePath($media).'/conversions/';
        //return md5($media->id . config('app.key')) . '/conversions/';
        $md5_var=md5($media->id . config('app.key'));
        $myPath=date("Y").'/'.date("m").'/'.substr($md5_var,0,4). '/'.substr($md5_var,4,4) . '/'.substr($md5_var,8,4).'/'.$md5_var. '/conversions/'; 
        return $myPath;
    }

    /**
     * Get the path for responsive images of the given media, relative to the root storage path.
     *
     * @param \Spatie\MediaLibrary\MediaCollections\Models\Media $media
     *
     * @return string
     */
    public function getPathForResponsiveImages(Media $media): string
    {
        //return $this->getBasePath($media).'/responsive-images/';
        //return md5($media->id . config('app.key')) . '/responsive-images/';
        $md5_var=md5($media->id . config('app.key'));
        $myPath=date("Y").'/'.date("m").'/'.substr($md5_var,0,4). '/'.substr($md5_var,4,4) . '/'.substr($md5_var,8,4).'/'.$md5_var. '/responsive-images/'; 
        return $myPath;
    }
}

Solution

  • You can change your path creator class to use the created_at date if the Media model has already been saved.

    I've written an example of the approach, it may need tweaks to work in your environment of course:

    <?php
    
    namespace App\Services\MediaLibrary;
    
    use \Spatie\MediaLibrary\MediaCollections\Models\Media;
    use Spatie\MediaLibrary\Support\PathGenerator\PathGenerator as BasePathGenerator;
    
    class CustomPathGenerator implements BasePathGenerator
    {
    
        private function getFilePath(Media $media, ?string $extra = null): string
        {
            $datePart = date('Y/m');
            if ($media->exists) {
                $datePart = $media->created_at->format('Y/m');
            }
            $md5_var = md5($media->id . config('app.key'));
            return implode('/', array_filter([
                $datePart,
                substr($md5_var, 0, 4),
                substr($md5_var, 4, 4),
                substr($md5_var, 8, 4),
                $md5_var,
                $extra
            ])) . '/';
        }
    
        /**
         * Get the path for the given media, relative to the root storage path.
         *
         * @param \Spatie\MediaLibrary\MediaCollections\Models\Media $media
         *
         * @return string
         */
        public function getPath(Media $media): string
        {
            return $this->getFilePath($media);
        }
    
        /**
         * Get the path for conversions of the given media, relative to the root storage path.
         *
         * @param \Spatie\MediaLibrary\MediaCollections\Models\Media $media
         *
         * @return string
         */
        public function getPathForConversions(Media $media): string
        {
            return $this->getFilePath($media, 'conversions');
        }
    
        /**
         * Get the path for responsive images of the given media, relative to the root storage path.
         *
         * @param \Spatie\MediaLibrary\MediaCollections\Models\Media $media
         *
         * @return string
         */
        public function getPathForResponsiveImages(Media $media): string
        {
            return $this->getFilePath($media, 'responsive-images');
        }
    }