/
v.bolshakov
/
AIEcosystem-Testing
Обзор
Документация
Войти
/
v.bolshakov
/
AIEcosystem-Testing
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
dev
common/helpers/MemoQHelper.php
638 строк
20 KB
Developer
Initial commit
03 авг 2026, 17:43
03 авг 2026, 17:43
7433917
Код
Авторство
О чём код?
<?php namespace common\helpers; use common\kdf\KDocumentStatus; use common\kdf\KModelStatus; use common\kdf\KSystem; use common\memoQ\FileManagerService; use common\memoQ\meta\filemanager\AddNextFileChunk; use common\memoQ\meta\filemanager\BeginChunkedFileDownload; use common\memoQ\meta\filemanager\BeginChunkedFileDownloadResponse; use common\memoQ\meta\filemanager\BeginChunkedFileUpload; use common\memoQ\meta\filemanager\BeginChunkedFileUploadResponse; use common\memoQ\meta\filemanager\DeleteFile; use common\memoQ\meta\filemanager\EndChunkedFileDownload; use common\memoQ\meta\filemanager\EndChunkedFileUpload; use common\memoQ\meta\filemanager\GetNextFileChunk; use common\memoQ\meta\filemanager\GetNextFileChunkResponse; use common\memoQ\meta\security\ArrayOfUserInfo; use common\memoQ\meta\security\ListUsers; use common\memoQ\meta\security\ListUsersResponse; use common\memoQ\meta\security\UserInfo; use common\memoQ\meta\serverproject\ArrayOfServerProjectInfo; use common\memoQ\meta\serverproject\ArrayOfServerProjectTranslationDocInfo; use common\memoQ\meta\serverproject\ListProjects; use common\memoQ\meta\serverproject\ListProjectsResponse; use common\memoQ\meta\serverproject\ListProjectTranslationDocuments; use common\memoQ\meta\serverproject\ListProjectTranslationDocumentsResponse; use common\memoQ\meta\serverproject\ServerProjectInfo; use common\memoQ\meta\serverproject\ServerProjectListFilter; use common\memoQ\meta\serverproject\ServerProjectTranslationDocInfo; use common\memoQ\SecurityService; use common\memoQ\ServerProjectService; use common\models\link\LinkUserMemoQ; use common\models\memoq\Client; use common\models\memoq\Document; use common\models\memoq\link\LinkDocumentProject; use common\models\memoq\Project; use common\models\memoq\ProjectInfo; use common\models\memoq\ProjectSync; use common\models\memoq\ProjectTarget; use common\models\memoq\User; use common\validators\UidValidator; use Yii; use yii\bootstrap\Html; use yii\db\Connection; use yii\db\Expression; use yii\helpers\Console; use yii\helpers\VarDumper; use yii\web\ServerErrorHttpException; /** * Вспомогательный класс для работы MemoQ * * @author Dmitry E. Semenov <sde.tomsk@gmail.com> * @copyright Self (c) 2025 */ class MemoQHelper { const CHUNKSIZE = 500000; /** * Загрузка файлов в MemoQ * * @param FileManagerService $fmService * @param string $filePath * @return string|null */ public static function UploadFile(FileManagerService $fmService, string $filePath) { $fileIdAndSessionId = UidValidator::GUID_NULL; $handle = null; try { $parameters = new BeginChunkedFileUpload(basename($filePath), false); // Begin chunked upload /** @var BeginChunkedFileUploadResponse $result */ $result = $fmService->BeginChunkedFileUpload($parameters); $fileIdAndSessionId = $result->getBeginChunkedFileUploadResult(); // Open source file stream $handle = fopen($filePath, "r"); while ($contents = fread($handle, self::CHUNKSIZE)) { $parameters = new AddNextFileChunk($fileIdAndSessionId, $contents); $fmService->AddNextFileChunk($parameters); } return $fileIdAndSessionId; } finally { if ($handle) { fclose($handle); } // End chunked upload if ($fileIdAndSessionId != UidValidator::GUID_NULL) { $parameters = new EndChunkedFileUpload($fileIdAndSessionId); $fmService->EndChunkedFileUpload($parameters); } } } /** * Скачать файл из MemoQ * * @param FileManagerService $fmService * @param $fileGuid * @return array * @throws ServerErrorHttpException */ public static function DownloadFile(FileManagerService $fmService, $fileGuid) { $fp = null; $sessionId = UidValidator::GUID_NULL; try { $parameters = new BeginChunkedFileDownload($fileGuid, false); /** @var BeginChunkedFileDownloadResponse $result */ $result = $fmService->BeginChunkedFileDownload($parameters); $sessionId = $result->getBeginChunkedFileDownloadResult(); $fileName = $result->getFileName(); $fileSize = $result->getFileSize(); $fileBytesLeft = $fileSize; $content = null; // $tmp = tempnam(sys_get_temp_dir(), md5(microtime(true))); // // if (!$fp = fopen($tmp, 'a')) { // throw new ServerErrorHttpException(Yii::t('app', 'Cannot open file ({0})', [ // $tmp // ])); // } while ($fileBytesLeft > 0) { $parameters = new GetNextFileChunk($sessionId, self::CHUNKSIZE); /** @var GetNextFileChunkResponse $response */ $response = $fmService->GetNextFileChunk($parameters); $chunkBytes = $response->getGetNextFileChunkResult(); // if (false === fwrite($fp, $chunkBytes)) { // throw new ServerErrorHttpException(Yii::t('app', 'Cannot write to file ({0})', [ // $tmp // ])); // } $content .= $chunkBytes; $fileBytesLeft -= strlen($chunkBytes); } return [ 'filename' => $fileName, 'filesize' => $fileSize, 'content' => $content // 'filepath' => $tmp ]; } finally { // if ($fp) { // fclose($fp); // } if ($sessionId != UidValidator::GUID_NULL) { $parameters = new EndChunkedFileDownload($sessionId); $fmService->EndChunkedFileDownload($parameters); } } } /** * Удаление файла * * @param FileManagerService $fmService * @param $fileGuid * @return void */ public static function DeleteFile(FileManagerService $fmService, $fileGuid) { try { // We no longer need the file, delete it on the server. $parameters = new DeleteFile($fileGuid); $fmService->DeleteFile($parameters); } catch (\Exception $e) { Yii::debug(VarDumper::dumpAsString([ 'message' => $e->getMessage(), ])); } } /** * Преобразовать данные дата, прешедшая из Сервиса приема - преобразуем в формат даты используемой в коде * * @param $date * @return string|null */ public static function asDate($date, $timeZone = null) { if ($date instanceof \DateTime) { $date->setTimezone(new \DateTimeZone($timeZone ?: Yii::$app->timeZone)); return $date->format(DateHelper::$date_format); } else { return null; } } /** * Преобразовать данные дата и время, прешедшая из Сервиса приема - преобразуем в формат даты и времени используемой в коде * * @param $dateTime * @return string|null */ public static function asDateTime($dateTime, $timeZone = null) { if ($dateTime instanceof \DateTime) { $dateTime->setTimezone(new \DateTimeZone($timeZone ?: Yii::$app->timeZone)); return $dateTime->format(DateHelper::$timestamp_format); } else { return null; } } /** * Синхронизация пользователей MemoQ * @return bool * @throws ServerErrorHttpException * @throws \yii\base\InvalidConfigException * @throws \yii\db\Exception */ public static function syncUser() { $service = new SecurityService(); $parameters = new ListUsers(); /** @var ListUsersResponse $response */ $response = $service->ListUsers($parameters); /** @var ArrayOfUserInfo $users */ $users = $response->getListUsersResult(); /** @var UserInfo $user */ foreach ($users->getUserInfo() as $user) { Yii::debug(VarDumper::dumpAsString([ 'user' => $user ])); $guid = $user->getUserGuid(); $m_user = User::findOrNew([ 'guid' => $guid ]); $m_user->setAttributes([ 'email' => $user->getEmailAddress(), 'title' => $user->getFullName() ]); if (!$m_user->save()) { $error = Html::errorSummary($m_user); throw new ServerErrorHttpException($error); } } return true; } /** * Внутренняя синхронизация проекта * * @param ServerProjectInfo $item * @param ServerProjectService $service * @return mixed * @throws \Throwable */ protected static function syncInternalProject($item, $service = null) { if (!$service) { /** @var ServerProjectService $service */ $service = new ServerProjectService(); } /** @var Connection $db */ $db = Yii::$app->db; return $db->transaction(function () use ($item, $service) { $user_id = User::GUEST; $client_id = Client::DEFAULT_CLIENT; if ($u_guid = $item->getCreatorUser()) { $user_id = User::find() ->andWhere([ 'guid' => $u_guid ]) ->scalar() ?: User::GUEST; } if ($c_title = $item->getClient()) { $client = Client::findOrNew([ 'title' => $c_title ]); $client->save(); $client_id = $client->id ?: Client::DEFAULT_CLIENT; } $m_project = Project::findOrNew([ 'guid' => $item->getServerProjectGuid() ]); $source_language_id = LanguageHelper::getLanguageCodeId($item->getSourceLanguageCode(), KSystem::MEMOQ); $status_id = KDocumentStatus::toId($item->getDocumentStatus()); $m_project->setAttributes([ 'title' => $item->getProject(), 'name' => $item->getName(), 'source_language_id' => $source_language_id, 'dead_line' => self::asDateTime($item->getDeadline()), 'client_id' => $client_id, 'creator_user_id' => $user_id, 'status_id' => $status_id ]); if (!$m_project->save()) { Yii::debug(VarDumper::dumpAsString([ 'error' => $m_project->errors ])); return false; } $target_list = $item->getTargetLanguageCodes(); ProjectTarget::deleteAll(['project_id' => $m_project->id]); foreach ($target_list as $target) { $target_language_id = LanguageHelper::getLanguageCodeId($target, KSystem::MEMOQ); $pt = new ProjectTarget([ 'project_id' => $m_project->id, 'target_language_id' => $target_language_id ]); if (!$pt->save()) { Yii::debug(VarDumper::dumpAsString([ 'error' => $pt->errors ])); return false; } } try { $parameters = new ListProjectTranslationDocuments($m_project->guid); /** @var ListProjectTranslationDocumentsResponse $response */ $response = $service->ListProjectTranslationDocuments($parameters); /** @var ArrayOfServerProjectTranslationDocInfo $items */ $items = $response->getListProjectTranslationDocumentsResult(); $link = LinkDocumentProject::find() ->select('document_id') ->andWhere([ 'project_id' => $m_project->id, ]); Document::updateAll([ 'rec_status' => KModelStatus::DELETED ], [ 'id' => $link ]); $is_request = 0; if (in_array($status_id, [ KDocumentStatus::TRANSLATION_FINISHED, KDocumentStatus::PROOFREADING_FINISHED ])) { $is_request = 1; } if ($items->getServerProjectTranslationDocInfo()) { /** @var ServerProjectTranslationDocInfo $item */ foreach ($items as $item) { $document = Document::findOrNew([ 'guid' => $item->getDocumentGuid() ]); $is_request_doc = ($is_request or $document->isNewRecord); $document->setAttributes([ 'is_request' => $is_request_doc, 'document_name' => $item->getDocumentName(), 'total_segment' => $item->getTotalSegmentCount(), 'total_word' => $item->getTotalWordCount(), 'rec_status' => KModelStatus::PUBLISHED ]); if (!$document->save()) { return false; } $link = LinkDocumentProject::findOrNew([ 'project_id' => $m_project->id, 'document_id' => $document->id ]); if (!$link->save()) { return false; } } } $m_project->touch(); } catch (\SoapFault $e) { Yii::debug(VarDumper::dumpAsString([ 'message' => $e->getMessage() ])); $m_project->delete(); } // проставляем синхронизацию ProjectSync::updateAll([ 'last_update' => DateHelper::now(), 'is_request' => 0, ], [ 'guid' => $m_project->guid ]); return true; }); } /** * Синхронизация одного проекта * @return bool */ public static function syncProject($project, $client, $service = null) { if (!$service) { /** @var ServerProjectService $service */ $service = new ServerProjectService(); } $filter = new ServerProjectListFilter(); $filter->setProject($project); $filter->setClient($client); $parameters = new ListProjects($filter); /** @var ListProjectsResponse $result */ $result = $service->ListProjects($parameters); /** @var ArrayOfServerProjectInfo $items */ $items = $result->getListProjectsResult(); /** @var ServerProjectInfo $item */ foreach ($items as $item) { self::syncInternalProject($item, $service); } return true; } /** * Синхронизация проектов (заголовки) * @return bool */ public static function syncProjectInfo() { $begin_time = microtime(true); /** @var ServerProjectService $service */ $service = new ServerProjectService(); $filter = new ServerProjectListFilter(); $parameters = new ListProjects($filter); /** @var ListProjectsResponse $result */ $result = $service->ListProjects($parameters); /** @var ArrayOfServerProjectInfo $items */ $items = $result->getListProjectsResult(); $end_time = microtime(true); Console::stdout('step 1: (time: ' . sprintf('%.3f', $end_time - $begin_time) . "s)" . PHP_EOL);; $begin_time = $end_time; ProjectInfo::deleteAll(); $end_time = microtime(true); Console::stdout('step 2: (time: ' . sprintf('%.3f', $end_time - $begin_time) . "s)" . PHP_EOL);; $begin_time = $end_time; $matrix = []; $rows = []; $id = 1; $sync_project = ProjectSync::find() ->select('guid') ->andWhere([ 'is_request' => 1 ]) ->limit(50) ->column(); /** @var ServerProjectInfo $item */ foreach ($items as $item) { $rows[] = [ $id, $item->getServerProjectGuid(), $item->getProject() ?: null, $item->getName() ?: null, $item->getClient() ?: null, $item->getCreatorUser() ?: null, self::asDateTime($item->getDeadline()), KDocumentStatus::toId($item->getDocumentStatus()) ]; if (in_array($item->getServerProjectGuid(), $sync_project)) { self::syncInternalProject($item, $service); } $id++; if ($id % 1000 == 0) { $matrix[] = $rows; $rows = []; } } $matrix[] = $rows; $end_time = microtime(true); Console::stdout('step 3: (time: ' . sprintf('%.3f', $end_time - $begin_time) . "s)" . PHP_EOL); $begin_time = $end_time; foreach ($matrix as $index => $rows) { $affected_rows = Yii::$app->db->createCommand() ->batchInsert(ProjectInfo::tableName(), [ 'id', 'guid', 'title', 'name', 'client', 'creator_user', 'deadline', 'status_id' ], $rows) ->execute(); $end_time = microtime(true); Console::stdout('insert ' . $index . ': (time: ' . sprintf('%.3f', $end_time - $begin_time) . "s)" . PHP_EOL); $begin_time = $end_time; } $b = ProjectInfo::getAlias(); $a = ProjectSync::getAlias(); $sub = ProjectSync::find() ->select('*') ->alias($a) ->andWhere([$a . '.guid' => new Expression($b . '.guid')]); $query = ProjectInfo::find() ->select('guid') ->alias($b) ->andWhere(['not exists', $sub]); $affected_rows = Yii::$app->db->createCommand() ->insert(ProjectSync::tableName(), $query) ->execute(); Console::stdout('insert sync: ' . $affected_rows . PHP_EOL); return true; } /** * Синхронизация проектов (заголовки) * @return bool */ public static function syncProjectDirect($guid) { $begin_time = microtime(true); /** @var ServerProjectService $service */ $service = new ServerProjectService(); $filter = new ServerProjectListFilter(); $parameters = new ListProjects($filter); /** @var ListProjectsResponse $result */ $result = $service->ListProjects($parameters); /** @var ArrayOfServerProjectInfo $items */ $items = $result->getListProjectsResult(); $end_time = microtime(true); Console::stdout('step 1: (time: ' . sprintf('%.3f', $end_time - $begin_time) . "s)" . PHP_EOL);; /** @var ServerProjectInfo $item */ foreach ($items as $item) { if ($item->getServerProjectGuid() == $guid) { self::syncInternalProject($item, $service); break; } } return true; } /** * Получить пользования экосистемы * * @param $m_user_id * @return array|\yii\db\ActiveRecord|null * @throws \yii\base\InvalidConfigException */ public static function getUser($m_user_id) { $a = \common\models\User::getAlias(); return \common\models\User::find() ->alias($a) ->innerJoin(['l' => LinkUserMemoQ::tableName()], $a . '.id = l.user_id') ->andWhere([ 'm_user_id' => $m_user_id ]) ->one(); } }