From 473d81abc74b584b9ba63de2d6322fb30dcf827f Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Fri, 3 May 2024 17:52:53 +0200 Subject: [PATCH] feat: Import entity tags Fixes #124 --- app/Http/Resources/SC/Item/ItemResource.php | 7 ++ app/Jobs/SC/Import/Item.php | 25 ++++++ app/Models/SC/EntityTag.php | 29 +++++++ app/Models/SC/Item/Item.php | 11 +++ app/Services/Parser/SC/ItemBaseData.php | 86 +++++++++---------- ..._22_194116_create_sc_entity_tags_table.php | 28 ++++++ ...194242_create_sc_item_entity_tag_table.php | 37 ++++++++ 7 files changed, 180 insertions(+), 43 deletions(-) create mode 100644 app/Models/SC/EntityTag.php create mode 100644 database/migrations/base_structure/sc/2024_04_22_194116_create_sc_entity_tags_table.php create mode 100644 database/migrations/base_structure/sc/items/2024_04_22_194242_create_sc_item_entity_tag_table.php diff --git a/app/Http/Resources/SC/Item/ItemResource.php b/app/Http/Resources/SC/Item/ItemResource.php index 3c4f2077a..ec0c9f068 100644 --- a/app/Http/Resources/SC/Item/ItemResource.php +++ b/app/Http/Resources/SC/Item/ItemResource.php @@ -115,6 +115,12 @@ items: new OA\Items(type: 'string'), nullable: true, ), + new OA\Property( + property: 'entity_tags', + type: 'array', + items: new OA\Items(type: 'string'), + nullable: true, + ), new OA\Property( property: 'interactions', type: 'array', @@ -207,6 +213,7 @@ public function toArray(Request $request): array ]), 'tags' => $this->defaultTags->pluck('name')->toArray(), 'required_tags' => $this->requiredTags->pluck('name')->toArray(), + 'entity_tags' => $this->entityTags->pluck('tag')->toArray(), 'interactions' => $this->interactions->pluck('name')->toArray(), 'ports' => ItemPortResource::collection($this->whenLoaded('ports')), $this->mergeWhen(! $this->onlySimpleData && $this->relationLoaded('heatData'), [ diff --git a/app/Jobs/SC/Import/Item.php b/app/Jobs/SC/Import/Item.php index b67745e63..d58c006e0 100644 --- a/app/Jobs/SC/Import/Item.php +++ b/app/Jobs/SC/Import/Item.php @@ -4,6 +4,7 @@ namespace App\Jobs\SC\Import; +use App\Models\SC\EntityTag; use App\Models\SC\Item\Interaction; use App\Models\SC\Item\ItemPort; use App\Models\SC\Item\ItemPortType; @@ -94,6 +95,7 @@ public function handle(): void $this->addTags($itemModel, $this->data, 'tags'); $this->addTags($itemModel, $this->data, 'required_tags', true); $this->addInteractions($itemModel, $this->data); + $this->addEntityTags($itemModel, $this->data); } private function createDimensionModel(\App\Models\SC\Item\Item $itemModel): void @@ -319,4 +321,27 @@ private function addInteractions($model, $data): void $model->interactions()->sync($interactions); } + + /** + * @param \App\Models\SC\Item\Item $model + * @param $data + */ + private function addEntityTags(\App\Models\SC\Item\Item $model, $data): void + { + if (empty($data['entity_tags'])) { + return; + } + + $tags = collect($data['entity_tags']) + ->map('trim') + ->map(function ($tag) { + $tag = EntityTag::query()->firstOrCreate([ + 'tag' => $tag, + ]); + + return $tag->id; + }); + + $model->entityTags()->sync($tags); + } } diff --git a/app/Models/SC/EntityTag.php b/app/Models/SC/EntityTag.php new file mode 100644 index 000000000..b667d2cb2 --- /dev/null +++ b/app/Models/SC/EntityTag.php @@ -0,0 +1,29 @@ +belongsToMany( + Item::class, + 'sc_item_entity_tag', + 'item_id', + 'entity_tag_id' + ); + } +} diff --git a/app/Models/SC/Item/Item.php b/app/Models/SC/Item/Item.php index b57b1d143..7ba5c4fce 100644 --- a/app/Models/SC/Item/Item.php +++ b/app/Models/SC/Item/Item.php @@ -13,6 +13,7 @@ use App\Models\SC\Char\PersonalWeapon\Knife; use App\Models\SC\Char\PersonalWeapon\PersonalWeapon; use App\Models\SC\Char\PersonalWeapon\PersonalWeaponMagazine; +use App\Models\SC\EntityTag; use App\Models\SC\Food\Food; use App\Models\SC\ItemSpecification\Bomb\Bomb; use App\Models\SC\ItemSpecification\Cooler; @@ -487,4 +488,14 @@ public function variants(): HasMany { return $this->hasMany(self::class, 'base_id', 'id'); } + + public function entityTags(): BelongsToMany + { + return $this->belongsToMany( + EntityTag::class, + 'sc_item_entity_tag', + 'item_id', + 'entity_tag_id' + ); + } } diff --git a/app/Services/Parser/SC/ItemBaseData.php b/app/Services/Parser/SC/ItemBaseData.php index 413222660..1f58565bd 100644 --- a/app/Services/Parser/SC/ItemBaseData.php +++ b/app/Services/Parser/SC/ItemBaseData.php @@ -17,7 +17,7 @@ public static function getData(Collection $item): ?array 'lifetime' => Arr::get($item, 'Raw.Entity.Components.SDegradationParams.MaxLifetimeHours'), 'salvageable' => Arr::get($item, 'Raw.Entity.Components.SHealthComponentParams.IsSalvagable'), 'repairable' => Arr::get($item, 'Raw.Entity.Components.SHealthComponentParams.IsRepairable'), - ], function ($entry) { + ], static function ($entry) { return $entry !== null; }); @@ -27,33 +27,34 @@ public static function getData(Collection $item): ?array $out['heat'] = self::addHeatData($item); $out['distortion'] = self::addDistortionData($item); $out['interactions'] = self::addInteractionData($item); + $out['entity_tags'] = collect($item['tags'] ?? [])->map(fn (array $tag) => $tag['value']); return $out; } private static function addPowerData(Collection $item): array { - if (!isset($item['Components']['EntityComponentPowerConnection'])) { + if (! isset($item['Components']['EntityComponentPowerConnection'])) { return []; } $basePath = 'Components.EntityComponentPowerConnection.'; return array_filter([ - 'power_base' => Arr::get($item, $basePath . 'PowerBase'), - 'power_draw' => Arr::get($item, $basePath . 'PowerDraw'), + 'power_base' => Arr::get($item, $basePath.'PowerBase'), + 'power_draw' => Arr::get($item, $basePath.'PowerDraw'), - 'throttleable' => Arr::get($item, $basePath . 'IsThrottleable'), - 'overclockable' => Arr::get($item, $basePath . 'IsOverclockable'), + 'throttleable' => Arr::get($item, $basePath.'IsThrottleable'), + 'overclockable' => Arr::get($item, $basePath.'IsOverclockable'), - 'overclock_threshold_min' => Arr::get($item, $basePath . 'OverclockThresholdMin'), - 'overclock_threshold_max' => Arr::get($item, $basePath . 'OverclockThresholdMax'), - 'overclock_performance' => Arr::get($item, $basePath . 'OverclockPerformance'), + 'overclock_threshold_min' => Arr::get($item, $basePath.'OverclockThresholdMin'), + 'overclock_threshold_max' => Arr::get($item, $basePath.'OverclockThresholdMax'), + 'overclock_performance' => Arr::get($item, $basePath.'OverclockPerformance'), - 'overpower_performance' => Arr::get($item, $basePath . 'OverpowerPerformance'), + 'overpower_performance' => Arr::get($item, $basePath.'OverpowerPerformance'), - 'power_to_em' => Arr::get($item, $basePath . 'PowerToEM'), - 'decay_rate_em' => Arr::get($item, $basePath . 'DecayRateOfEM'), + 'power_to_em' => Arr::get($item, $basePath.'PowerToEM'), + 'decay_rate_em' => Arr::get($item, $basePath.'DecayRateOfEM'), ], static function ($entry) { return $entry !== null; }); @@ -61,32 +62,32 @@ private static function addPowerData(Collection $item): array private static function addHeatData(Collection $item): array { - if (!isset($item['Components']['EntityComponentHeatConnection'])) { + if (! isset($item['Components']['EntityComponentHeatConnection'])) { return []; } $basePath = 'Components.EntityComponentHeatConnection.'; return array_filter([ - 'temperature_to_ir' => Arr::get($item, $basePath . 'TemperatureToIR'), - 'ir_temperature_threshold' => Arr::get($item, $basePath . 'StartIRTemperature'), - 'overpower_heat' => Arr::get($item, $basePath . 'OverpowerHeat'), - 'overclock_threshold_min' => Arr::get($item, $basePath . 'OverclockThresholdMinHeat'), - 'overclock_threshold_max' => Arr::get($item, $basePath . 'OverclockThresholdMaxHeat'), - 'thermal_energy_base' => Arr::get($item, $basePath . 'ThermalEnergyBase'), - 'thermal_energy_draw' => Arr::get($item, $basePath . 'ThermalEnergyDraw'), - 'thermal_conductivity' => Arr::get($item, $basePath . 'ThermalConductivity'), - 'specific_heat_capacity' => Arr::get($item, $basePath . 'SpecificHeatCapacity'), - 'mass' => Arr::get($item, $basePath . 'Mass'), - 'surface_area' => Arr::get($item, $basePath . 'SurfaceArea'), - 'start_cooling_temperature' => Arr::get($item, $basePath . 'StartCoolingTemperature'), - 'max_cooling_rate' => Arr::get($item, $basePath . 'MaxCoolingRate'), - 'max_temperature' => Arr::get($item, $basePath . 'MaxTemperature'), - 'min_temperature' => Arr::get($item, $basePath . 'MinTemperature'), - 'overheat_temperature' => Arr::get($item, $basePath . 'OverheatTemperature'), - 'recovery_temperature' => Arr::get($item, $basePath . 'RecoveryTemperature'), - 'misfire_min_temperature' => Arr::get($item, $basePath . 'MisfireMinTemperature'), - 'misfire_max_temperature' => Arr::get($item, $basePath . 'MisfireMaxTemperature'), + 'temperature_to_ir' => Arr::get($item, $basePath.'TemperatureToIR'), + 'ir_temperature_threshold' => Arr::get($item, $basePath.'StartIRTemperature'), + 'overpower_heat' => Arr::get($item, $basePath.'OverpowerHeat'), + 'overclock_threshold_min' => Arr::get($item, $basePath.'OverclockThresholdMinHeat'), + 'overclock_threshold_max' => Arr::get($item, $basePath.'OverclockThresholdMaxHeat'), + 'thermal_energy_base' => Arr::get($item, $basePath.'ThermalEnergyBase'), + 'thermal_energy_draw' => Arr::get($item, $basePath.'ThermalEnergyDraw'), + 'thermal_conductivity' => Arr::get($item, $basePath.'ThermalConductivity'), + 'specific_heat_capacity' => Arr::get($item, $basePath.'SpecificHeatCapacity'), + 'mass' => Arr::get($item, $basePath.'Mass'), + 'surface_area' => Arr::get($item, $basePath.'SurfaceArea'), + 'start_cooling_temperature' => Arr::get($item, $basePath.'StartCoolingTemperature'), + 'max_cooling_rate' => Arr::get($item, $basePath.'MaxCoolingRate'), + 'max_temperature' => Arr::get($item, $basePath.'MaxTemperature'), + 'min_temperature' => Arr::get($item, $basePath.'MinTemperature'), + 'overheat_temperature' => Arr::get($item, $basePath.'OverheatTemperature'), + 'recovery_temperature' => Arr::get($item, $basePath.'RecoveryTemperature'), + 'misfire_min_temperature' => Arr::get($item, $basePath.'MisfireMinTemperature'), + 'misfire_max_temperature' => Arr::get($item, $basePath.'MisfireMaxTemperature'), ], static function ($entry) { return $entry !== null; }); @@ -94,23 +95,23 @@ private static function addHeatData(Collection $item): array private static function addDistortionData(Collection $item): array { - if (!isset($item['Components']['SDistortionParams'])) { + if (! isset($item['Components']['SDistortionParams'])) { return []; } $basePath = 'Components.SDistortionParams.'; return array_filter([ - 'decay_rate' => Arr::get($item, $basePath . 'DecayRate'), - 'decay_delay' => Arr::get($item, $basePath . 'DecayDelay'), + 'decay_rate' => Arr::get($item, $basePath.'DecayRate'), + 'decay_delay' => Arr::get($item, $basePath.'DecayDelay'), - 'maximum' => Arr::get($item, $basePath . 'Maximum'), + 'maximum' => Arr::get($item, $basePath.'Maximum'), - 'overload_ratio' => Arr::get($item, $basePath . 'OverloadRatio'), + 'overload_ratio' => Arr::get($item, $basePath.'OverloadRatio'), - 'warning_ratio' => Arr::get($item, $basePath . 'WarningRatio'), - 'recovery_ratio' => Arr::get($item, $basePath . 'RecoveryRatio'), - 'recovery_time' => Arr::get($item, $basePath . 'RecoveryTime'), + 'warning_ratio' => Arr::get($item, $basePath.'WarningRatio'), + 'recovery_ratio' => Arr::get($item, $basePath.'RecoveryRatio'), + 'recovery_time' => Arr::get($item, $basePath.'RecoveryTime'), ], static function ($entry) { return $entry !== null; }); @@ -118,14 +119,13 @@ private static function addDistortionData(Collection $item): array private static function addInteractionData(Collection $item): array { - if (!isset($item['Components']['SEntityInteractableParams'])) { + if (! isset($item['Components']['SEntityInteractableParams'])) { return []; } $basePath = 'Components.SEntityInteractableParams.Interactable.SharedInteractions'; - - return collect(Arr::get($item, $basePath))->map(fn(array $interaction) => $interaction['Name']) + return collect(Arr::get($item, $basePath))->map(fn (array $interaction) => $interaction['Name']) ->unique() ->map('trim') ->map('strtolower') diff --git a/database/migrations/base_structure/sc/2024_04_22_194116_create_sc_entity_tags_table.php b/database/migrations/base_structure/sc/2024_04_22_194116_create_sc_entity_tags_table.php new file mode 100644 index 000000000..4c1292840 --- /dev/null +++ b/database/migrations/base_structure/sc/2024_04_22_194116_create_sc_entity_tags_table.php @@ -0,0 +1,28 @@ +id(); + $table->uuid('tag'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sc_entity_tags'); + } +}; diff --git a/database/migrations/base_structure/sc/items/2024_04_22_194242_create_sc_item_entity_tag_table.php b/database/migrations/base_structure/sc/items/2024_04_22_194242_create_sc_item_entity_tag_table.php new file mode 100644 index 000000000..b247f13fb --- /dev/null +++ b/database/migrations/base_structure/sc/items/2024_04_22_194242_create_sc_item_entity_tag_table.php @@ -0,0 +1,37 @@ +unsignedBigInteger('item_id'); + $table->unsignedBigInteger('entity_tag_id'); + + $table->foreign('item_id', 'sc_i_e_tag_item_id') + ->references('id') + ->on('sc_items') + ->onDelete('cascade'); + + $table->foreign('entity_tag_id', 'sc_i_e_tag_tag_id') + ->references('id') + ->on('sc_entity_tags') + ->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sc_item_entity_tag'); + } +};