portal.mkgtu.ru/common/modules/abiturient/models/services/FullPackageFilesSyncer.php

343 lines
10 KiB
PHP
Raw Normal View History

2024-03-28 09:51:45 +03:00
<?php
namespace common\modules\abiturient\models\services;
use common\components\AttachmentManager;
use common\models\dictionary\DocumentType;
use common\models\interfaces\FileToSendInterface;
use common\models\SendingFile;
use common\models\ToAssocCaster;
use common\models\User;
use common\modules\abiturient\models\AbiturientQuestionary;
use common\modules\abiturient\models\bachelor\BachelorApplication;
use common\modules\abiturient\models\ReceivingFile;
use geoffry304\enveditor\exceptions\FileNotFoundException;
use Throwable;
use Yii;
use yii\helpers\FileHelper;
class FullPackageFilesSyncer extends \yii\base\BaseObject
{
protected $application;
protected $questionary;
protected $sent_files_with_info = [];
protected $received_files = [];
protected $files_sent = false;
protected $processed_raw_files = [];
public function __construct(?BachelorApplication $application)
{
parent::__construct();
$this->application = $application;
}
public function setQuestionary(AbiturientQuestionary $questionary): FullPackageFilesSyncer
{
$this->questionary = $questionary;
return $this;
}
public function isFilesSyncing(): bool
{
return $this->files_sent;
}
public static function BuildFilesInfoToList(array $files_info_list)
{
$data = [];
foreach ($files_info_list as [$file_instance, $documentType, $filename]) {
if ($file_instance->linkedFile && $file_instance->linkedFile->fileExists()) {
$data[] = FullPackageFilesSyncer::fileInfoInto1CFormat($file_instance, $filename);
}
}
return $data;
}
public function GetFilesNeedsToSend(): array
{
$files_info_list = $this->getApplicationFilesInfo();
$files_need_to_send = FullPackageFilesSyncer::BuildFilesInfoToList($files_info_list);
if ($this->getUser()->userRef) {
$files_need_to_send = $this->postFilesList($files_need_to_send);
}
return $this->filterFileInfosBy1CRequest($files_info_list, $files_need_to_send);
}
public function buildFileInfoTo1C(FileToSendInterface $fileInstance, DocumentType $documentType, ?string $filename): array
{
$built_parts = $this->findProcessedFileParts($fileInstance);
return AttachmentManager::buildFileTo1C($fileInstance->linkedFile, $documentType, $filename, $built_parts);
}
public function SendFiles()
{
$files_info = $this->GetFilesNeedsToSend();
$result = [];
foreach ($files_info as [$fileWithLinkedFile, $custom_file_name]) {
$file = $fileWithLinkedFile->linkedFile;
if (!$file) {
throw new FileNotFoundException();
}
$sending_file = new SendingFile($file);
if ($sending_file->saveFileTo1C()) {
$built_parts = $sending_file->getPartsArraysTo1C();
if (!empty($built_parts)) {
$result[] = [$fileWithLinkedFile, $custom_file_name, $built_parts];
}
}
}
$this->sent_files_with_info = $result;
$this->files_sent = true;
}
public function FetchMissingFiles()
{
$received_files = [];
try {
$files_in_1c = $this->getFilesList();
$files_info_list = $this->getApplicationFilesInfo();
foreach ($files_in_1c as $file_from_1c) {
if (!FullPackageFilesSyncer::FindInfoBy1CFile($files_info_list, $file_from_1c)) {
$receiving_file = new ReceivingFile($file_from_1c);
$receiving_file->fetchFile();
$received_files[] = $receiving_file;
}
}
} catch (Throwable $e) {
foreach ($received_files as $received_file) {
$received_file->removeTempFiles();
}
throw $e;
}
$this->received_files = $received_files;
}
public static function FindInfoBy1CFile(array $local_files_info_list, \stdClass $file_from_1c)
{
foreach ($local_files_info_list as $local_file_info) {
$fileInstance = $local_file_info[0];
$documentType = $local_file_info[1];
if (!$fileInstance->linkedFile) {
continue;
}
if ($file_from_1c->FileUID && $fileInstance->linkedFile->uid && $fileInstance->linkedFile->uid != $file_from_1c->FileUID) {
continue;
}
if ($fileInstance->linkedFile->content_hash === $file_from_1c->FileHash) {
if (!isset($file_from_1c->FileTypeRef) || $documentType->ref_key == ((object)$file_from_1c->FileTypeRef)->ReferenceUID) {
if ($fileInstance->linkedFile->fileExists()) {
return $local_file_info;
}
}
}
}
return null;
}
public function FindReceivedFile(
string $file_name,
string $file_extension,
string $file_hash,
string $file_uid
): ?ReceivingFile {
$file_full_name = "{$file_name}.{$file_extension}";
foreach ($this->received_files as $received_file) {
if (
$received_file->uploadName == $file_full_name
&& $received_file->hash === $file_hash
&& (!$file_uid || !$received_file->fileUID || $file_uid == $received_file->fileUID)
) {
return $received_file;
}
}
return null;
}
public function appendReceivedFile(ReceivingFile $received_file)
{
$this->received_files[] = $received_file;
}
public function ClearReceivedFiles()
{
foreach ($this->received_files as $file) {
$file->removeTempFiles();
}
$this->received_files = [];
foreach ($this->_additional_temp_files as $temp_file) {
if (file_exists($temp_file) && !is_dir($temp_file)) {
try {
FileHelper::unlink($temp_file);
} catch (Throwable $e) {
Yii::error("Не удалось очистить временный файл {$temp_file} по причине: {$e->getMessage()}");
}
}
}
$this->_additional_temp_files = [];
}
private $_additional_temp_files = [];
public function appendAdditionalTempFiles(array $temp_files)
{
$this->_additional_temp_files = [...$this->_additional_temp_files, ...$temp_files];
}
protected function findProcessedFileParts(FileToSendInterface $fileToSend): ?array
{
$buildInfo = null;
if ($fileToSend->linkedFile) {
foreach ($this->sent_files_with_info as [$fileWithLinkedFile, $custom_file_name, $built_parts]) {
if ($fileWithLinkedFile->id == $fileToSend->id && $fileWithLinkedFile::tableName() == $fileToSend::tableName()) {
$buildInfo = $built_parts;
break;
}
}
}
return $buildInfo;
}
protected static function fileInfoInto1CFormat(FileToSendInterface $fileInstance, ?string $filename): array
{
return [
'FileName' => $filename ?? pathinfo($fileInstance->filename)['filename'],
'FileExt' => $fileInstance->extension,
'FileUID' => $fileInstance->linkedFile->uid,
'FileHash' => $fileInstance->linkedFile->content_hash,
'FilePartsCount' => $fileInstance->linkedFile->partsCount,
];
}
protected function filterFileInfosBy1CRequest(array $files_info_list, array $files_info_from_1c): array
{
$result = [];
foreach ($files_info_list as [$file_instance, $_, $filename]) {
if (array_filter($files_info_from_1c, function ($file) use ($file_instance, $filename) {
$assoc_file = ToAssocCaster::getAssoc($file);
$linkedFile = $file_instance->linkedFile;
if (!$linkedFile) {
return false;
}
if ($assoc_file['FileUID'] && $linkedFile->uid && $assoc_file['FileUID'] != $linkedFile->uid) {
return false;
}
return $assoc_file['FileHash'] == $linkedFile->content_hash
&& ($filename ?? pathinfo($linkedFile->upload_name)['filename']) == $assoc_file['FileName']
&& $file_instance->extension == $assoc_file['FileExt'];
})) {
$result[] = [$file_instance, $filename];
}
}
return $result;
}
public function getApplicationFilesInfo(): array
{
return $this->application->getAllAttachmentsInfo();
}
protected function postFilesList(array $files): array
{
$result = Yii::$app->soapClientWebApplication->load('PostFilesList', [
'Entrant' => $this->application->buildEntrantArray(),
'Files' => $files
]);
if (isset($result->return) && isset($result->return->FileInfo)) {
if (!is_array($result->return->FileInfo)) {
$result->return->FileInfo = array_values(array_filter([$result->return->FileInfo]));
}
return $result->return->FileInfo;
}
return [];
}
protected function getFilesList(): array
{
$result = Yii::$app->soapClientWebApplication->load('GetFilesList', [
'Entrant' => $this->application->buildEntrantArray(),
]);
if (isset($result->return) && isset($result->return->FileInfo)) {
if (!is_array($result->return->FileInfo)) {
$result->return->FileInfo = array_values(array_filter([$result->return->FileInfo]));
}
return $result->return->FileInfo;
}
return [];
}
public function getProcessedRawFiles(): array
{
return $this->processed_raw_files;
}
public function appendProcessedRawFile(array $file)
{
$this->processed_raw_files[] = $file;
}
protected function getUser(): User
{
return $this->application->user ?? $this->questionary->user;
}
}