chore: sync module from working instance and add install guide

This commit is contained in:
Kelin Rescue Hub
2026-04-09 14:11:34 -04:00
parent 20adb1bd1e
commit 039c12233e
23 changed files with 4577 additions and 394 deletions

View File

@@ -7,15 +7,17 @@ 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 = 10;
public int $limit = 4;
public function run()
{
@@ -25,29 +27,19 @@ class SearchAnimalProfilesBlock extends Widget
. '</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();
$perPage = max(1, $this->limit);
$page = (int)Yii::$app->request->get('animalFeedPage', 1);
if ($page < 1) {
$page = 1;
}
$totalCount = (int)$query->count();
$displayCount = $showAll ? $totalCount : min($countParam, $totalCount);
$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));
@@ -60,7 +52,8 @@ class SearchAnimalProfilesBlock extends Widget
$animals = $query
->orderBy(['updated_at' => SORT_DESC, 'id' => SORT_DESC])
->limit($displayCount)
->offset($offset)
->limit($perPage)
->all();
$animalIds = array_map(static function (Animal $animal): int {
@@ -70,9 +63,14 @@ class SearchAnimalProfilesBlock extends Widget
$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);
$hasMore = !$showAll && $displayCount < $totalCount;
$nextCount = min($displayCount + $this->limit, $totalCount);
$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)) {
@@ -84,20 +82,59 @@ class SearchAnimalProfilesBlock extends Widget
return $this->render('searchAnimalProfilesBlock', [
'animals' => $animals,
'contentContainer' => $this->contentContainer,
'queryValue' => $queryValue,
'heading' => $heading,
'tileFields' => $tileFields,
'tileFieldOverrides' => $tileFieldOverrides,
'latestMedicalVisitByAnimal' => $latestMedicalVisitByAnimal,
'animalImageUrls' => $animalImageUrls,
'animalDonationGoalsByAnimal' => $animalDonationGoalsByAnimal,
'showDonationSettingsButton' => $showDonationSettingsButton,
'totalCount' => $totalCount,
'displayCount' => $displayCount,
'hasMore' => $hasMore,
'nextCount' => $nextCount,
'showAll' => $showAll,
'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)) {

View File

@@ -7,46 +7,30 @@ use yii\helpers\Html;
/* @var Animal[] $animals */
/* @var ContentContainerActiveRecord $contentContainer */
/* @var string $queryValue */
/* @var string $heading */
/* @var array $tileFields */
/* @var array<int, array> $tileFieldOverrides */
/* @var array<int, AnimalMedicalVisit> $latestMedicalVisitByAnimal */
/* @var array<int, string> $animalImageUrls */
/* @var array<int, mixed> $animalDonationGoalsByAnimal */
/* @var bool $showDonationSettingsButton */
/* @var int $totalCount */
/* @var int $displayCount */
/* @var bool $hasMore */
/* @var int $nextCount */
/* @var bool $showAll */
/* @var int $page */
/* @var int $pageCount */
/* @var bool $hasPreviousPage */
/* @var bool $hasNextPage */
$moduleEnabled = $contentContainer->moduleManager->isEnabled('animal_management');
$allAnimalsUrl = $contentContainer->createUrl('/animal_management/animals/index');
$currentParams = Yii::$app->request->getQueryParams();
$buildProfileUrl = static function (array $overrides) use ($contentContainer, $currentParams): string {
unset($currentParams['q'], $currentParams['animalFeedCount'], $currentParams['animalFeedAll']);
$params = array_merge($currentParams, $overrides);
return $contentContainer->createUrl('/space_profiles/profile/view', $params);
};
?>
<h4 style="margin-top:0;"><?= Html::encode($heading) ?></h4>
<?php if ($moduleEnabled): ?>
<form method="get" action="<?= Html::encode($contentContainer->createUrl('/space_profiles/profile/view')) ?>" style="margin-bottom:12px;">
<div class="input-group">
<input
type="text"
class="form-control"
name="q"
value="<?= Html::encode($queryValue) ?>"
placeholder="<?= Html::encode(Yii::t('AnimalManagementModule.base', 'Search by name, species, or ID')) ?>"
>
<input type="hidden" name="animalFeedCount" value="10">
<input type="hidden" name="animalFeedAll" value="0">
<span class="input-group-btn">
<button class="btn btn-default" type="submit"><?= Yii::t('AnimalManagementModule.base', 'Search') ?></button>
</span>
</div>
</form>
<?php else: ?>
<?php if (!$moduleEnabled): ?>
<div class="well well-sm" style="margin-bottom:12px;">
<?= Yii::t('AnimalManagementModule.base', 'Animal profiles are not enabled for this rescue.') ?>
</div>
@@ -68,28 +52,36 @@ $buildProfileUrl = static function (array $overrides) use ($contentContainer, $c
'imageUrl' => $animalImageUrls[$animalId] ?? '',
'tileFields' => $tileFieldOverrides[$animalId] ?? $tileFields,
'showMedicalIcon' => true,
'showDonationSettingsButton' => $showDonationSettingsButton,
'existingDonationGoal' => $animalDonationGoalsByAnimal[$animalId] ?? null,
'tileLayoutMode' => 'rows',
]) ?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if ($moduleEnabled): ?>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
<?php if ($hasMore): ?>
<a class="btn btn-default btn-sm" href="<?= Html::encode($buildProfileUrl(['animalFeedCount' => $nextCount, 'animalFeedAll' => 0])) ?>">
<?= Yii::t('AnimalManagementModule.base', 'Show More') ?>
</a>
<?php endif; ?>
<?php if (!$showAll && $totalCount > 0): ?>
<a class="btn btn-default btn-sm" href="<?= Html::encode($buildProfileUrl(['animalFeedAll' => 1])) ?>">
<?= Yii::t('AnimalManagementModule.base', 'Show All') ?>
</a>
<?php endif; ?>
<?php if ($totalCount > 0): ?>
<span class="text-muted" style="font-size:12px;">
<?= Yii::t('AnimalManagementModule.base', '{shown} of {total} shown', ['shown' => $displayCount, 'total' => $totalCount]) ?>
</span>
<?php endif; ?>
<?php if ($moduleEnabled && $totalCount > 0): ?>
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap;">
<div class="text-muted" style="font-size:12px;">
<?= Yii::t('AnimalManagementModule.base', 'Page {page} of {pages}', ['page' => $page, 'pages' => $pageCount]) ?>
</div>
<div style="display:flex;align-items:center;gap:8px;">
<?php if ($hasPreviousPage): ?>
<a class="btn btn-default btn-sm" href="<?= Html::encode($buildProfileUrl(['animalFeedPage' => $page - 1])) ?>">
<?= Yii::t('AnimalManagementModule.base', 'Previous') ?>
</a>
<?php endif; ?>
<?php if ($hasNextPage): ?>
<a class="btn btn-default btn-sm" href="<?= Html::encode($buildProfileUrl(['animalFeedPage' => $page + 1])) ?>">
<?= Yii::t('AnimalManagementModule.base', 'Next') ?>
</a>
<?php endif; ?>
</div>
</div>
<div style="margin-top:10px;text-align:center;">
<a href="<?= Html::encode($allAnimalsUrl) ?>" style="font-weight:700;text-decoration:underline;">
<?= Yii::t('AnimalManagementModule.base', 'All Animals') ?>
</a>
</div>
<?php endif; ?>