diff --git a/install/Install.php b/install/Install.php index 436956cf..34c1cebb 100644 --- a/install/Install.php +++ b/install/Install.php @@ -274,17 +274,14 @@ public function getMigrationsToDo(string $current_version): array public static function getOrCreateSource(string $name, int $fallback_level = 1, int $is_carbon_intensity_source = 1): int { $source = new Source(); - $source->getFromDBByCrit(['name' => $name]); + $source->getOrCreate([ + 'fallback_level' => $fallback_level, + 'is_carbon_intensity_source' => $is_carbon_intensity_source, + ], [ + 'name' => $name + ]); if ($source->isNewItem()) { - $source->add([ - 'name' => $name, - 'fallback_level' => $fallback_level, - 'is_carbon_intensity_source' => $is_carbon_intensity_source, - ]); - /** @phpstan-ignore if.alwaysTrue */ - if ($source->isNewItem()) { - throw new \RuntimeException("Failed to create carbon intensity source '$name' in DB"); - } + throw new \RuntimeException("Failed to create carbon intensity source '$name' in DB"); } return $source->getID(); } @@ -299,18 +296,15 @@ public static function getOrCreateSource(string $name, int $fallback_level = 1, public static function getOrCreateZone(string $name, int $source_id): int { $zone = new Zone(); + $zone->getOrCreate([ + 'plugin_carbon_sources_id_historical' => $source_id, + ], [ + 'name' => $name, + ]); $zone->getFromDBByCrit(['name' => $name]); if ($zone->isNewItem()) { - $zone->add([ - 'name' => $name, - 'plugin_carbon_sources_id_historical' => $source_id, - ]); - /** @phpstan-ignore if.alwaysTrue */ - if ($zone->isNewItem()) { - throw new \RuntimeException("Failed to create zone '$name' in DB"); - } + throw new \RuntimeException("Failed to create zone '$name' in DB"); } - return $zone->getID(); } diff --git a/src/DataSource/CarbonIntensity/AbstractClient.php b/src/DataSource/CarbonIntensity/AbstractClient.php index 619f862f..6f6f6956 100644 --- a/src/DataSource/CarbonIntensity/AbstractClient.php +++ b/src/DataSource/CarbonIntensity/AbstractClient.php @@ -54,27 +54,6 @@ abstract public function getDataInterval(): string; abstract protected function formatOutput(array $response, int $step): array; - /** - * Create the source in the database - * Should not be called as it shall be created at plugin installation - * - * @return Source - */ - protected function getOrCreateSource(): ?Source - { - $source = new Source(); - if (!$source->getFromDBByCrit(['name' => $this->getSourceName()])) { - $source->add([ - 'name' => $this->getSourceName(), - ]); - if ($source->isNewItem()) { - return null; - } - } - - return $source; - } - /** * Download all data for a single day from the datasource * diff --git a/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php b/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php index 9c27d8fc..3905d21b 100644 --- a/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php +++ b/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php @@ -101,8 +101,11 @@ public function getHardStartDate(): DateTimeImmutable public function createZones(): int { - $source = $this->getOrCreateSource(); - if ($source === null) { + $source = new Source(); + $source->getOrCreate([], [ + ['name' => $this->getSourceName()] + ]); + if ($source->isNewItem()) { return -1; } $source_id = $source->getID(); diff --git a/src/DataSource/CarbonIntensity/Rte/Client.php b/src/DataSource/CarbonIntensity/Rte/Client.php index 94a525cb..7db27a72 100644 --- a/src/DataSource/CarbonIntensity/Rte/Client.php +++ b/src/DataSource/CarbonIntensity/Rte/Client.php @@ -107,28 +107,35 @@ public function getSupportedZones(): array public function createZones(): int { - $source = $this->getOrCreateSource(); - if ($source === null) { + $source = new source(); + $source->getOrCreate([], [ + 'name' => $this->getSourceName(), + ]); + if ($source->isNewItem()) { return -1; } $source_id = $source->getID(); $zone = new Zone(); - $input = [ - 'name' => 'France', - ]; - if ($zone->getFromDBByCrit($input) === false) { - if (!$zone->add($input)) { - return -1; - } + $zone->getOrCreate([], [ + 'name' => 'France' + ]); + if ($zone->isNewItem()) { + return -1; } + $zone_id = $zone->getID(); $source_zone = new Source_Zone(); - $source_zone->add([ + $source_zone->getOrCreate([ + 'code' => '', + 'is_download_enabled' => Toolbox::isLocationExistForZone($zone->fields['name']) + ], [ Source::getForeignKeyField() => $source_id, - Zone::getForeignKeyField() => $zone->getID(), - 'is_download_enabled' => Toolbox::isLocationExistForZone($zone->fields['name']), + Zone::getForeignKeyField() => $zone_id ]); + if ($source_zone->isNewItem()) { + return -1; + } $this->setZoneSetupComplete(); return 1; } diff --git a/src/Source.php b/src/Source.php index 3a71b24a..a15b2773 100644 --- a/src/Source.php +++ b/src/Source.php @@ -150,4 +150,22 @@ public function getDownloadableSources(): array ]); return iterator_to_array($iterator); } + + /** + * get or create an item + * + * @param array $params + * @param array $where + * @return self|null + */ + public function getOrCreate(array $params, array $where): ?self + { + if (!$this->getFromDBByCrit($where)) { + $this->add(array_merge($where, $params)); + return $this; + } + + $this->update(array_merge($where, $params, ['id' => $this->getID()])); + return $this; + } } diff --git a/src/Source_Zone.php b/src/Source_Zone.php index a7be038a..62fa62cc 100644 --- a/src/Source_Zone.php +++ b/src/Source_Zone.php @@ -481,4 +481,22 @@ public function getFromDbByItem(CommonDBTM $item): bool return $this->getFromDBByRequest($request); } + + /** + * get or create an item + * + * @param array $params + * @param array $where + * @return self|null + */ + public function getOrCreate(array $params, array $where): ?self + { + if (!$this->getFromDBByCrit($where)) { + $this->add(array_merge($where, $params)); + return $this; + } + + $this->update(array_merge($where, $params, ['id' => $this->getID()])); + return $this; + } } diff --git a/src/Zone.php b/src/Zone.php index a510c378..af25b1cb 100644 --- a/src/Zone.php +++ b/src/Zone.php @@ -370,4 +370,22 @@ public static function getRestrictBySourceCondition(int $source_id): array ] ]; } + + /** + * get or create an item + * + * @param array $params + * @param array $where + * @return self|null + */ + public function getOrCreate(array $params, array $where): ?self + { + if (!$this->getFromDBByCrit($where)) { + $this->add(array_merge($where, $params)); + return $this; + } + + $this->update(array_merge($where, $params, ['id' => $this->getID()])); + return $this; + } } diff --git a/tests/units/SourceTest.php b/tests/units/SourceTest.php index 3e81774d..e9cce5ac 100644 --- a/tests/units/SourceTest.php +++ b/tests/units/SourceTest.php @@ -177,4 +177,24 @@ public function testGetDownloadableSources() $new_count = $instance->getDownloadableSources(); $this->assertEquals(0, count($new_count) - count($original_count)); } + + public function testGetOrCreate() + { + // Test we can create a non existing item + $instance = new Source(); + $where = ['name' => 'to becreated']; + $this->count(0, $instance->find($where)); + $instance->getOrCreate([], $where); + $this->count(1, $instance->find($where)); + + // Test we find an existing instance + $instance_2 = new Source(); + $instance_2->getOrCreate([], $where); + $this->assertSame($instance->getID(), $instance_2->getID()); + + // Test we can update an existing item + $instance_3 = new source(); + $instance_3->getOrCreate(['fallback_level' => 2], $where); + $this->assertEquals(2, $instance_3->fields['fallback_level']); + } } diff --git a/tests/units/Source_ZoneTest.php b/tests/units/Source_ZoneTest.php index 57b78b0b..e66a4292 100644 --- a/tests/units/Source_ZoneTest.php +++ b/tests/units/Source_ZoneTest.php @@ -268,4 +268,31 @@ public function testGetFallbackFromDB() $success = $instance->getFallbackFromDB($source_zone); $this->assertFalse($success); } + + public function testGetOrCreate() + { + // Test we can create a non existing item + $instance = new Source_Zone(); + $source_fk = getForeignKeyFieldForItemType(Source::class); + $zone_fk = getForeignKeyFieldForItemType(Zone::class); + $source = $this->createItem(Source::class); + $zone = $this->createItem(Zone::class); + $where = [ + $source_fk => $source->getID(), + $zone_fk => $zone->getID(), + ]; + $this->count(0, $instance->find($where)); + $instance->getOrCreate([], $where); + $this->count(1, $instance->find($where)); + + // Test we find an existing instance + $instance_2 = new Source_Zone(); + $instance_2->getOrCreate([], $where); + $this->assertSame($instance->getID(), $instance_2->getID()); + + // Test we can update an existing item + $instance_3 = new Source_Zone(); + $instance_3->getOrCreate(['code' => 'FOO'], $where); + $this->assertEquals('FOO', $instance_3->fields['code']); + } } diff --git a/tests/units/ZoneTest.php b/tests/units/ZoneTest.php index 9cfc97af..1d1b2a48 100644 --- a/tests/units/ZoneTest.php +++ b/tests/units/ZoneTest.php @@ -39,6 +39,7 @@ use GlpiPlugin\Carbon\Zone; use Location as GlpiLocation; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; #[CoversClass(Zone::class)] class ZoneTest extends DbTestCase @@ -199,4 +200,19 @@ public function testGetByItem() $this->assertTrue($zone->getByItem($item, null, true)); $this->assertEquals($zone->getID(), $expected_zone->getID()); } + + public function testGetOrCreate() + { + // Test we can create a non existing item + $instance = new Zone(); + $where = ['name' => 'to becreated']; + $this->count(0, $instance->find($where)); + $instance->getOrCreate([], $where); + $this->count(1, $instance->find($where)); + + // Test we find an existing instance + $instance_2 = new Zone(); + $instance_2->getOrCreate([], $where); + $this->assertSame($instance->getID(), $instance_2->getID()); + } }