Newer
Older
<?php
/**
* Copyright Maarch since 2008 under licence GPLv3.
* See LICENCE.txt file at the root folder for more details.
* This file is part of Maarch software.
*
*/
/**
* @brief Export Controller
* @author dev@maarch.org
*/
namespace Resource\controllers;
use Attachment\models\AttachmentModel;
use Basket\models\BasketModel;
use Contact\controllers\ContactController;
use Folder\controllers\FolderController;
use Folder\models\FolderModel;
use Resource\models\ExportTemplateModel;
use Resource\models\ResModel;
use Resource\models\ResourceListModel;
use Respect\Validation\Validator;
use SrcCore\controllers\PreparedClauseController;
public function getExportTemplates(Request $request, Response $response)
{
$currentUser = UserModel::getByLogin(['login' => $GLOBALS['userId'], 'select' => ['id']]);
$rawTemplates = ExportTemplateModel::getByUserId(['userId' => $currentUser['id']]);
$templates = ['pdf' => ['data' => []], 'csv' => ['data' => []]];
foreach ($rawTemplates as $rawTemplate) {
$templates['pdf'] = ['data' => (array)json_decode($rawTemplate['data'])];
$templates['csv'] = ['delimiter' => $rawTemplate['delimiter'], 'data' => (array)json_decode($rawTemplate['data'])];
}
return $response->withJson(['templates' => $templates]);
public function updateExport(Request $request, Response $response, array $aArgs)
$currentUser = UserModel::getByLogin(['login' => $GLOBALS['userId'], 'select' => ['id']]);
$errors = ResourceListController::listControl(['groupId' => $aArgs['groupId'], 'userId' => $aArgs['userId'], 'basketId' => $aArgs['basketId'], 'currentUserId' => $currentUser['id']]);
if (!empty($errors['errors'])) {
return $response->withStatus($errors['code'])->withJson(['errors' => $errors['errors']]);
}
if (!Validator::stringType()->notEmpty()->validate($body['format']) || !in_array($body['format'], ['pdf', 'csv'])) {
return $response->withStatus(400)->withJson(['errors' => 'Data format is empty or not a string between [\'pdf\', \'csv\']']);
} elseif ($body['format'] == 'csv' && (!Validator::stringType()->notEmpty()->validate($body['delimiter']) || !in_array($body['delimiter'], [',', ';', 'TAB']))) {
return $response->withStatus(400)->withJson(['errors' => 'Delimiter is empty or not a string between [\',\', \';\', \'TAB\']']);
} elseif (!Validator::arrayType()->notEmpty()->validate($body['data'])) {
return $response->withStatus(400)->withJson(['errors' => 'Data data is empty or not an array']);
} elseif (!Validator::arrayType()->notEmpty()->validate($body['resources'])) {
return $response->withStatus(403)->withJson(['errors' => 'Data resources is empty or not an array']);
foreach ($body['data'] as $value) {
if (!isset($value['value']) || !Validator::stringType()->notEmpty()->validate($value['label']) || !Validator::boolType()->validate($value['isFunction'])) {
return $response->withStatus(400)->withJson(['errors' => 'One data is not set well']);
$basket = BasketModel::getById(['id' => $aArgs['basketId'], 'select' => ['basket_clause', 'basket_res_order', 'basket_name']]);
$user = UserModel::getById(['id' => $aArgs['userId'], 'select' => ['user_id']]);
$whereClause = PreparedClauseController::getPreparedClause(['clause' => $basket['basket_clause'], 'login' => $user['user_id']]);
$rawResourcesInBasket = ResModel::getOnView([
'select' => ['res_id'],
'where' => [$whereClause, 'res_view_letterbox.res_id in (?)'],
'data' => [$body['resources']]
]);
$allResourcesInBasket = [];
foreach ($rawResourcesInBasket as $resource) {
$allResourcesInBasket[] = $resource['res_id'];
}
$order = 'CASE res_view_letterbox.res_id ';
foreach ($body['resources'] as $key => $resId) {
if (!in_array($resId, $allResourcesInBasket)) {
return $response->withStatus(403)->withJson(['errors' => 'Resources out of perimeter']);
}
$order .= "WHEN {$resId} THEN {$key} ";
}
$order .= 'END';
$template = ExportTemplateModel::get(['select' => [1], 'where' => ['user_id = ?', 'format = ?'], 'data' => [$currentUser['id'], $body['format']]]);
ExportTemplateModel::create([
'userId' => $currentUser['id'],
'delimiter' => empty($body['delimiter']) ? null : $body['delimiter'],
'delimiter' => empty($body['delimiter']) ? null : $body['delimiter'],
'where' => ['user_id = ?', 'format = ?'],
'data' => [$currentUser['id'], $body['format']]
$select = ['res_view_letterbox.res_id'];
foreach ($body['data'] as $value) {
$csvHead[] = $value['label'];
if (empty($value['value'])) {
continue;
}
if ($value['isFunction']) {
$select[] = 'status.label_status AS "status.label_status"';
$tableFunction[] = 'status';
$leftJoinFunction[] = 'res_view_letterbox.status = status.id';
$select[] = 'priorities.label AS "priorities.label"';
$tableFunction[] = 'priorities';
$leftJoinFunction[] = 'res_view_letterbox.priority = priorities.id';
$select[] = 'enone.short_label AS "enone.short_label"';
$tableFunction[] = 'entities enone';
$leftJoinFunction[] = 'res_view_letterbox.initiator = enone.entity_id';
} elseif ($value['value'] == 'getDestinationEntity') {
$select[] = 'entwo.short_label AS "entwo.short_label"';
$tableFunction[] = 'entities entwo';
$leftJoinFunction[] = 'res_view_letterbox.destination = entwo.entity_id';
} elseif ($value['value'] == 'getDestinationEntityType') {
$select[] = 'enthree.entity_type AS "enthree.entity_type"';
$tableFunction[] = 'entities enthree';
$leftJoinFunction[] = 'res_view_letterbox.destination = enthree.entity_id';
} elseif ($value['value'] == 'getTypist') {
$select[] = 'res_view_letterbox.typist';
} elseif ($value['value'] == 'getAssignee') {
$select[] = 'res_view_letterbox.dest_user';
} elseif ($value['value'] == 'getDepartment') {
$select[] = 'res_view_letterbox.department_number_id';
} else {
$select[] = "res_view_letterbox.{$value['value']}";
$aChunkedResources = array_chunk($body['resources'], 10000);
$resources = [];
foreach ($aChunkedResources as $chunkedResource) {
$resourcesTmp = ResourceListModel::getOnView([
'select' => $select,
'table' => $tableFunction,
'leftJoin' => $leftJoinFunction,
'where' => ['res_view_letterbox.res_id in (?)'],
'data' => [$chunkedResource],
'orderBy' => [$order]
]);
$resources = array_merge($resources, $resourcesTmp);
}
$file = ExportController::getCsv(['delimiter' => $body['delimiter'], 'data' => $body['data'], 'resources' => $resources, 'chunkedResIds' => $aChunkedResources]);
$response->write(stream_get_contents($file));
$response = $response->withAddedHeader('Content-Disposition', 'attachment; filename=export_maarch.csv');
$contentType = 'application/vnd.ms-excel';
$pdf = ExportController::getPdf(['data' => $body['data'], 'resources' => $resources, 'chunkedResIds' => $aChunkedResources]);
$fileContent = $pdf->Output('', 'S');
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$contentType = $finfo->buffer($fileContent);
$response->write($fileContent);
$response = $response->withAddedHeader('Content-Disposition', "inline; filename=maarch.pdf");
return $response->withHeader('Content-Type', $contentType);
ValidatorModel::notEmpty($aArgs, ['delimiter', 'data', 'resources', 'chunkedResIds']);
ValidatorModel::stringType($aArgs, ['delimiter']);
ValidatorModel::arrayType($aArgs, ['data', 'resources', 'chunkedResIds']);
$delimiter = ($aArgs['delimiter'] == 'TAB' ? "\t" : $aArgs['delimiter']);
$csvHead = [];
foreach ($aArgs['data'] as $value) {
$decoded = utf8_decode($value['label']);
$csvHead[] = $decoded;
}
fputcsv($file, $csvHead, $delimiter);
foreach ($aArgs['resources'] as $resource) {
$csvContent = [];
foreach ($aArgs['data'] as $value) {
if (empty($value['value'])) {
$csvContent[] = '';
continue;
}
if ($value['isFunction']) {
if ($value['value'] == 'getStatus') {
$csvContent[] = $resource['status.label_status'];
} elseif ($value['value'] == 'getPriority') {
$csvContent[] = $resource['priorities.label'];
} elseif ($value['value'] == 'getCopies') {
$copies = ExportController::getCopies(['chunkedResIds' => $aArgs['chunkedResIds']]);
$csvContent[] = empty($copies[$resource['res_id']]) ? '' : $copies[$resource['res_id']];
} elseif ($value['value'] == 'getDetailLink') {
$csvContent[] = str_replace('rest/', "apps/maarch_entreprise/index.php?page=details&dir=indexing_searching&id={$resource['res_id']}", \Url::coreurl());
} elseif ($value['value'] == 'getParentFolder') {
$csvContent[] = ExportController::getParentFolderLabel(['res_id' => $resource['res_id']]);
} elseif ($value['value'] == 'getFolder') {
$csvContent[] = ExportController::getFolderLabel(['res_id' => $resource['res_id']]);
} elseif ($value['value'] == 'getCategory') {
$csvContent[] = ResModel::getCategoryLabel(['categoryId' => $resource['category_id']]);
} elseif ($value['value'] == 'getInitiatorEntity') {
$csvContent[] = $resource['enone.short_label'];
} elseif ($value['value'] == 'getDestinationEntity') {
$csvContent[] = $resource['entwo.short_label'];
} elseif ($value['value'] == 'getDestinationEntityType') {
$csvContent[] = $resource['enthree.entity_type'];
$senders = ContactController::getFormattedContacts(['resId' => $resource['res_id'], 'mode' => 'sender']);
$csvContent[] = implode("\n", $senders);
} elseif ($value['value'] == 'getRecipients') {
$recipients = ContactController::getFormattedContacts(['resId' => $resource['res_id'], 'mode' => 'recipient']);
$csvContent[] = implode("\n", $recipients);
$csvContent[] = UserModel::getLabelledUserById(['id' => $resource['typist']]);
} elseif ($value['value'] == 'getAssignee') {
$csvContent[] = UserModel::getLabelledUserById(['login' => $resource['dest_user']]);
} elseif ($value['value'] == 'getTags') {
$tags = ExportController::getTags(['chunkedResIds' => $aArgs['chunkedResIds']]);
$csvContent[] = empty($tags[$resource['res_id']]) ? '' : $tags[$resource['res_id']];
$signatories = ExportController::getSignatories(['chunkedResIds' => $aArgs['chunkedResIds']]);
$csvContent[] = empty($signatories[$resource['res_id']]) ? '' : $signatories[$resource['res_id']];
$signatureDates = ExportController::getSignatureDates(['chunkedResIds' => $aArgs['chunkedResIds']]);
$csvContent[] = empty($signatureDates[$resource['res_id']]) ? '' : $signatureDates[$resource['res_id']];
} elseif ($value['value'] == 'getDepartment') {
if (!empty($resource['department_number_id'])) {
$csvContent[] = $resource['department_number_id'] . ' - ' . DepartmentController::getById(['id' => $resource['department_number_id']]);
} else {
$csvContent[] = '';
}
} elseif (strpos($value['value'], 'custom_', 0) !== false) {
$csvContent[] = ExportController::getCustomFieldValue(['custom' => $value['value'], 'resId' => $resource['res_id']]);
$allDates = ['doc_date', 'departure_date', 'admission_date', 'process_limit_date', 'opinion_limit_date', 'closing_date'];
if (in_array($value['value'], $allDates)) {
$csvContent[] = TextFormatModel::formatDate($resource[$value['value']]);
} else {
$csvContent[] = $resource[$value['value']];
}
}
}
foreach($csvContent as $key => $value) {
$csvContent[$key] = utf8_decode($value);
}
fputcsv($file, $csvContent, $delimiter);
}
rewind($file);
return $file;
}
private static function getPdf(array $aArgs)
{
ValidatorModel::notEmpty($aArgs, ['data', 'resources', 'chunkedResIds']);
ValidatorModel::arrayType($aArgs, ['data', 'resources', 'chunkedResIds']);
$columnsNumber = count($aArgs['data']);
$orientation = 'P';
if ($columnsNumber > 5) {
$orientation = 'L';
}
$pdf = new Fpdi($orientation, 'pt');
$pdf->setPrintHeader(false);
$pdf->AddPage();
$widthNoMargins = $dimensions['w'] - $dimensions['rm'] - $dimensions['lm'];
$bottomHeight = $dimensions['h'] - $dimensions['bm'];
$pdf->SetFont('', 'B', 12);
$labelHeight = ExportController::getMaximumHeight($pdf, ['data' => $labels, 'width' => $widthNoMargins / $columnsNumber]);
$pdf->MultiCell($widthNoMargins / $columnsNumber, $labelHeight, $value['label'], 1, 'L', true, 0);
}
$pdf->SetY($pdf->GetY() + $labelHeight);
$pdf->SetFont('', '', 10);
foreach ($aArgs['resources'] as $resource) {
continue;
}
if ($value['isFunction']) {
if ($value['value'] == 'getStatus') {
$copies = ExportController::getCopies(['chunkedResIds' => $aArgs['chunkedResIds']]);
$content[] = empty($copies[$resource['res_id']]) ? '' : $copies[$resource['res_id']];
} elseif ($value['value'] == 'getDetailLink') {
$content[] = str_replace('rest/', "apps/maarch_entreprise/index.php?page=details&dir=indexing_searching&id={$resource['res_id']}", \Url::coreurl());
$content[] = ExportController::getParentFolderLabel(['res_id' => $resource['res_id']]);
} elseif ($value['value'] == 'getFolder') {
$content[] = ExportController::getFolderLabel(['res_id' => $resource['res_id']]);
$content[] = ResModel::getCategoryLabel(['categoryId' => $resource['category_id']]);
} elseif ($value['value'] == 'getInitiatorEntity') {
} elseif ($value['value'] == 'getDestinationEntity') {
} elseif ($value['value'] == 'getDestinationEntityType') {
$content[] = $resource['enthree.entity_type'];
} elseif ($value['value'] == 'getSenders') {
$senders = ContactController::getFormattedContacts(['resId' => $resource['res_id'], 'mode' => 'sender']);
$content[] = implode("\n", $senders);
$recipients = ContactController::getFormattedContacts(['resId' => $resource['res_id'], 'mode' => 'recipient']);
$content[] = implode("\n", $recipients);
$content[] = UserModel::getLabelledUserById(['id' => $resource['typist']]);
$content[] = UserModel::getLabelledUserById(['login' => $resource['dest_user']]);
$tags = ExportController::getTags(['chunkedResIds' => $aArgs['chunkedResIds']]);
$content[] = empty($tags[$resource['res_id']]) ? '' : $tags[$resource['res_id']];
$signatories = ExportController::getSignatories(['chunkedResIds' => $aArgs['chunkedResIds']]);
$content[] = empty($signatories[$resource['res_id']]) ? '' : $signatories[$resource['res_id']];
} elseif ($value['value'] == 'getSignatureDates') {
$signatureDates = ExportController::getSignatureDates(['chunkedResIds' => $aArgs['chunkedResIds']]);
$csvContent[] = empty($signatureDates[$resource['res_id']]) ? '' : $signatureDates[$resource['res_id']];
} elseif ($value['value'] == 'getDepartment') {
if (!empty($resource['department_number_id'])) {
$content[] = $resource['department_number_id'] . ' - ' . DepartmentController::getById(['id' => $resource['department_number_id']]);
} else {
$content[] = '';
}
} elseif (strpos($value['value'], 'custom_', 0) !== false) {
$content[] = ExportController::getCustomFieldValue(['custom' => $value['value'], 'resId' => $resource['res_id']]);
$allDates = ['doc_date', 'departure_date', 'admission_date', 'process_limit_date', 'opinion_limit_date', 'closing_date'];
$content[] = TextFormatModel::formatDate($resource[$value['value']]);
if (!empty($contentHeight)) {
$pdf->SetY($pdf->GetY() + $contentHeight);
}
$contentHeight = ExportController::getMaximumHeight($pdf, ['data' => $content, 'width' => $widthNoMargins / $columnsNumber]);
if (($pdf->GetY() + $contentHeight) > $bottomHeight) {
$pdf->AddPage();
}
foreach ($content as $value) {
$pdf->MultiCell($widthNoMargins / $columnsNumber, $contentHeight, $value, 1, 'L', false, 0);
}
ValidatorModel::notEmpty($args, ['chunkedResIds']);
ValidatorModel::arrayType($args, ['chunkedResIds']);
static $aCopies = [];
if (!empty($aCopies)) {
return $aCopies;
}
foreach ($args['chunkedResIds'] as $resIds) {
$listInstances = ListInstanceModel::get([
'select' => ['item_id', 'item_type', 'res_id'],
'where' => ['res_id in (?)', 'difflist_type = ?', 'item_mode = ?'],
'data' => [$resIds, 'entity_id', 'cc'],
'order_by' => ['res_id']
]);
$resId = '';
if (!empty($listInstances)) {
foreach ($listInstances as $key => $listInstance) {
if ($key != 0 && $resId == $listInstance['res_id']) {
$copies .= "\n";
} elseif ($key != 0 && $resId != $listInstance['res_id']) {
$aCopies[$resId] = $copies;
$copies = '';
} else {
$copies = '';
}
if ($listInstance['item_type'] == 'user_id') {
$copies .= UserModel::getLabelledUserById(['login' => $listInstance['item_id']]);
} elseif ($listInstance['item_type'] == 'entity_id') {
$entity = EntityModel::getByEntityId(['entityId' => $listInstance['item_id'], 'select' => ['short_label']]);
$copies .= $entity['short_label'];
}
$resId = $listInstance['res_id'];
}
if (empty($aCopies)) {
$aCopies = ['empty'];
}
return $aCopies;
}
private static function getTags(array $args)
{
ValidatorModel::notEmpty($args, ['chunkedResIds']);
ValidatorModel::arrayType($args, ['chunkedResIds']);
static $tags = [];
if (!empty($tags)) {
return $tags;
}
foreach ($args['chunkedResIds'] as $resIds) {
$tagsRes = TagResModel::get([
'select' => ['tag_id', 'res_id'],
'where' => ['res_id in (?)'],
'data' => [$resIds],
'order_by' => ['res_id']
]);
foreach ($tagsRes as $key => $value) {
$tag = TagModel::getById(['id' => $value['tag_id'], 'select' => ['label']]);
if (!empty($tags[$value['res_id']])) {
$tags[$value['res_id']] .= "\n";
} else {
$tags[$value['res_id']] = '';
$tags[$value['res_id']] .= $tag['label'];
}
private static function getSignatories(array $args)
{
ValidatorModel::notEmpty($args, ['chunkedResIds']);
ValidatorModel::arrayType($args, ['chunkedResIds']);
static $aSignatories = [];
if (!empty($aSignatories)) {
return $aSignatories;
}
foreach ($args['chunkedResIds'] as $resIds) {
$listInstances = ListInstanceModel::get([
'select' => ['item_id', 'res_id'],
'where' => ['res_id in (?)', 'item_type = ?', 'signatory = ?'],
'data' => [$resIds, 'user_id', true],
'order_by' => ['res_id']
]);
foreach ($listInstances as $key => $listInstance) {
$user = UserModel::getByLogin(['login' => $listInstance['item_id'], 'select' => ['firstname', 'lastname']]);
if (!empty($aSignatories[$listInstance['res_id']])) {
$aSignatories[$listInstance['res_id']] .= "\n";
} else {
$aSignatories[$listInstance['res_id']] = '';
$aSignatories[$listInstance['res_id']] .= "{$user['firstname']} {$user['lastname']}";
private static function getSignatureDates(array $args)
{
ValidatorModel::notEmpty($args, ['chunkedResIds']);
ValidatorModel::arrayType($args, ['chunkedResIds']);
static $aSignatureDates = [];
if (!empty($aSignatureDates)) {
return $aSignatureDates;
}
foreach ($args['chunkedResIds'] as $resIds) {
$attachments = AttachmentModel::get([
'select' => ['creation_date', 'res_id'],
'where' => ['res_id in (?)', 'attachment_type = ?', 'status = ?'],
'data' => [$resIds, 'signed_response', 'TRA'],
'order_by' => ['res_id']
]);
foreach ($attachments as $key => $attachment) {
$date = new \DateTime($attachment['creation_date']);
if (!empty($aSignatureDates[$attachment['res_id']])) {
$aSignatureDates[$attachment['res_id']] .= "\n";
} else {
$aSignatureDates[$attachment['res_id']] = '';
$aSignatureDates[$attachment['res_id']] .= $date->format('d-m-Y H:i');
private static function getMaximumHeight(Fpdi $pdf, array $args)
{
ValidatorModel::notEmpty($args, ['data', 'width']);
ValidatorModel::arrayType($args, ['data']);
$maxHeight = 1;
if (!is_numeric($args['width'])) {
return $maxHeight;
}
foreach ($args['data'] as $value) {
$height = $pdf->getStringHeight($args['width'], $value);
if ($height > $maxHeight) {
$maxHeight = $height;
}
}
return $maxHeight + 2;
}
private static function getFolderLabel(array $args)
{
$folders = FolderModel::getWithResources([
'select' => ['folders.id, folders.label'],
'where' => ['resources_folders.res_id = ?'],
'data' => [$args['res_id']]
]);
if (empty($folders)) {
return '';
}
$labels = [];
foreach ($folders as $folder) {
$hasFolder = FolderController::hasFolders([
'userId' => $GLOBALS['id'],
'folders' => [$folder['id']]
]);
if ($hasFolder) {
$labels[] = $folder['label'];
}
}
return implode("\n", $labels);
}
private static function getParentFolderLabel(array $args)
{
$folders = FolderModel::getWithResources([
'select' => ['folders.parent_id'],
'where' => ['resources_folders.res_id = ?'],
'data' => [$args['res_id']]
]);
if (empty($folders)) {
$parentLabels = [];
foreach ($folders as $folder) {
$hasFolder = FolderController::hasFolders([
'userId' => $GLOBALS['id'],
'folders' => [$folder['parent_id']]
]);
if (!$hasFolder) {
continue;
}
$parentFolder = FolderModel::getById([
'id' => $folder['parent_id']
]);
$parentLabels[] = $parentFolder['label'];
return implode("\n", $parentLabels);
private static function getCustomFieldValue(array $args)
{
ValidatorModel::notEmpty($args, ['custom', 'resId']);
ValidatorModel::stringType($args, ['custom']);
ValidatorModel::intVal($args, ['resId']);
$customField = explode('_', $args['custom']);
// Custom fields must be in this format : 'custom_<id custom field>'
// So if the explode returns an array with more or less than 2 elements, the format is wrong
if (count($customField) != 2) {
return null;
}
$customFieldId = $customField[1];
$customField = ResModel::get(['select' => ["custom_fields->'{$customFieldId}' as csfield"], 'where' => ['res_id = ?'], 'data' => [$args['resId']]]);
if (empty($customField[0]['csfield'])) {
$customValues = json_decode($customField[0]['csfield'], true);
if (!isset($customValues)) {
return null;
}
if (is_array($customValues)) {
return implode("\n", $customValues);
}
return $customValues;
}