307 lines
11 KiB
PHP
307 lines
11 KiB
PHP
<?php
|
|
|
|
namespace humhub\modules\animal_management\widgets;
|
|
|
|
use humhub\modules\animal_management\models\Animal;
|
|
use humhub\modules\animal_management\models\AnimalFieldValue;
|
|
use humhub\modules\animal_management\models\AnimalGalleryItem;
|
|
use humhub\modules\animal_management\models\AnimalMedicalVisit;
|
|
use humhub\modules\animal_management\models\forms\DisplaySettingsForm;
|
|
use humhub\modules\content\components\ContentContainerActiveRecord;
|
|
use humhub\modules\rescue_foundation\models\RescueFieldDefinition;
|
|
use Yii;
|
|
use yii\base\Widget;
|
|
|
|
class SearchAnimalProfilesBlock extends Widget
|
|
{
|
|
public ContentContainerActiveRecord $contentContainer;
|
|
public int $limit = 10;
|
|
|
|
public function run()
|
|
{
|
|
if (!$this->contentContainer->moduleManager->isEnabled('animal_management')) {
|
|
return '<div class="well well-sm" style="margin-bottom:0;">'
|
|
. Yii::t('AnimalManagementModule.base', 'Animal profiles are not enabled for this rescue.')
|
|
. '</div>';
|
|
}
|
|
|
|
$queryValue = trim((string)Yii::$app->request->get('q', ''));
|
|
$showAll = ((int)Yii::$app->request->get('animalFeedAll', 0)) === 1;
|
|
$countParam = (int)Yii::$app->request->get('animalFeedCount', $this->limit);
|
|
if ($countParam < $this->limit) {
|
|
$countParam = $this->limit;
|
|
}
|
|
if ($countParam > 200) {
|
|
$countParam = 200;
|
|
}
|
|
|
|
$query = Animal::find()->where(['contentcontainer_id' => $this->contentContainer->contentcontainer_id]);
|
|
|
|
if ($queryValue !== '') {
|
|
$query->andWhere([
|
|
'or',
|
|
['like', 'animal_uid', $queryValue],
|
|
['like', 'name', $queryValue],
|
|
['like', 'species', $queryValue],
|
|
]);
|
|
}
|
|
|
|
$totalCount = (int)$query->count();
|
|
$displayCount = $showAll ? $totalCount : min($countParam, $totalCount);
|
|
|
|
$settings = Yii::$app->getModule('animal_management')->settings->contentContainer($this->contentContainer);
|
|
$heading = trim((string)$settings->get('searchBlockHeading', DisplaySettingsForm::DEFAULT_SEARCH_BLOCK_HEADING));
|
|
if ($heading === '') {
|
|
$heading = DisplaySettingsForm::DEFAULT_SEARCH_BLOCK_HEADING;
|
|
}
|
|
|
|
$tileFieldsRaw = $settings->get('tileFields', json_encode(DisplaySettingsForm::DEFAULT_TILE_FIELDS));
|
|
$tileFields = $this->normalizeDisplayFields($tileFieldsRaw, DisplaySettingsForm::DEFAULT_TILE_FIELDS);
|
|
|
|
$animals = $query
|
|
->orderBy(['updated_at' => SORT_DESC, 'id' => SORT_DESC])
|
|
->limit($displayCount)
|
|
->all();
|
|
|
|
$animalIds = array_map(static function (Animal $animal): int {
|
|
return (int)$animal->id;
|
|
}, $animals);
|
|
|
|
$latestMedicalVisitByAnimal = $this->resolveLatestMedicalVisits($animalIds);
|
|
$animalImageUrls = $this->resolveAnimalImageUrls($animalIds, ['profile_image_url', 'profile_image', 'photo_url', 'image_url', 'photo'], false);
|
|
$tileFieldOverrides = $this->resolveDisplayFieldOverrides($animalIds, 'tile_display_fields');
|
|
|
|
$hasMore = !$showAll && $displayCount < $totalCount;
|
|
$nextCount = min($displayCount + $this->limit, $totalCount);
|
|
|
|
$viewFile = $this->getViewPath() . '/searchAnimalProfilesBlock.php';
|
|
if (!is_file($viewFile)) {
|
|
return '<div class="well well-sm" style="margin-bottom:0;">'
|
|
. Yii::t('AnimalManagementModule.base', 'Animal search is temporarily unavailable.')
|
|
. '</div>';
|
|
}
|
|
|
|
return $this->render('searchAnimalProfilesBlock', [
|
|
'animals' => $animals,
|
|
'contentContainer' => $this->contentContainer,
|
|
'queryValue' => $queryValue,
|
|
'heading' => $heading,
|
|
'tileFields' => $tileFields,
|
|
'tileFieldOverrides' => $tileFieldOverrides,
|
|
'latestMedicalVisitByAnimal' => $latestMedicalVisitByAnimal,
|
|
'animalImageUrls' => $animalImageUrls,
|
|
'totalCount' => $totalCount,
|
|
'displayCount' => $displayCount,
|
|
'hasMore' => $hasMore,
|
|
'nextCount' => $nextCount,
|
|
'showAll' => $showAll,
|
|
]);
|
|
}
|
|
|
|
private function normalizeDisplayFields($raw, array $default): array
|
|
{
|
|
if (is_string($raw)) {
|
|
$decoded = json_decode($raw, true);
|
|
if (!is_array($decoded)) {
|
|
return $default;
|
|
}
|
|
$raw = $decoded;
|
|
}
|
|
|
|
if (!is_array($raw)) {
|
|
return $default;
|
|
}
|
|
|
|
$allowed = array_keys(DisplaySettingsForm::fieldOptions());
|
|
$normalized = [];
|
|
foreach ($raw as $field) {
|
|
$field = trim((string)$field);
|
|
if ($field === '' || !in_array($field, $allowed, true)) {
|
|
continue;
|
|
}
|
|
if (!in_array($field, $normalized, true)) {
|
|
$normalized[] = $field;
|
|
}
|
|
}
|
|
|
|
return !empty($normalized) ? $normalized : $default;
|
|
}
|
|
|
|
private function resolveLatestMedicalVisits(array $animalIds): array
|
|
{
|
|
$animalIds = array_values(array_unique(array_map('intval', $animalIds)));
|
|
if (empty($animalIds)) {
|
|
return [];
|
|
}
|
|
|
|
$visits = AnimalMedicalVisit::find()
|
|
->where(['animal_id' => $animalIds])
|
|
->orderBy(['animal_id' => SORT_ASC, 'visit_at' => SORT_DESC, 'id' => SORT_DESC])
|
|
->all();
|
|
|
|
$result = [];
|
|
foreach ($visits as $visit) {
|
|
$animalId = (int)$visit->animal_id;
|
|
if (!isset($result[$animalId])) {
|
|
$result[$animalId] = $visit;
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
private function resolveAnimalImageUrls(array $animalIds, array $imageFieldOrder = [], bool $allowGalleryFallback = false): array
|
|
{
|
|
$animalIds = array_values(array_unique(array_map('intval', $animalIds)));
|
|
if (empty($animalIds)) {
|
|
return [];
|
|
}
|
|
|
|
if (!class_exists(RescueFieldDefinition::class)
|
|
|| Yii::$app->db->schema->getTableSchema('rescue_field_definition', true) === null
|
|
|| Yii::$app->db->schema->getTableSchema('rescue_animal_field_value', true) === null
|
|
) {
|
|
return [];
|
|
}
|
|
|
|
if (empty($imageFieldOrder)) {
|
|
$imageFieldOrder = ['cover_image_url', 'profile_image_url', 'photo_url', 'image_url', 'profile_image', 'photo'];
|
|
}
|
|
|
|
$definitions = RescueFieldDefinition::find()
|
|
->select(['id', 'field_key'])
|
|
->where([
|
|
'module_id' => 'animal_management',
|
|
'group_key' => 'animal_profile',
|
|
'field_key' => $imageFieldOrder,
|
|
'is_active' => 1,
|
|
])
|
|
->all();
|
|
|
|
if (empty($definitions)) {
|
|
return [];
|
|
}
|
|
|
|
$definitionPriority = [];
|
|
foreach ($definitions as $definition) {
|
|
$priority = array_search((string)$definition->field_key, $imageFieldOrder, true);
|
|
$definitionPriority[(int)$definition->id] = $priority === false ? 999 : (int)$priority;
|
|
}
|
|
|
|
if (empty($definitionPriority)) {
|
|
return [];
|
|
}
|
|
|
|
$valueRows = AnimalFieldValue::find()
|
|
->where(['animal_id' => $animalIds, 'field_definition_id' => array_keys($definitionPriority)])
|
|
->all();
|
|
|
|
$imageUrls = [];
|
|
$chosenPriorityByAnimal = [];
|
|
foreach ($valueRows as $valueRow) {
|
|
$animalId = (int)$valueRow->animal_id;
|
|
$valueText = trim((string)$valueRow->value_text);
|
|
if ($valueText === '') {
|
|
continue;
|
|
}
|
|
|
|
$priority = $definitionPriority[(int)$valueRow->field_definition_id] ?? 999;
|
|
if (!isset($chosenPriorityByAnimal[$animalId]) || $priority < $chosenPriorityByAnimal[$animalId]) {
|
|
$chosenPriorityByAnimal[$animalId] = $priority;
|
|
$imageUrls[$animalId] = $valueText;
|
|
}
|
|
}
|
|
|
|
$missingAnimalIds = [];
|
|
foreach ($animalIds as $animalId) {
|
|
if (!isset($imageUrls[$animalId])) {
|
|
$missingAnimalIds[] = (int)$animalId;
|
|
}
|
|
}
|
|
|
|
if ($allowGalleryFallback && !empty($missingAnimalIds) && Yii::$app->db->schema->getTableSchema('rescue_animal_gallery_item', true) !== null) {
|
|
$galleryItems = AnimalGalleryItem::find()
|
|
->where(['animal_id' => $missingAnimalIds])
|
|
->orderBy(['animal_id' => SORT_ASC, 'id' => SORT_DESC])
|
|
->all();
|
|
|
|
foreach ($galleryItems as $galleryItem) {
|
|
$animalId = (int)$galleryItem->animal_id;
|
|
if (isset($imageUrls[$animalId])) {
|
|
continue;
|
|
}
|
|
|
|
$url = trim((string)$galleryItem->getImageUrl());
|
|
if ($url === '') {
|
|
continue;
|
|
}
|
|
|
|
$imageUrls[$animalId] = $url;
|
|
}
|
|
}
|
|
|
|
return $imageUrls;
|
|
}
|
|
|
|
private function resolveDisplayFieldOverrides(array $animalIds, string $fieldKey): array
|
|
{
|
|
$animalIds = array_values(array_unique(array_map('intval', $animalIds)));
|
|
if (empty($animalIds)) {
|
|
return [];
|
|
}
|
|
|
|
if (!class_exists(RescueFieldDefinition::class)
|
|
|| Yii::$app->db->schema->getTableSchema('rescue_field_definition', true) === null
|
|
|| Yii::$app->db->schema->getTableSchema('rescue_animal_field_value', true) === null
|
|
) {
|
|
return [];
|
|
}
|
|
|
|
$definition = RescueFieldDefinition::findOne([
|
|
'module_id' => 'animal_management',
|
|
'group_key' => 'animal_profile',
|
|
'field_key' => $fieldKey,
|
|
]);
|
|
|
|
if (!$definition instanceof RescueFieldDefinition) {
|
|
return [];
|
|
}
|
|
|
|
$rows = AnimalFieldValue::find()
|
|
->where(['animal_id' => $animalIds, 'field_definition_id' => (int)$definition->id])
|
|
->all();
|
|
|
|
$allowed = array_keys(DisplaySettingsForm::fieldOptions());
|
|
$result = [];
|
|
foreach ($rows as $row) {
|
|
$raw = trim((string)$row->value_text);
|
|
if ($raw === '') {
|
|
continue;
|
|
}
|
|
|
|
$decoded = json_decode($raw, true);
|
|
if (!is_array($decoded)) {
|
|
$decoded = array_map('trim', explode(',', $raw));
|
|
}
|
|
|
|
$normalized = [];
|
|
foreach ($decoded as $field) {
|
|
$field = trim((string)$field);
|
|
if ($field === '' || !in_array($field, $allowed, true)) {
|
|
continue;
|
|
}
|
|
|
|
if (!in_array($field, $normalized, true)) {
|
|
$normalized[] = $field;
|
|
}
|
|
}
|
|
|
|
if (!empty($normalized)) {
|
|
$result[(int)$row->animal_id] = $normalized;
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|