344 lines
12 KiB
PHP
344 lines
12 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\animal_management\permissions\ManageAnimals;
|
|
use humhub\modules\content\components\ContentContainerActiveRecord;
|
|
use humhub\modules\rescue_foundation\models\RescueFieldDefinition;
|
|
use humhub\modules\space\models\Space;
|
|
use Yii;
|
|
use yii\base\Widget;
|
|
|
|
class SearchAnimalProfilesBlock extends Widget
|
|
{
|
|
public ContentContainerActiveRecord $contentContainer;
|
|
public int $limit = 4;
|
|
|
|
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>';
|
|
}
|
|
|
|
$query = Animal::find()->where(['contentcontainer_id' => $this->contentContainer->contentcontainer_id]);
|
|
$totalCount = (int)$query->count();
|
|
$perPage = max(1, $this->limit);
|
|
$page = (int)Yii::$app->request->get('animalFeedPage', 1);
|
|
if ($page < 1) {
|
|
$page = 1;
|
|
}
|
|
|
|
$pageCount = max(1, (int)ceil($totalCount / $perPage));
|
|
if ($page > $pageCount) {
|
|
$page = $pageCount;
|
|
}
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
$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])
|
|
->offset($offset)
|
|
->limit($perPage)
|
|
->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');
|
|
$animalDonationGoalsByAnimal = $this->resolveAnimalDonationGoals($animalIds);
|
|
|
|
$canManageAnimals = $this->contentContainer->can(ManageAnimals::class)
|
|
|| ($this->contentContainer instanceof Space && $this->contentContainer->isAdmin());
|
|
$showDonationSettingsButton = $canManageAnimals && $this->contentContainer->moduleManager->isEnabled('donations');
|
|
|
|
$hasPreviousPage = $page > 1;
|
|
$hasNextPage = $page < $pageCount;
|
|
|
|
$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,
|
|
'heading' => $heading,
|
|
'tileFields' => $tileFields,
|
|
'tileFieldOverrides' => $tileFieldOverrides,
|
|
'latestMedicalVisitByAnimal' => $latestMedicalVisitByAnimal,
|
|
'animalImageUrls' => $animalImageUrls,
|
|
'animalDonationGoalsByAnimal' => $animalDonationGoalsByAnimal,
|
|
'showDonationSettingsButton' => $showDonationSettingsButton,
|
|
'totalCount' => $totalCount,
|
|
'page' => $page,
|
|
'pageCount' => $pageCount,
|
|
'hasPreviousPage' => $hasPreviousPage,
|
|
'hasNextPage' => $hasNextPage,
|
|
]);
|
|
}
|
|
|
|
private function resolveAnimalDonationGoals(array $animalIds): array
|
|
{
|
|
$animalIds = array_values(array_unique(array_map('intval', $animalIds)));
|
|
if (empty($animalIds)
|
|
|| !$this->contentContainer->moduleManager->isEnabled('donations')
|
|
) {
|
|
return [];
|
|
}
|
|
|
|
$donationGoalClass = 'humhub\\modules\\donations\\models\\DonationGoal';
|
|
if (!class_exists($donationGoalClass)
|
|
|| Yii::$app->db->schema->getTableSchema($donationGoalClass::tableName(), true) === null
|
|
) {
|
|
return [];
|
|
}
|
|
|
|
$goals = $donationGoalClass::find()
|
|
->where([
|
|
'contentcontainer_id' => $this->contentContainer->contentcontainer_id,
|
|
'goal_type' => $donationGoalClass::TYPE_ANIMAL,
|
|
])
|
|
->andWhere(['target_animal_id' => $animalIds])
|
|
->orderBy(['is_active' => SORT_DESC, 'id' => SORT_DESC])
|
|
->all();
|
|
|
|
$result = [];
|
|
foreach ($goals as $goal) {
|
|
$animalId = (int)$goal->target_animal_id;
|
|
if ($animalId <= 0 || isset($result[$animalId])) {
|
|
continue;
|
|
}
|
|
|
|
$result[$animalId] = $goal;
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|