moduleManager->isEnabled('animal_management')) { return false; } if (!$space->moduleManager->isEnabled('gallery')) { return false; } return self::hasRequiredTables(); } public static function syncSpaceAnimalGalleries(Space $space): void { if (!self::canSyncForSpace($space)) { return; } $animals = Animal::find()->where(['contentcontainer_id' => (int)$space->contentcontainer_id])->all(); $synced = 0; foreach ($animals as $animal) { if ($animal instanceof Animal) { if (self::ensureAnimalGallery($animal, $space) instanceof CustomGallery) { $synced++; } } } Yii::warning([ 'space_id' => (int)$space->id, 'contentcontainer_id' => (int)$space->contentcontainer_id, 'animal_count' => count($animals), 'synced_count' => $synced, 'has_link_table' => self::hasLinkTable(), ], 'animal_management.gallery_integration.sync'); } public static function ensureAnimalGallery(Animal $animal, ?Space $space = null): ?CustomGallery { if (!self::hasRequiredTables()) { return null; } $space = $space ?: Space::findOne(['contentcontainer_id' => (int)$animal->contentcontainer_id]); if (!$space instanceof Space || !self::canSyncForSpace($space)) { return null; } $link = self::hasLinkTable() ? AnimalGalleryLink::findOne(['animal_id' => (int)$animal->id]) : null; $gallery = null; if ($link instanceof AnimalGalleryLink) { $gallery = CustomGallery::find() ->contentContainer($space) ->where(['gallery_gallery.id' => (int)$link->gallery_id]) ->one(); } if (!$gallery instanceof CustomGallery) { $gallery = CustomGallery::find() ->contentContainer($space) ->where(['like', 'description', self::buildMarker((int)$animal->id)]) ->one(); if (!$gallery instanceof CustomGallery) { $gallery = CustomGallery::find() ->contentContainer($space) ->where(['title' => self::buildTitle($animal)]) ->one(); } } if (!$gallery instanceof CustomGallery) { $gallery = new CustomGallery(); $gallery->content->container = $space; $gallery->content->visibility = (int)$space->getDefaultContentVisibility(); $gallery->title = self::buildTitle($animal); $gallery->description = self::buildDescription($animal); try { if (!$gallery->save()) { Yii::warning($gallery->getErrors(), 'animal_management.gallery_integration.gallery_create_failed'); return null; } } catch (\Throwable $e) { Yii::warning($e->getMessage(), 'animal_management.gallery_integration.gallery_create_failed'); return null; } } else { $newTitle = self::buildTitle($animal); $newDescription = self::buildDescription($animal); $dirty = false; if ((string)$gallery->title !== $newTitle) { $gallery->title = $newTitle; $dirty = true; } if ((string)$gallery->description !== $newDescription) { $gallery->description = $newDescription; $dirty = true; } if ($dirty) { try { $gallery->save(); } catch (\Throwable $e) { Yii::warning($e->getMessage(), 'animal_management.gallery_integration.gallery_update_failed'); } } } if (self::hasLinkTable()) { if (!$link instanceof AnimalGalleryLink) { $link = new AnimalGalleryLink(); $link->animal_id = (int)$animal->id; } $link->gallery_id = (int)$gallery->id; $link->contentcontainer_id = (int)$space->contentcontainer_id; try { if (!$link->save()) { Yii::warning($link->getErrors(), 'animal_management.gallery_integration.link_save_failed'); } } catch (\Throwable $e) { Yii::warning($e->getMessage(), 'animal_management.gallery_integration.link_save_failed'); } } self::refreshGalleryThumb($animal, $gallery); return $gallery; } public static function isAnimalBackedGallery(CustomGallery $gallery): bool { return self::getAnimalByGalleryId((int)$gallery->id) instanceof Animal; } public static function getAnimalByGalleryId(int $galleryId): ?Animal { if (!self::hasRequiredTables()) { return null; } if (self::hasLinkTable()) { $link = AnimalGalleryLink::findOne(['gallery_id' => $galleryId]); if ($link instanceof AnimalGalleryLink) { return Animal::findOne(['id' => (int)$link->animal_id]); } } $gallery = CustomGallery::findOne(['id' => $galleryId]); if (!$gallery instanceof CustomGallery) { return null; } $animalId = self::extractAnimalIdFromDescription((string)$gallery->description); if ($animalId === null) { $animalId = self::extractAnimalIdFromTitle($gallery); if ($animalId === null) { return null; } } return Animal::findOne(['id' => $animalId]); } public static function getAnimalItemsQuery(CustomGallery $gallery) { $animal = self::getAnimalByGalleryId((int)$gallery->id); if (!$animal instanceof Animal) { Yii::warning([ 'gallery_id' => (int)$gallery->id, 'title' => (string)$gallery->title, 'description' => (string)$gallery->description, ], 'animal_management.gallery_integration.gallery_unmapped'); return null; } return AnimalGalleryItem::find() ->where(['animal_id' => (int)$animal->id]) ->andWhere([ 'or', ['and', ['not', ['file_path' => null]], ['!=', 'file_path', '']], ['not', ['file_id' => null]], ]) ->orderBy(['id' => SORT_DESC]); } public static function getAnimalPreviewUrl(CustomGallery $gallery): ?string { $animal = self::getAnimalByGalleryId((int)$gallery->id); if (!$animal instanceof Animal) { return null; } $item = AnimalGalleryItem::find() ->where(['animal_id' => (int)$animal->id]) ->orderBy(['id' => SORT_DESC]) ->one(); if (!$item instanceof AnimalGalleryItem) { return null; } $url = trim((string)$item->getImageUrl()); return $url !== '' ? $url : null; } public static function isAnimalGalleryEmpty(CustomGallery $gallery): ?bool { $animal = self::getAnimalByGalleryId((int)$gallery->id); if (!$animal instanceof Animal) { return null; } return !AnimalGalleryItem::find()->where(['animal_id' => (int)$animal->id])->exists(); } private static function refreshGalleryThumb(Animal $animal, CustomGallery $gallery): void { $thumbFileId = AnimalGalleryItem::find() ->where(['animal_id' => (int)$animal->id]) ->andWhere(['not', ['file_id' => null]]) ->orderBy(['id' => SORT_DESC]) ->select('file_id') ->scalar(); $thumbFileId = $thumbFileId === null ? null : (int)$thumbFileId; if ((int)($gallery->thumb_file_id ?? 0) === (int)($thumbFileId ?? 0)) { return; } $gallery->thumb_file_id = $thumbFileId; $gallery->save(false, ['thumb_file_id']); } private static function hasRequiredTables(): bool { $schema = Yii::$app->db->schema; return $schema->getTableSchema('rescue_animal', true) !== null && $schema->getTableSchema('rescue_animal_gallery_item', true) !== null && $schema->getTableSchema('gallery_gallery', true) !== null; } private static function hasLinkTable(): bool { return Yii::$app->db->schema->getTableSchema('rescue_animal_gallery_link', true) !== null; } private static function buildTitle(Animal $animal): string { return $animal->getDisplayName() . ' Gallery'; } private static function buildDescription(Animal $animal): string { return self::buildMarker((int)$animal->id); } private static function buildMarker(int $animalId): string { return '[animal-gallery:' . $animalId . ']'; } private static function extractAnimalIdFromDescription(string $description): ?int { if (!preg_match('/\[animal-gallery:(\d+)\]/', $description, $matches)) { return null; } return isset($matches[1]) ? (int)$matches[1] : null; } private static function extractAnimalIdFromTitle(CustomGallery $gallery): ?int { $container = $gallery->content->container ?? null; if (!$container instanceof Space) { return null; } $title = trim((string)$gallery->title); if ($title === '') { return null; } $titleNormalized = self::normalizeTitleToken($title); if ($titleNormalized === '') { return null; } $animals = Animal::find() ->where(['contentcontainer_id' => (int)$container->contentcontainer_id]) ->orderBy(['id' => SORT_ASC]) ->all(); foreach ($animals as $animal) { if (!$animal instanceof Animal) { continue; } $nameNormalized = self::normalizeTitleToken((string)$animal->name); if ($nameNormalized !== '' && ($nameNormalized === $titleNormalized || strpos($titleNormalized, $nameNormalized) !== false)) { return (int)$animal->id; } $uidNormalized = self::normalizeTitleToken((string)$animal->animal_uid); if ($uidNormalized !== '' && ($uidNormalized === $titleNormalized || strpos($titleNormalized, $uidNormalized) !== false)) { return (int)$animal->id; } } return null; } private static function normalizeTitleToken(string $value): string { $value = strtolower(trim($value)); if ($value === '') { return ''; } $value = preg_replace('/\bgallery\b/i', ' ', $value); $value = preg_replace('/[^a-z0-9]+/i', ' ', (string)$value); return trim((string)$value); } }