chore: bootstrap module from working instance and add install guide
This commit is contained in:
271
models/forms/DonationGoalForm.php
Normal file
271
models/forms/DonationGoalForm.php
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
namespace humhub\modules\donations\models\forms;
|
||||
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\donations\models\DonationGoal;
|
||||
use humhub\modules\donations\models\DonationProviderConfig;
|
||||
use humhub\modules\rescue_foundation\components\UploadStandards;
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use yii\helpers\FileHelper;
|
||||
use yii\web\UploadedFile;
|
||||
|
||||
class DonationGoalForm extends Model
|
||||
{
|
||||
public ContentContainerActiveRecord $contentContainer;
|
||||
|
||||
public $id = null;
|
||||
public $goal_type = DonationGoal::TYPE_RESCUE_GENERAL;
|
||||
public $target_animal_id = null;
|
||||
public $title = '';
|
||||
public $description = '';
|
||||
public $image_path = '';
|
||||
public UploadedFile|string|null $imageFile = null;
|
||||
public $imageGalleryPath = '';
|
||||
public $target_amount = 0.0;
|
||||
public $current_amount = 0.0;
|
||||
public $is_active = true;
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['goal_type', 'title', 'target_amount'], 'required'],
|
||||
[['id', 'target_animal_id'], 'integer'],
|
||||
[['description'], 'string'],
|
||||
[['target_amount', 'current_amount'], 'number', 'min' => 0],
|
||||
[['is_active'], 'boolean'],
|
||||
[['goal_type'], 'in', 'range' => array_keys(DonationGoal::goalTypeOptions())],
|
||||
[['title'], 'string', 'max' => 190],
|
||||
[['image_path'], 'string', 'max' => 255],
|
||||
[['imageGalleryPath'], 'string', 'max' => 500],
|
||||
[['imageGalleryPath'], 'validateGalleryImageSelection'],
|
||||
[['imageFile'], 'file',
|
||||
'skipOnEmpty' => true,
|
||||
'extensions' => UploadStandards::imageExtensions(),
|
||||
'checkExtensionByMimeType' => true,
|
||||
'mimeTypes' => UploadStandards::imageMimeTypes(),
|
||||
'maxSize' => UploadStandards::IMAGE_MAX_BYTES,
|
||||
],
|
||||
[['target_animal_id'], 'required', 'when' => function (self $model) {
|
||||
return $model->goal_type === DonationGoal::TYPE_ANIMAL;
|
||||
}, 'whenClient' => "function () { return $('#donationgoalform-goal_type').val() === 'animal'; }"],
|
||||
];
|
||||
}
|
||||
|
||||
public function attributeLabels()
|
||||
{
|
||||
return [
|
||||
'target_animal_id' => Yii::t('DonationsModule.base', 'Target Animal'),
|
||||
'target_amount' => Yii::t('DonationsModule.base', 'Target Amount'),
|
||||
'current_amount' => Yii::t('DonationsModule.base', 'Current Amount'),
|
||||
'imageGalleryPath' => Yii::t('DonationsModule.base', 'Image'),
|
||||
'imageFile' => Yii::t('DonationsModule.base', 'Image Upload'),
|
||||
];
|
||||
}
|
||||
|
||||
public function loadFromGoal(DonationGoal $goal): void
|
||||
{
|
||||
$this->id = (int)$goal->id;
|
||||
$this->goal_type = (string)$goal->goal_type;
|
||||
$this->target_animal_id = $goal->target_animal_id !== null ? (int)$goal->target_animal_id : null;
|
||||
$this->title = (string)$goal->title;
|
||||
$this->description = (string)$goal->description;
|
||||
$this->image_path = (string)$goal->image_path;
|
||||
$this->imageGalleryPath = (string)$goal->image_path;
|
||||
$this->target_amount = (float)$goal->target_amount;
|
||||
$this->current_amount = (float)$goal->current_amount;
|
||||
$this->is_active = (int)$goal->is_active === 1;
|
||||
}
|
||||
|
||||
public function save(): ?DonationGoal
|
||||
{
|
||||
if (!$this->validate()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$goal = null;
|
||||
if ($this->id) {
|
||||
$goal = DonationGoal::findOne([
|
||||
'id' => $this->id,
|
||||
'contentcontainer_id' => $this->contentContainer->contentcontainer_id,
|
||||
]);
|
||||
}
|
||||
|
||||
if (!$goal instanceof DonationGoal) {
|
||||
$goal = new DonationGoal();
|
||||
$goal->contentcontainer_id = $this->contentContainer->contentcontainer_id;
|
||||
}
|
||||
|
||||
$goal->goal_type = $this->goal_type;
|
||||
$goal->target_animal_id = $this->goal_type === DonationGoal::TYPE_ANIMAL ? (int)$this->target_animal_id : null;
|
||||
$goal->title = trim($this->title);
|
||||
$goal->description = trim($this->description);
|
||||
$goal->image_path = trim((string)$goal->image_path);
|
||||
$goal->target_amount = $this->target_amount;
|
||||
$goal->current_amount = $this->current_amount;
|
||||
$goal->currency = $this->resolveDefaultCurrency();
|
||||
$goal->is_active = $this->is_active ? 1 : 0;
|
||||
|
||||
if (!$goal->save()) {
|
||||
$this->addErrors($goal->getErrors());
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->imageFile instanceof UploadedFile) {
|
||||
$stored = $this->storeImage($this->imageFile, $goal);
|
||||
if ($stored === null) {
|
||||
$this->addError('imageFile', Yii::t('DonationsModule.base', 'Could not upload goal image.'));
|
||||
return null;
|
||||
}
|
||||
$goal->image_path = $stored;
|
||||
} else {
|
||||
$selectedFromGallery = trim((string)$this->imageGalleryPath);
|
||||
if ($selectedFromGallery !== '') {
|
||||
$goal->image_path = $selectedFromGallery;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$goal->save()) {
|
||||
$this->addErrors($goal->getErrors());
|
||||
return null;
|
||||
}
|
||||
|
||||
return $goal;
|
||||
}
|
||||
|
||||
public function validateGalleryImageSelection(string $attribute): void
|
||||
{
|
||||
$value = trim((string)$this->$attribute);
|
||||
if ($value === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->goal_type !== DonationGoal::TYPE_ANIMAL || (int)$this->target_animal_id <= 0) {
|
||||
if (preg_match('/^(https?:\/\/|\/)/i', $value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->addError($attribute, Yii::t('DonationsModule.base', 'Please select a valid image source.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$options = $this->getGalleryImageOptionsForAnimal((int)$this->target_animal_id);
|
||||
if (!isset($options[$value])) {
|
||||
$this->addError($attribute, Yii::t('DonationsModule.base', 'Please select an image from this animal gallery or upload a new one.'));
|
||||
}
|
||||
}
|
||||
|
||||
public function getAnimalOptions(): array
|
||||
{
|
||||
$animalClass = 'humhub\\modules\\animal_management\\models\\Animal';
|
||||
if (!class_exists($animalClass)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$tableName = $animalClass::tableName();
|
||||
if (Yii::$app->db->schema->getTableSchema($tableName, true) === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$animals = $animalClass::find()
|
||||
->where(['contentcontainer_id' => $this->contentContainer->contentcontainer_id])
|
||||
->orderBy(['name' => SORT_ASC, 'id' => SORT_ASC])
|
||||
->all();
|
||||
|
||||
$options = [];
|
||||
foreach ($animals as $animal) {
|
||||
$label = method_exists($animal, 'getDisplayName')
|
||||
? (string)$animal->getDisplayName()
|
||||
: trim((string)($animal->name ?? ''));
|
||||
|
||||
if ($label === '') {
|
||||
$label = 'Animal #' . (int)$animal->id;
|
||||
}
|
||||
|
||||
$options[(int)$animal->id] = $label;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function getGalleryImageOptionsForAnimal(int $animalId): array
|
||||
{
|
||||
$animalGalleryClass = 'humhub\\modules\\animal_management\\models\\AnimalGalleryItem';
|
||||
if (!class_exists($animalGalleryClass)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (Yii::$app->db->schema->getTableSchema($animalGalleryClass::tableName(), true) === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$items = $animalGalleryClass::find()
|
||||
->where(['animal_id' => $animalId])
|
||||
->orderBy(['id' => SORT_DESC])
|
||||
->all();
|
||||
|
||||
$options = [];
|
||||
foreach ($items as $item) {
|
||||
$url = trim((string)$item->getImageUrl());
|
||||
if ($url === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$options[$url] = Yii::t('DonationsModule.base', 'Gallery Image #{id}', [
|
||||
'id' => (int)$item->id,
|
||||
]);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
private function resolveDefaultCurrency(): string
|
||||
{
|
||||
$config = DonationProviderConfig::findOne([
|
||||
'contentcontainer_id' => $this->contentContainer->contentcontainer_id,
|
||||
]);
|
||||
|
||||
if ($config instanceof DonationProviderConfig) {
|
||||
$currency = strtoupper(trim((string)$config->default_currency));
|
||||
if ($currency !== '') {
|
||||
return $currency;
|
||||
}
|
||||
}
|
||||
|
||||
return 'USD';
|
||||
}
|
||||
|
||||
private function storeImage(UploadedFile $file, DonationGoal $goal): ?string
|
||||
{
|
||||
$random = Yii::$app->security->generateRandomString(8);
|
||||
$extension = strtolower((string)$file->extension);
|
||||
$fileName = 'goal-' . (int)$goal->id . '-' . time() . '-' . $random . '.' . $extension;
|
||||
|
||||
$candidateDirs = [
|
||||
'/uploads/donations/goals/' . (int)$goal->id,
|
||||
'/uploads/donations-runtime/goals/' . (int)$goal->id,
|
||||
];
|
||||
|
||||
foreach ($candidateDirs as $relativeDir) {
|
||||
$absoluteDir = Yii::getAlias('@webroot') . $relativeDir;
|
||||
try {
|
||||
FileHelper::createDirectory($absoluteDir, 0775, true);
|
||||
} catch (\Throwable $e) {
|
||||
Yii::warning($e->getMessage(), 'donations.goal_image_upload_dir');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_dir($absoluteDir) || !is_writable($absoluteDir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$absolutePath = $absoluteDir . '/' . $fileName;
|
||||
if ($file->saveAs($absolutePath)) {
|
||||
return $relativeDir . '/' . $fileName;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user