Initial import of animal_management module
This commit is contained in:
343
services/GalleryIntegrationService.php
Normal file
343
services/GalleryIntegrationService.php
Normal file
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
|
||||
namespace humhub\modules\animal_management\services;
|
||||
|
||||
use humhub\modules\animal_management\models\Animal;
|
||||
use humhub\modules\animal_management\models\AnimalGalleryItem;
|
||||
use humhub\modules\animal_management\models\AnimalGalleryLink;
|
||||
use humhub\modules\gallery\models\CustomGallery;
|
||||
use humhub\modules\space\models\Space;
|
||||
use Yii;
|
||||
|
||||
class GalleryIntegrationService
|
||||
{
|
||||
public static function canSyncForSpace(Space $space): bool
|
||||
{
|
||||
if (!$space->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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user