From 085aac0160cd494e8ac85d1f1e9ae632428ebf9d Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Fri, 15 Mar 2024 15:04:10 +0100 Subject: [PATCH] feat: Import compatible item (sub)types on ports Fixes #113 --- .../Resources/SC/Item/ItemPortResource.php | 2 + .../SC/Item/ItemPortTypeResource.php | 40 ++++++++++++++ app/Jobs/SC/Import/Item.php | 52 ++++++++++++++++++- app/Models/SC/Item/ItemPort.php | 6 +++ app/Models/SC/Item/ItemPortType.php | 35 +++++++++++++ app/Models/SC/Item/ItemPortTypeSubType.php | 29 +++++++++++ app/Models/SC/Item/ItemSubType.php | 17 ++++++ app/Models/SC/Item/ItemType.php | 17 ++++++ app/Services/Parser/SC/Item.php | 15 ++++++ ...5_04_090341_create_sc_item_ports_table.php | 2 +- ...4_03_15_135349_create_item_types_table.php | 28 ++++++++++ ..._15_135350_create_item_port_type_table.php | 30 +++++++++++ ..._15_135354_create_item_sub_types_table.php | 28 ++++++++++ ...5_create_item_port_type_sub_type_table.php | 28 ++++++++++ storage/app/api/scunpacked-data | 2 +- 15 files changed, 327 insertions(+), 4 deletions(-) create mode 100644 app/Http/Resources/SC/Item/ItemPortTypeResource.php create mode 100644 app/Models/SC/Item/ItemPortType.php create mode 100644 app/Models/SC/Item/ItemPortTypeSubType.php create mode 100644 app/Models/SC/Item/ItemSubType.php create mode 100644 app/Models/SC/Item/ItemType.php create mode 100644 database/migrations/base_structure/sc/items/2024_03_15_135349_create_item_types_table.php create mode 100644 database/migrations/base_structure/sc/items/2024_03_15_135350_create_item_port_type_table.php create mode 100644 database/migrations/base_structure/sc/items/2024_03_15_135354_create_item_sub_types_table.php create mode 100644 database/migrations/base_structure/sc/items/2024_03_15_135355_create_item_port_type_sub_type_table.php diff --git a/app/Http/Resources/SC/Item/ItemPortResource.php b/app/Http/Resources/SC/Item/ItemPortResource.php index 006e891b3..a7f7f5af1 100644 --- a/app/Http/Resources/SC/Item/ItemPortResource.php +++ b/app/Http/Resources/SC/Item/ItemPortResource.php @@ -19,6 +19,7 @@ new OA\Property(property: 'min', type: 'integer', nullable: true), new OA\Property(property: 'max', type: 'integer', nullable: true), ], type: 'object'), + new OA\Property(property: 'compatible_types', ref: '#/components/schemas/item_port_type_v2', nullable: true), new OA\Property( property: 'tags', type: 'array', @@ -53,6 +54,7 @@ public function toArray(Request $request): array 'min' => $this->min_size, 'max' => $this->max_size, ], + 'compatible_types' => ItemPortTypeResource::collection($this->compatibleTypes), 'tags' => $this->defaultTags->pluck('name')->toArray(), 'required_tags' => $this->requiredTags->pluck('name')->toArray(), 'equipped_item' => new ItemLinkResource($this->item), diff --git a/app/Http/Resources/SC/Item/ItemPortTypeResource.php b/app/Http/Resources/SC/Item/ItemPortTypeResource.php new file mode 100644 index 000000000..4a99281e9 --- /dev/null +++ b/app/Http/Resources/SC/Item/ItemPortTypeResource.php @@ -0,0 +1,40 @@ + $this->type, + 'sub_types' => $this->subTypes->pluck('sub_type')->toArray(), + ]; + } +} diff --git a/app/Jobs/SC/Import/Item.php b/app/Jobs/SC/Import/Item.php index 5e8c42ce9..529e28a7b 100644 --- a/app/Jobs/SC/Import/Item.php +++ b/app/Jobs/SC/Import/Item.php @@ -6,6 +6,9 @@ use App\Models\SC\Item\Interaction; use App\Models\SC\Item\ItemPort; +use App\Models\SC\Item\ItemPortType; +use App\Models\SC\Item\ItemSubType; +use App\Models\SC\Item\ItemType; use App\Models\SC\Item\Tag; use App\Models\SC\Manufacturer; use Illuminate\Bus\Queueable; @@ -129,7 +132,7 @@ private function createContainerModel(\App\Models\SC\Item\Item $itemModel): void private function createPorts(\App\Models\SC\Item\Item $itemModel): void { if (! empty($this->data['ports'])) { - collect($this->data['ports'])->each(function (array $port) use ($itemModel) { + $availablePorts = collect($this->data['ports'])->each(function (array $port) use ($itemModel) { /** @var ItemPort $port */ $portModel = $itemModel->ports()->updateOrCreate([ 'name' => $port['name'], @@ -143,7 +146,52 @@ private function createPorts(\App\Models\SC\Item\Item $itemModel): void $this->addTags($portModel, $port, 'tags'); $this->addTags($portModel, $port, 'required_tags', true); - }); + + $types = collect($port['compatible_types']) + ->map(function (array $type) { + /** @var ItemType $typeModel */ + $typeModel = ItemType::query()->firstOrCreate([ + 'type' => $type['type'], + ]); + + $type['id'] = $typeModel->id; + + return $type; + }) + ->each(function (array $type) use ($portModel) { + /** @var ItemPort $portModel */ + $portModelType = $portModel->compatibleTypes()->updateOrCreate([ + 'item_type_id' => $type['id'], + ]); + + $subTypes = collect($type['sub_types']) + ->map(function (string $subType) { + /** @var ItemSubType $typeModel */ + $typeModel = ItemSubType::query()->firstOrCreate([ + 'sub_type' => $subType, + ]); + + return $typeModel->id; + }) + ->each(function (int $id) use ($portModelType) { + /** @var ItemPortType $portModelType */ + $portModelType->subTypes()->updateOrCreate([ + 'sub_type_id' => $id, + ]); + }); + + /** @var ItemPortType $portModelType */ + $portModelType->subTypes()->whereNotIn('sub_type_id', $subTypes)->delete(); + }) + ->pluck('id'); + + /** @var ItemPort $portModel */ + $portModel->compatibleTypes()->whereNotIn('item_type_id', $types)->delete(); + }) + ->pluck('name'); + + // Remove old ports + $itemModel->ports()->whereNotIn('name', $availablePorts)->delete(); } } diff --git a/app/Models/SC/Item/ItemPort.php b/app/Models/SC/Item/ItemPort.php index 6d34c9a5a..009feb509 100644 --- a/app/Models/SC/Item/ItemPort.php +++ b/app/Models/SC/Item/ItemPort.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Database\Eloquent\Relations\HasMany; class ItemPort extends Model { @@ -85,4 +86,9 @@ public function requiredTags(): BelongsToMany { return $this->tags()->wherePivot('is_required_tag', true); } + + public function compatibleTypes(): HasMany + { + return $this->hasMany(ItemPortType::class); + } } diff --git a/app/Models/SC/Item/ItemPortType.php b/app/Models/SC/Item/ItemPortType.php new file mode 100644 index 000000000..95eb341cb --- /dev/null +++ b/app/Models/SC/Item/ItemPortType.php @@ -0,0 +1,35 @@ +hasMany(ItemPortTypeSubType::class); + } + + public function typeName(): BelongsTo + { + return $this->belongsTo(ItemType::class, 'item_type_id', 'id'); + } + + public function getTypeAttribute() + { + return $this->typeName->type; + } +} diff --git a/app/Models/SC/Item/ItemPortTypeSubType.php b/app/Models/SC/Item/ItemPortTypeSubType.php new file mode 100644 index 000000000..03bf2a286 --- /dev/null +++ b/app/Models/SC/Item/ItemPortTypeSubType.php @@ -0,0 +1,29 @@ +belongsTo(ItemSubType::class, 'sub_type_id', 'id'); + } + + public function getSubTypeAttribute() + { + return $this->subTypeName->sub_type; + } +} diff --git a/app/Models/SC/Item/ItemSubType.php b/app/Models/SC/Item/ItemSubType.php new file mode 100644 index 000000000..64d2c1f0b --- /dev/null +++ b/app/Models/SC/Item/ItemSubType.php @@ -0,0 +1,17 @@ + $port['EquippedItemUuid'] ?? $loadout[strtolower($port['Name'])] ?? null, 'tags' => $port['PortTags'] ?? null, 'required_tags' => $port['RequiredPortTags'] ?? null, + 'compatible_types' => $this->mapPortCompatibleTypes($port), ]; } @@ -296,4 +297,18 @@ private function mapPortLoadouts(): Collection }) ->filter(); } + + private function mapPortCompatibleTypes(array $port): Collection + { + return collect(Arr::get($port, 'Types', [])) + ->map(function ($type) { + return [ + 'type' => $type['Type'], + 'sub_types' => collect(Arr::get($type, 'SubTypes', [])) + ->map(fn (array $subType) => $subType['value'] ?? null) + ->filter(), + ]; + }) + ->filter(); + } } diff --git a/database/migrations/base_structure/sc/items/2023_05_04_090341_create_sc_item_ports_table.php b/database/migrations/base_structure/sc/items/2023_05_04_090341_create_sc_item_ports_table.php index dbf82dfb4..850f793dc 100644 --- a/database/migrations/base_structure/sc/items/2023_05_04_090341_create_sc_item_ports_table.php +++ b/database/migrations/base_structure/sc/items/2023_05_04_090341_create_sc_item_ports_table.php @@ -13,7 +13,7 @@ */ public function up(): void { - Schema::create('sc_item_ports', function (Blueprint $table) { + Schema::create('sc_item_ports', static function (Blueprint $table) { $table->id(); $table->string('item_uuid'); diff --git a/database/migrations/base_structure/sc/items/2024_03_15_135349_create_item_types_table.php b/database/migrations/base_structure/sc/items/2024_03_15_135349_create_item_types_table.php new file mode 100644 index 000000000..89848ceeb --- /dev/null +++ b/database/migrations/base_structure/sc/items/2024_03_15_135349_create_item_types_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('type'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sc_item_types'); + } +}; diff --git a/database/migrations/base_structure/sc/items/2024_03_15_135350_create_item_port_type_table.php b/database/migrations/base_structure/sc/items/2024_03_15_135350_create_item_port_type_table.php new file mode 100644 index 000000000..2ffdba382 --- /dev/null +++ b/database/migrations/base_structure/sc/items/2024_03_15_135350_create_item_port_type_table.php @@ -0,0 +1,30 @@ +id(); + $table->unsignedBigInteger('item_port_id'); + $table->unsignedBigInteger('item_type_id'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sc_item_port_type'); + } +}; diff --git a/database/migrations/base_structure/sc/items/2024_03_15_135354_create_item_sub_types_table.php b/database/migrations/base_structure/sc/items/2024_03_15_135354_create_item_sub_types_table.php new file mode 100644 index 000000000..517dbd794 --- /dev/null +++ b/database/migrations/base_structure/sc/items/2024_03_15_135354_create_item_sub_types_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('sub_type'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sc_item_sub_types'); + } +}; diff --git a/database/migrations/base_structure/sc/items/2024_03_15_135355_create_item_port_type_sub_type_table.php b/database/migrations/base_structure/sc/items/2024_03_15_135355_create_item_port_type_sub_type_table.php new file mode 100644 index 000000000..426b921ae --- /dev/null +++ b/database/migrations/base_structure/sc/items/2024_03_15_135355_create_item_port_type_sub_type_table.php @@ -0,0 +1,28 @@ +unsignedBigInteger('item_port_type_id'); + $table->unsignedBigInteger('sub_type_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sc_item_port_type_sub_type'); + } +}; diff --git a/storage/app/api/scunpacked-data b/storage/app/api/scunpacked-data index 1f8ec2257..53ee8b80e 160000 --- a/storage/app/api/scunpacked-data +++ b/storage/app/api/scunpacked-data @@ -1 +1 @@ -Subproject commit 1f8ec225733215fc7d2f3c11521762c225016465 +Subproject commit 53ee8b80e00548f283cbbe2b2b858a70b2c61d25