PatrickDaniel's avatar

Seeding default files to match uploaded file paths

I'm adding to the blog project from Laravel 8 From Scratch. I have default thumbnail image files that were in the public/images/defaults/ directory and uploaded thumbnail image files that were in the storage/app/public/thumbnails directory. I was having trouble with seeding my database because the default thumbnails that I was using had a different path than the ones that were uploaded by interacting with the app- so I had to account for both cases everywhere I displayed a Post model's thumbnail, which I thought could be improved. I'm looking for feedback on the code that I settled with.

<?php

namespace Database\Seeders;

use App\Models\Post;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Http\File;
use Illuminate\Support\Facades\File as FileFacade;
use Illuminate\Support\Facades\Storage;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $admin = User::factory()->create([
            'name' => 'John Doe',
            'username' => 'John Doe',
            'email' => '[email protected]',
        ]);

        // Clear out storage/app/public/thumbnails so you don't endlessly add thumbnails to the folder
        Storage::delete(Storage::files('thumbnails'));

        // Copy images/defaults thumbnails to storage/app/public/thumbnails
        $files = FileFacade::files(public_path('images/defaults'));

        foreach ($files as $file) {
            $filename = public_path('images/defaults/') . $file->getFilename();
            Storage::putFile('thumbnails', new File($filename));
        }

        Post::factory(6)->create([
            'user_id' => $admin->id,
        ]);
    }
}
<?php

namespace Database\Factories;

use App\Models\Post;
use App\Models\User;
use App\Models\Category;
use Illuminate\Support\Facades\Storage;
use Illuminate\Database\Eloquent\Factories\Factory;

class PostFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Post::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'user_id' => User::factory(),
            'category_id' => Category::factory(),
            'title' => $this->faker->sentence(),
            'slug' => $this->faker->slug(),
            'thumbnail' => $this->randomThumbnail(),
            'is_published' => true,
            'excerpt' => '<p>' . implode('</p><p>', $this->faker->paragraphs(2)) . '</p>',
            'body' => '<p>' . implode('</p><p>', $this->faker->paragraphs(6)) . '</p>',
        ];
    }

    public function randomThumbnail()
    {
        $thumbnailsArray = Storage::files('thumbnails');
        $thumbnailsArrayMax = count($thumbnailsArray) - 1;
        $randomThumbnail = $thumbnailsArray[rand(0, $thumbnailsArrayMax)];
        return $randomThumbnail;
    }
}
0 likes
4 replies
newbie360's avatar

Storage default use local disk, so i guess you need prepand one more deep folder 'public/.....'

btw, faker can create image too

1 like
PatrickDaniel's avatar

I didn't realize that faker could create an image, thanks.

I'm not sure what you mean about prepending one more deep folder 'public/...'- could you elaborate?

PatrickDaniel's avatar

No problem! Thanks, that is a useful 'conversion table' between the different storages- that's one of the main things I was getting confused by.

Please or to participate in this conversation.