Skip to content

Commit

Permalink
Image upload support (#7)
Browse files Browse the repository at this point in the history
* feat: add images associated to recipes

* Apply pint changes

* chore: make sure no lazy loading and add strict mode

* chore: linting

---------

Co-authored-by: IronSinew <[email protected]>
  • Loading branch information
IronSinew and IronSinew authored Mar 22, 2024
1 parent 4549508 commit 655eca0
Show file tree
Hide file tree
Showing 24 changed files with 795 additions and 143 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ cert.pem
/draft.yaml
/.blueprint
/.editorconfig
/storage/media-library/*
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ docker-compose up -d php
- [x] Label Manager
- [x] Category Manager
- [x] Recipe Manager
- [ ] Image uploads
- [x] Image uploads
- [ ] Paginate Recipe Manager
- [ ] User Management
### Other
Expand All @@ -102,3 +102,4 @@ docker-compose up -d php
- [ ] "I made it" counter
- [ ] Reviews/ratings
- [x] Roles for access to the recipe manager as a contributor
- [ ] Associate images to labels/categories (?)
26 changes: 26 additions & 0 deletions app/Http/Controllers/Admin/ImageController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace App\Http\Controllers\Admin;

use App\Enums\BannerTypeEnum;
use App\Http\Controllers\Controller;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

class ImageController extends Controller
{
public function makeHero(Media $media)
{
$media->model->media()->update(['collection_name' => 'default']);
$media->update(['collection_name' => 'hero']);

return redirect()->back()->withBanner('Image set to hero');
}

public function destroy(Media $media)
{
$media->delete();

return redirect()->back()
->withBanner('Image deleted', BannerTypeEnum::danger);
}
}
22 changes: 21 additions & 1 deletion app/Http/Controllers/Admin/RecipeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\File;
use Inertia\Inertia;

class RecipeController extends Controller
Expand Down Expand Up @@ -57,7 +58,7 @@ public function store(Request $request): RedirectResponse
public function edit(Recipe $recipe)
{
return Inertia::render('Admin/Recipe/RecipeEdit')->with([
'recipe' => fn () => $recipe->makeVisible('id')->loadMissing('labels', 'categories'),
'recipe' => fn () => $recipe->makeVisible('id')->loadMissing('labels', 'categories', 'media'),
'labels' => fn () => Label::withTrashed()
->orderBy('order_column')
->get()
Expand All @@ -66,6 +67,7 @@ public function edit(Recipe $recipe)
->orderBy('order_column')
->get()
->makeVisible('id'),
'images' => fn () => $recipe->loadMissing('media')->media,
]);
}

Expand Down Expand Up @@ -128,4 +130,22 @@ public function restore(Recipe $recipe)
return redirect()->route('admin.recipes.index')
->withBanner("Restored {$name}");
}

public function imageStore(Recipe $recipe, Request $request)
{
$request->validate([
'images' => ['array'],
'images.*' => ['required', File::image()->max(10 * 1024)],
]);

foreach ($request->images as $key => $image) {
$recipe->addMediaFromRequest("images.{$key}")
->setName("{$recipe->name} Image")
->setFileName(sprintf('%s-%s.%s', $recipe->slug, \Str::random(6), $image->extension()))
->preservingOriginal()
->toMediaCollection();
}

return response()->noContent();
}
}
2 changes: 1 addition & 1 deletion app/Http/Controllers/HomeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class HomeController extends Controller
public function __invoke(Request $request): Response
{
return Inertia::render('Dashboard')->with([
'most_recent_recipes' => Inertia::lazy(fn () => Recipe::with('images', 'labels', 'categories')
'most_recent_recipes' => Inertia::lazy(fn () => Recipe::with('media', 'labels', 'categories')
->orderBy('id', 'desc')
->limit(3)
->get()),
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/RecipeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class RecipeController extends Controller
{
public function __invoke(Recipe $recipe, Request $request): Response
{
$recipe->loadMissing('images', 'labels', 'categories');
$recipe->loadMissing('labels', 'categories', 'media');

return Inertia::render('Recipe/RecipeShow')->with([
'recipe' => fn () => $recipe,
Expand Down
37 changes: 0 additions & 37 deletions app/Models/Image.php

This file was deleted.

45 changes: 38 additions & 7 deletions app/Models/Recipe.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@

namespace App\Models;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Scout\Searchable;
use Spatie\Image\Enums\Fit;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

class Recipe extends Model
class Recipe extends Model implements HasMedia
{
use HasFactory, HasSlug, Searchable, SoftDeletes;
use HasFactory, HasSlug, InteractsWithMedia, Searchable, SoftDeletes;

/**
* The attributes that are mass assignable.
Expand Down Expand Up @@ -45,6 +50,8 @@ class Recipe extends Model

protected $hidden = ['id'];

protected $appends = ['hero', 'hero_preview'];

public function getRouteKeyName(): string
{
return 'slug';
Expand All @@ -57,6 +64,35 @@ public function getSlugOptions(): SlugOptions
->saveSlugsTo('slug');
}

protected function hero(): Attribute
{
return Attribute::make(
get: fn () => $this->getFirstMedia('hero')?->getUrl() ?? '',
);
}

protected function heroPreview(): Attribute
{
return Attribute::make(
get: fn () => $this->getFirstMedia('hero')?->preview_url ?? '',
);
}

public function registerMediaConversions(?Media $media = null): void
{
$this
->addMediaConversion('preview')
->fit(Fit::Contain, 600, 400)
->nonQueued();
}

public function registerMediaCollections(): void
{
$this
->addMediaCollection('hero')
->singleFile();
}

public function toSearchableArray(): array
{
return [
Expand All @@ -75,11 +111,6 @@ public function user(): BelongsTo
return $this->belongsTo(User::class);
}

public function images(): BelongsTo
{
return $this->belongsTo(Image::class);
}

public function labels(): BelongsToMany
{
return $this->belongsToMany(Label::class)->orderBy((new Label)->determineOrderColumnName());
Expand Down
4 changes: 4 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Enums\BannerTypeEnum;
use Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\ServiceProvider;

Expand All @@ -14,6 +15,9 @@ class AppServiceProvider extends ServiceProvider
*/
public function register(): void
{
Model::preventLazyLoading(! app()->isProduction());
Model::preventAccessingMissingAttributes(! app()->isProduction());

// @codeCoverageIgnoreStart
if ($this->app->isLocal()) {
$this->app->register(IdeHelperServiceProvider::class);
Expand Down
4 changes: 2 additions & 2 deletions bootstrap/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
$middleware->web(append: [
\App\Http\Middleware\HandleInertiaRequests::class,
\Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class,
])->validateCsrfTokens(except: [
'admin/recipes/*/image',
]);

//
})
->withExceptions(function (Exceptions $exceptions) {
//
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"laravel/scout": "^10.8",
"laravel/tinker": "^2.9",
"spatie/eloquent-sortable": "^4.2",
"spatie/laravel-medialibrary": "^11.0.0",
"spatie/laravel-sluggable": "^3.6",
"tightenco/ziggy": "^2.0"
},
Expand Down
Loading

0 comments on commit 655eca0

Please sign in to comment.