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

703 lines
20 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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',
]
);
}
}