portal.mkgtu.ru/common/models/Attachment.php

703 lines
20 KiB
PHP
Raw Permalink Normal View History

2024-03-28 09:51:45 +03:00
<?php
namespace common\models;
use backend\models\UploadableFileTrait;
use common\components\AfterValidateHandler\LoggingAfterValidateHandler;
use common\components\AttachmentManager;
use common\components\changeHistoryHandler\ApplicationActiveRecordChangeHistoryHandler;
use common\components\changeHistoryHandler\decorators\AttachmentChangeHistoryDecorator;
use common\components\changeHistoryHandler\interfaces\ChangeHistoryHandlerInterface;
use common\components\changeHistoryHandler\QuestionaryActiveRecordChangeHistoryHandler;
use common\components\FilesWorker\FilesWorker;
use common\components\ini\iniGet;
use common\models\interfaces\ArchiveModelInterface;
use common\models\interfaces\AttachmentLinkableEntity;
use common\models\interfaces\FileToSendInterface;
use common\models\relation_presenters\comparison\interfaces\ICanGivePropsToCompare;
use common\models\relation_presenters\comparison\interfaces\IHaveIdentityProp;
use common\models\traits\ArchiveTrait;
use common\models\traits\HtmlPropsEncoder;
use common\modules\abiturient\models\AbiturientQuestionary;
use common\modules\abiturient\models\bachelor\BachelorApplication;
use common\modules\abiturient\models\bachelor\BachelorPreferences;
use common\modules\abiturient\models\bachelor\BachelorSpeciality;
use common\modules\abiturient\models\bachelor\BachelorTargetReception;
use common\modules\abiturient\models\bachelor\changeHistory\ChangeHistory;
use common\modules\abiturient\models\bachelor\changeHistory\ChangeHistoryClasses;
use common\modules\abiturient\models\bachelor\changeHistory\interfaces\ChangeLoggedModelInterface;
use common\modules\abiturient\models\bachelor\EducationData;
use common\modules\abiturient\models\IndividualAchievement;
use common\modules\abiturient\models\interfaces\ApplicationConnectedInterface;
use common\modules\abiturient\models\interfaces\ICanGetPathToStoreFile;
use common\modules\abiturient\models\interfaces\IHaveCallbackAfterDraftCopy;
use common\modules\abiturient\models\interfaces\OwnerConnectedInterface;
use common\modules\abiturient\models\interfaces\QuestionaryConnectedInterface;
use common\modules\abiturient\models\PassportData;
use Throwable;
use Yii;
use yii\base\InvalidConfigException;
use yii\base\UserException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\db\Exception;
use yii\db\StaleObjectException;
use yii\helpers\ArrayHelper;
use yii\helpers\Url;
use yii\web\ForbiddenHttpException;
use yii\web\ServerErrorHttpException;
class Attachment extends ActiveRecord
implements
ChangeLoggedModelInterface,
FileToSendInterface,
interfaces\AttachmentInterface,
ApplicationConnectedInterface,
QuestionaryConnectedInterface,
OwnerConnectedInterface,
ArchiveModelInterface,
IHaveIdentityProp,
ICanGetPathToStoreFile,
ICanGivePropsToCompare,
IHaveCallbackAfterDraftCopy
{
use ArchiveTrait;
use UploadableFileTrait;
use HtmlPropsEncoder;
public const SCENARIO_MARK_DELETED = 'mark_deleted';
public const SCENARIO_RECOVER = 'recover';
private $attachedEntity = null;
private $_changeHistoryHandler;
public $file;
protected function setUpChangeHistoryHandler()
{
if ($this->_changeHistoryHandler === null && $this->attachmentType) {
if ($this->attachmentType->inQuestionary()) {
$this->setChangeHistoryHandler(new QuestionaryActiveRecordChangeHistoryHandler($this));
} else {
$this->setChangeHistoryHandler(new ApplicationActiveRecordChangeHistoryHandler($this));
}
}
}
public function afterFind()
{
$this->_initAttachedEntity();
parent::afterFind();
}
public function _initAttachedEntity()
{
if (!$this->isCommon()) {
switch ($this->attachmentType->system_type) {
case AttachmentType::SYSTEM_TYPE_TARGET:
$this->attachedEntity = BachelorTargetReception::instance();
break;
case AttachmentType::SYSTEM_TYPE_PREFERENCE:
$this->attachedEntity = BachelorPreferences::instance();
break;
case AttachmentType::SYSTEM_TYPE_INDIVIDUAL_ACHIEVEMENT:
$this->attachedEntity = IndividualAchievement::instance();
break;
case AttachmentType::SYSTEM_TYPE_FULL_RECOVERY_SPECIALITY:
$this->attachedEntity = BachelorSpeciality::instance();
break;
case AttachmentType::SYSTEM_TYPE_IDENTITY_DOCUMENT:
$this->attachedEntity = PassportData::instance();
break;
case AttachmentType::SYSTEM_TYPE_EDUCATION_DOCUMENT:
$this->attachedEntity = EducationData::instance();
break;
default:
$this->attachedEntity = null;
break;
}
}
}
public static function tableName()
{
return '{{%attachment}}';
}
public static function getFileRelationTable()
{
return '{{%attachments_files}}';
}
public static function getFileRelationColumn()
{
return 'attachment_id';
}
public function behaviors()
{
return [TimestampBehavior::class];
}
public function rules()
{
return [
[
[
'questionary_id',
'application_id',
'owner_id',
'archived_at'
],
'integer'
],
[
[
'deleted',
],
'boolean'
],
[
['deleted'],
'default',
'value' => false
],
[
['attachment_type_id'],
'required',
'except' => [self::SCENARIO_MARK_DELETED]
],
[
['file'],
'file',
'extensions' => static::getExtensionsListForRules(),
'skipOnEmpty' => true,
'maxSize' => iniGet::getUploadMaxFilesize(false),
'except' => [
self::SCENARIO_MARK_DELETED,
self::SCENARIO_RECOVER
]
],
];
}
public function attributeLabels()
{
return [
'file' => Yii::t('abiturient/attachment', 'Подпись для поля "file" формы "Скан документа": `файл`'),
'deleted' => Yii::t('abiturient/attachment', 'Подпись для поля "deleted" формы "Скан документа": `Удален`'),
'filename' => Yii::t('abiturient/attachment', 'Подпись для поля "filename" формы "Скан документа": `Имя файла`'),
'application_id' => Yii::t('abiturient/attachment', 'Подпись для поля "application_id" формы "Скан документа": `Id заявления`'),
'questionary_id' => Yii::t('abiturient/attachment', 'Подпись для поля "questionary_id" формы "Скан документа": `Id Анкеты`'),
'attachment_type_id' => Yii::t('abiturient/attachment', 'Подпись для поля "attachment_type_id" формы "Скан документа": `Тип прикрепляемого файла`'),
];
}
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios[self::SCENARIO_MARK_DELETED] = ['deleted'];
$scenarios[self::SCENARIO_RECOVER] = $scenarios[self::SCENARIO_DEFAULT];
return $scenarios;
}
public static function getExtensionsListForRules(): string
{
return implode(', ', static::getExtensionsList());
}
public static function getExtensionsList(): array
{
return FilesWorker::getAllowedExtensionsToUploadList();
}
public function getAbiturientQuestionary()
{
return $this->hasOne(AbiturientQuestionary::class, ['id' => 'questionary_id']);
}
public function getAttachmentLinkDependency()
{
return [
BachelorSpeciality::class,
BachelorPreferences::class,
BachelorTargetReception::class,
IndividualAchievement::class,
UserRegulation::class,
EducationData::class,
PassportData::class,
];
}
public function getApplication()
{
return $this->hasOne(BachelorApplication::class, ['id' => 'application_id']);
}
public function getAttachmentType()
{
return $this->hasOne(AttachmentType::class, ['id' => 'attachment_type_id']);
}
public function getOwner()
{
return $this->hasOne(User::class, ['id' => 'owner_id']);
}
public function getOwnerId()
{
$abiturientQuestionary = $this->abiturientQuestionary;
if (isset($abiturientQuestionary)) {
return $abiturientQuestionary->user_id;
}
$bachelorApplication = $this->application;
if (isset($bachelorApplication)) {
return $bachelorApplication->user_id;
}
if (isset($this->owner_id)) {
return $this->owner_id;
}
throw new ServerErrorHttpException('Не удалось определить владельца файла');
}
public function checkAccess($user)
{
if ($user->isModer() || $user->isViewer()) {
return true;
} elseif ($user->id == $this->getOwnerId()) {
return true;
} else {
return false;
}
}
public function afterDelete()
{
parent::afterDelete();
$disable_history = !$this->getChangeHistoryHandler() || $this->getChangeHistoryHandler()->getDisabled();
if (!$disable_history && ArrayHelper::getValue($this, 'attachmentType.required')) {
if ($this->application_id != null) {
$application = BachelorApplication::findOne($this->application_id);
if (isset($application)) {
if ($this->scenario != self::SCENARIO_MARK_DELETED) {
$application->resetStatus();
}
}
}
}
}
public static function getNotFilledRequiredAttachmentTypeIds($attachments, $required_attachment_type_ids): array
{
if (empty($required_attachment_type_ids)) {
return [];
}
$saved_attachment_type_ids = [];
foreach ($attachments as $attachment) {
if ($attachment->attachmentType && $attachment->attachmentType->need_one_of_documents) {
$document_set_ref_id = $attachment->attachmentType->document_set_ref_id;
if ($document_set_ref_id) {
$sibling_attachment_type_ids = AttachmentType::find()
->where(['document_set_ref_id' => $document_set_ref_id])
->andWhere(['not', ['id' => $attachment->attachment_type_id]])
->select(['id'])
->column();
$saved_attachment_type_ids = array_merge($saved_attachment_type_ids, $sibling_attachment_type_ids);
}
}
$saved_attachment_type_ids[] = $attachment->attachment_type_id;
}
$saved_attachment_type_ids = array_values(array_unique($saved_attachment_type_ids));
return array_diff($required_attachment_type_ids, $saved_attachment_type_ids);
}
public function getMimeType()
{
return AttachmentManager::GetMimeType($this->getExtension());
}
public function inRegulation(): bool
{
if ($this->isNewRecord) {
return false;
}
return $this->userRegulation !== null;
}
public function getUserRegulation()
{
return $this->hasOne(UserRegulation::class, ['id' => 'user_regulation_id'])
->viaTable('{{%attachments-user_regulations}}', ['attachment_id' => 'id']);
}
public function beforeArchive()
{
$this->setScenario(Attachment::SCENARIO_MARK_DELETED);
}
public static function getArchiveColumn(): string
{
return 'deleted';
}
public static function getArchiveValue()
{
return true;
}
private function unlinkRegulation()
{
$regulation = $this->userRegulation;
if ($regulation !== null) {
$regulation->unlink('rawAttachments', $this, true);
}
}
public function safeDelete(User $user, bool $updateHistory = true): bool
{
$transaction = Yii::$app->db->beginTransaction();
if (!isset($transaction)) {
throw new UserException('Ошибка создания транзакции');
}
$is_moder = Yii::$app->user->identity->isModer();
try {
$this->unlinkRegulation();
$this->archive($updateHistory);
if (
!$is_moder &&
$updateHistory &&
$user->userRef &&
$this->application_id != null
) {
$application = BachelorApplication::findOne(['id' => $this->application_id]);
if (
$application->resetStatus(false) &&
!$application->save()
) {
throw new UserException('Ошибка обновления статуса заявления.');
}
}
if ($updateHistory) {
$this->getChangeHistoryHandler()->getDeleteHistoryAction()->proceed();
}
$transaction->commit();
} catch (Throwable $e) {
$transaction->rollBack();
throw $e;
}
return true;
}
public function silenceSafeDelete()
{
$transaction = Yii::$app->db->beginTransaction();
if (!isset($transaction)) {
throw new UserException('Ошибка создания транзакции');
}
try {
$this->unlinkRegulation();
$this->archive(false);
$transaction->commit();
} catch (\Throwable $e) {
$transaction->rollBack();
throw $e;
}
return true;
}
public function getFileDownloadUrl(): ?string
{
return Url::to(['site/download', 'id' => $this->id]);
}
public function getFileDeleteUrl(bool $make_redirect = false): ?string
{
return Url::to(['site/deletefile', 'key' => $this->id, 'redirect_back' => $make_redirect]);
}
public static function getLinkableSystemTypes()
{
return [
AttachmentType::SYSTEM_TYPE_PREFERENCE,
AttachmentType::SYSTEM_TYPE_INDIVIDUAL_ACHIEVEMENT,
AttachmentType::SYSTEM_TYPE_TARGET,
AttachmentType::SYSTEM_TYPE_FULL_RECOVERY_SPECIALITY,
AttachmentType::SYSTEM_TYPE_IDENTITY_DOCUMENT,
AttachmentType::SYSTEM_TYPE_EDUCATION_DOCUMENT,
];
}
public function isCommon(): bool
{
return $this->attachmentType->system_type === AttachmentType::SYSTEM_TYPE_COMMON;
}
public function isLinked(): bool
{
return in_array($this->attachmentType->system_type, Attachment::getLinkableSystemTypes());
}
public function getEntity(): ?ActiveQuery
{
$en = $this->attachedEntity;
if (!empty($_REQUEST['test'])){
$en = $this->entity;
var_dump($en);
echo '<pre>';
print_r($en);
echo '</pre>';
exit();
}
return $this->hasOne($en::getModel(), ['id' => $en::getEntityTableLinkAttribute()])->viaTable($en::getTableLink(), [
$en::getAttachmentTableLinkAttribute() => 'id'
]);
}
public function getLinkedEntity(): ?AttachmentLinkableEntity
{
return $this->entity;
}
public function getAttachmentTypeName(): string
{
$name = null;
if ($this->isLinked()) {
try {
$name = $this->entity->getName();
} catch (\Throwable $e) {
Yii::error("Не удалось невозможно получить связанную сущность: {$e->getMessage()}");
}
}
return ($name ?? $this->attachmentType->name);
}
public function fileExists(): bool
{
return $this->linkedFile && $this->linkedFile->fileExists();
}
public function getChangeLoggedAttributes()
{
return [
'file',
'attachment_type_id'
];
}
public function getClassTypeForChangeHistory(): int
{
return ChangeHistoryClasses::CLASS_ATTACHMENT;
}
public function getOldAttribute($name)
{
return null;
}
public function getOldAttributes()
{
return null;
}
public function getEntityChangeType(): int
{
return ChangeHistory::CHANGE_HISTORY_FILE;
}
public function setChangeHistoryHandler(ChangeHistoryHandlerInterface $handler): void
{
$this->_changeHistoryHandler = new AttachmentChangeHistoryDecorator($handler);
}
public function getChangeHistoryHandler(): ?ChangeHistoryHandlerInterface
{
$this->setUpChangeHistoryHandler();
return $this->_changeHistoryHandler;
}
public function getOldClass(): ChangeLoggedModelInterface
{
return $this;
}
public function getEntityIdentifier(): ?string
{
$attachmentType = "";
if (!($this->isCommon() || !$this->isLinked())) {
try {
$attachmentType = $this->getLinkedEntity()->getName();
} catch (\Throwable $e) {
}
}
if (!$attachmentType) {
$attachmentType = ArrayHelper::getValue($this, 'attachmentType.name');
}
return $attachmentType;
}
public function beforeDelete()
{
if (parent::beforeDelete()) {
$errorFrom = '';
$deleteSuccess = AttachmentManager::unlinkAttachmentFromAll($this);
if (!$deleteSuccess) {
$errorFrom .= "{$this->tableName()} -> {$this->id}\n";
}
if (!$deleteSuccess) {
Yii::error("Ошибка при удалении данных с портала. В таблице: {$errorFrom}");
}
$this->deleteAttachedFile();
return $deleteSuccess;
} else {
return false;
}
}
public function afterValidate()
{
(new LoggingAfterValidateHandler())
->setModel($this)
->invoke();
}
public function getIdentityString(): string
{
$attachment_type_doc_uid = ArrayHelper::getValue($this, 'attachmentType.name');
$attachment_type_name = ArrayHelper::getValue($this, 'attachmentType.documentType.ref_key');
$file_name = $this->filename;
return "{$attachment_type_doc_uid}_{$attachment_type_name}_{$file_name}";
}
public function getPropsToCompare(): array
{
return ArrayHelper::merge(
array_diff(
array_keys($this->attributes),
[
'questionary_id',
'application_id',
'owner_id',
'attachment_type_id',
]
),
[
'filename',
]
);
}
}