From b8d0cbdbaf398324ab7eb1891dc6adea72ed435e Mon Sep 17 00:00:00 2001 From: "Burgstede, W.Y. (Ysbrand, Student B-CREA)" Date: Fri, 31 May 2024 02:43:47 +0200 Subject: [PATCH] Add photos to items and start the relations --- app/Http/Controllers/ItemController.php | 20 +++++- app/Http/Requests/StoreItemRequest.php | 4 +- app/Models/Attribute.php | 18 +++++ app/Models/Controller.php | 30 ++++++++ app/Models/Item.php | 19 +++-- config/filesystems.php | 5 ++ database/factories/AttributeFactory.php | 22 ++++++ database/factories/ControllerFactory.php | 22 ++++++ .../2024_05_26_204123_create_items_table.php | 2 + ..._05_29_081709_create_controllers_table.php | 23 ++++++ ...4_05_29_082156_create_attributes_table.php | 40 +++++++++++ database/seeders/DatabaseSeeder.php | 7 ++ resources/js/Pages/Items/Create.vue | 9 +++ resources/js/Pages/Items/Edit.vue | 70 ++++++++++++------- resources/js/Pages/Items/Index.vue | 2 + 15 files changed, 259 insertions(+), 34 deletions(-) create mode 100644 app/Models/Attribute.php create mode 100644 app/Models/Controller.php create mode 100644 database/factories/AttributeFactory.php create mode 100644 database/factories/ControllerFactory.php create mode 100644 database/migrations/2024_05_29_081709_create_controllers_table.php create mode 100644 database/migrations/2024_05_29_082156_create_attributes_table.php diff --git a/app/Http/Controllers/ItemController.php b/app/Http/Controllers/ItemController.php index 4bff5af..0870b39 100644 --- a/app/Http/Controllers/ItemController.php +++ b/app/Http/Controllers/ItemController.php @@ -5,6 +5,7 @@ use App\Http\Requests\StoreItemRequest; use App\Http\Requests\UpdateItemRequest; use App\Models\Item; +use Illuminate\Support\Facades\Storage; use Inertia\Inertia; use Vinkla\Hashids\Facades\Hashids; @@ -18,6 +19,7 @@ public function index() return Inertia::render('Items/Index', [ 'items' => Item::all()->each(function ($item) { $item->hashid = $item->public_id; + $item->photo_url = asset('storage/photos/' . $item->photo); }), ]); } @@ -35,9 +37,12 @@ public function create() */ public function store(StoreItemRequest $request) { + $photo = $request->file('photo'); + $photo->storeAs( 'photos/'.$photo->hashName(), ['disk' => 'public']); Item::create([ 'name' => $request->name, 'description' => $request->description, + 'photo' => $photo->hashName(), ]); return redirect(route('items.index')); @@ -72,10 +77,19 @@ public function edit(Int $id) public function update(StoreItemRequest $request, int $id) { $item = Item::findOrFail($id); + $photo = $request->file('photo'); + $photo->storeAs( 'photos/'.$photo->hashName(), ['disk' => 'public']); + + if($item->photo){ + //delete the old photo + Storage::disk('public')->delete('photos/' . $item->photo); + } $item->update([ 'name' => $request->name, 'description' => $request->description, + 'photo' => $photo->hashName(), ]); + $item->save(); return redirect(route('items.index')); } @@ -84,6 +98,10 @@ public function update(StoreItemRequest $request, int $id) */ public function destroy(Item $item) { - // + if($item->photo){ + //delete the old photo + Storage::disk('public')->delete('photos/' . $item->photo); + } + $item->delete(); } } diff --git a/app/Http/Requests/StoreItemRequest.php b/app/Http/Requests/StoreItemRequest.php index 90fbc43..30de01a 100644 --- a/app/Http/Requests/StoreItemRequest.php +++ b/app/Http/Requests/StoreItemRequest.php @@ -24,8 +24,8 @@ public function rules(): array { return [ //name and description are required - 'name' => ['required'], - 'description' => ['required'], + 'name' => ['required', 'string'], + 'description' => ['required', 'string'], ]; } } diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php new file mode 100644 index 0000000..a88d0f3 --- /dev/null +++ b/app/Models/Attribute.php @@ -0,0 +1,18 @@ +belongsToMany(Item::class, 'attribute_items'); + } +} diff --git a/app/Models/Controller.php b/app/Models/Controller.php new file mode 100644 index 0000000..c6bbedf --- /dev/null +++ b/app/Models/Controller.php @@ -0,0 +1,30 @@ +belongsTo(HasMany::class, 'item_id'); + } + + public function attributes(): BelongsToMany + { + return $this->belongsToMany(Attribute::class, 'attribute_controllers'); + } +} diff --git a/app/Models/Item.php b/app/Models/Item.php index 31b2680..e92b9d0 100644 --- a/app/Models/Item.php +++ b/app/Models/Item.php @@ -6,20 +6,29 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +/** + * @property string name + * @property string description + * @property string public_id + * @property boolean is_actuator + * @property string photo + * + */ + class Item extends Model { use HasFactory; + /** + * @var \Illuminate\Support\HigherOrderCollectionProxy|mixed + */ protected $fillable = [ 'name', 'description', + 'photo', + 'is_actuator' ]; - public function resolveRouteBinding($value, $field = null) - { - return $this::findOrFail(Hashids::decode($value)); - } - public function getPublicIdAttribute(): string { return Hashids::encode($this->id); diff --git a/config/filesystems.php b/config/filesystems.php index 44fe9c8..807ab3a 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -30,6 +30,11 @@ 'disks' => [ + 'uploads' => [ + 'driver' => 'local', + 'root' => storage_path().'/files/uploads', + ], + 'local' => [ 'driver' => 'local', 'root' => storage_path('app'), diff --git a/database/factories/AttributeFactory.php b/database/factories/AttributeFactory.php new file mode 100644 index 0000000..0a67e6d --- /dev/null +++ b/database/factories/AttributeFactory.php @@ -0,0 +1,22 @@ + Carbon::now(), + 'updated_at' => Carbon::now(), + 'name' => $this->faker->name(), + 'description' => $this->faker->text(), + ]; + } +} diff --git a/database/factories/ControllerFactory.php b/database/factories/ControllerFactory.php new file mode 100644 index 0000000..8503733 --- /dev/null +++ b/database/factories/ControllerFactory.php @@ -0,0 +1,22 @@ + Carbon::now(), + 'updated_at' => Carbon::now(), + 'Name' => $this->faker->name(), + 'item_id' => $this->faker->randomNumber(), + ]; + } +} diff --git a/database/migrations/2024_05_26_204123_create_items_table.php b/database/migrations/2024_05_26_204123_create_items_table.php index c359457..379bf2c 100644 --- a/database/migrations/2024_05_26_204123_create_items_table.php +++ b/database/migrations/2024_05_26_204123_create_items_table.php @@ -14,7 +14,9 @@ public function up(): void Schema::create('items', function (Blueprint $table) { $table->id(); $table->string('name'); + $table->string('photo'); $table->text('description')->nullable(); + $table->boolean('is_actuator')->default(false); $table->timestamps(); }); } diff --git a/database/migrations/2024_05_29_081709_create_controllers_table.php b/database/migrations/2024_05_29_081709_create_controllers_table.php new file mode 100644 index 0000000..2ec918d --- /dev/null +++ b/database/migrations/2024_05_29_081709_create_controllers_table.php @@ -0,0 +1,23 @@ +id(); + $table->string('name'); + $table->text('description'); + $table->foreignId('item_id'); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('controllers'); + } +}; diff --git a/database/migrations/2024_05_29_082156_create_attributes_table.php b/database/migrations/2024_05_29_082156_create_attributes_table.php new file mode 100644 index 0000000..b6e49d8 --- /dev/null +++ b/database/migrations/2024_05_29_082156_create_attributes_table.php @@ -0,0 +1,40 @@ +id(); + $table->string('name'); + $table->string('description'); + $table->timestamps(); + }); + + //add new pivot table called attribute_items + Schema::create('attribute_items', function (Blueprint $table) { + $table->id(); + $table->foreignId('attribute_id'); + $table->foreignId('item_id'); + $table->timestamps(); + }); + + //add a new pivot table called attribute_controllers + Schema::create('attribute_controllers', function (Blueprint $table) { + $table->id(); + $table->foreignId('attribute_id'); + $table->foreignId('controller_id'); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('attributes'); + Schema::dropIfExists('attribute_items'); + Schema::dropIfExists('attribute_controllers'); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index d01a0ef..e646403 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,6 +2,7 @@ namespace Database\Seeders; +use App\Models\Item; use App\Models\User; // use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; @@ -19,5 +20,11 @@ public function run(): void 'name' => 'Test User', 'email' => 'test@example.com', ]); + + Item::create([ + 'name' => 'Item 1', + 'description' => 'This is item 1', + 'is_actuator' => false, + ]); } } diff --git a/resources/js/Pages/Items/Create.vue b/resources/js/Pages/Items/Create.vue index 8cd34d5..2379e52 100644 --- a/resources/js/Pages/Items/Create.vue +++ b/resources/js/Pages/Items/Create.vue @@ -9,6 +9,7 @@ import { Head, useForm } from '@inertiajs/vue3'; const form = useForm({ name: '', description: '', + image: '', }); const submit = () => { @@ -40,6 +41,14 @@ const submit = () => { +
+ + + + + +
+
diff --git a/resources/js/Pages/Items/Edit.vue b/resources/js/Pages/Items/Edit.vue index b915a68..ab28c1a 100644 --- a/resources/js/Pages/Items/Edit.vue +++ b/resources/js/Pages/Items/Edit.vue @@ -7,10 +7,19 @@ import TextInput from '@/Components/TextInput.vue'; import {Head, useForm} from '@inertiajs/vue3'; import {marked} from 'marked'; import {computed, ref} from "vue"; +import axios from "axios"; const props = defineProps<{ - item?: any; + item?: { + id: number; + name: string; + description: string; + }; }>(); +const photo = ref({ + name: '', + data: null, +}); const markdown = ref(props.item?.description??""); //computed property to convert markdown to html @@ -24,20 +33,31 @@ const form = useForm({ }); const submit = () => { - if(!props.item){ - form.post(route('items.store'), { - onFinish: () => { - form.reset('name', 'description'); - }, - }); - }else { - form.put(route('items.update', props.item.id), { - onFinish: () => { - form.reset('name', 'description'); - }, + + const formData = new FormData(); + console.log(form.name, form.description, photo.value.data); + formData.append('name', form.name); + formData.append('description', form.description); + formData.append('photo', photo.value.data); + if(props.item) formData.append('_method', 'put'); + console.log(...formData.entries()); + let postRoute = props.item ? route('items.update', props.item.id) : route('items.store'); + axios.post(postRoute, formData, { + headers: { + 'Content-Type': 'multipart/form-data' + }}) + .then((res) => { + console.log(res); }); - } }; + +const updatePhoto = (files) => { + if (!files.length) return; + + // Store the file data + photo.value.data = files[0]; + photo.value.name= files[0].name; +}