272 lines
9.4 KiB
PHP
272 lines
9.4 KiB
PHP
<?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;
|
|
}
|
|
}
|