Vtiger_PDF_Action::generate()   F
last analyzed

Complexity

Conditions 41
Paths 416

Size

Total Lines 124
Code Lines 93

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 1722

Importance

Changes 0
Metric Value
eloc 93
dl 0
loc 124
ccs 0
cts 85
cp 0
rs 0.8111
c 0
b 0
f 0
cc 41
nc 416
nop 1
crap 1722

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Export PDF action file.
5
 *
6
 * @package Action
7
 *
8
 * @copyright YetiForce S.A.
9
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
10
 * @author    Maciej Stencel <[email protected]>
11
 * @author    Mariusz Krzaczkowski <[email protected]>
12
 * @author    Adrian Koń <[email protected]>
13
 * @author    Rafal Pospiech <[email protected]>
14
 * @author    Radosław Skrzypczak <[email protected]>
15
 */
16
17
/**
18
 * Export PDF action class.
19
 */
20
class Vtiger_PDF_Action extends \App\Controller\Action
21
{
22
	use \App\Controller\ExposeMethod;
23
24
	/**
25
	 * Function to check permission.
26
	 *
27
	 * @param \App\Request $request
28
	 *
29
	 * @throws \App\Exceptions\NoPermitted
30
	 */
31
	public function checkPermission(App\Request $request)
32
	{
33
		$userPrivilegesModel = Users_Privileges_Model::getCurrentUserPrivilegesModel();
34
		if (!$userPrivilegesModel->hasModuleActionPermission($request->getModule(), 'ExportPdf')) {
35
			throw new \App\Exceptions\NoPermitted('LBL_PERMISSION_DENIED', 406);
36
		}
37
	}
38
39
	/**
40
	 * Constructor.
41
	 */
42
	public function __construct()
43
	{
44
		parent::__construct();
45
		$this->exposeMethod('hasValidTemplate');
46
		$this->exposeMethod('validateRecords');
47
		$this->exposeMethod('generate');
48
		$this->exposeMethod('saveInventoryColumnScheme');
49
	}
50
51
	/**
52
	 * Function to validate date.
53
	 *
54
	 * @param App\Request $request
55
	 *
56
	 * @return void
57
	 */
58
	public function validateRecords(App\Request $request): void
59
	{
60
		$moduleName = $request->getModule();
61
		$recordId = $request->isEmpty('record', true) ? null : $request->getInteger('record');
0 ignored issues
show
Unused Code introduced by
The assignment to $recordId is dead and can be removed.
Loading history...
62
		$result = false;
63
		foreach ($request->getArray('templates', \App\Purifier::INTEGER) as $templateId) {
64
			$templateRecord = Vtiger_PDF_Model::getInstanceById($templateId);
65
			foreach ($this->getRecords($request) as $recordId) {
66
				if (\App\Privilege::isPermitted($moduleName, 'DetailView', $recordId) && $templateRecord->checkFiltersForRecord((int) $recordId)) {
67
					$result = true;
68
					break 2;
69
				}
70
			}
71
		}
72
		$response = new Vtiger_Response();
73
		$response->setResult([
74
			'valid' => $result,
75
			'message' => \App\Language::translateArgs('LBL_NO_DATA_AVAILABLE', $moduleName),
76
		]);
77
		$response->emit();
78
	}
79
80
	/**
81
	 * Generate pdf.
82
	 *
83
	 * @param App\Request $request
84
	 *
85
	 * @throws \App\Exceptions\NoPermitted
86
	 *
87
	 * @return void
88
	 */
89
	public function generate(App\Request $request): void
90
	{
91
		$pdfModuleName = $request->getModule();
92
		$view = $request->getByType('fromview', \App\Purifier::STANDARD);
93
		$recordId = $request->isEmpty('record', true) ? null : $request->getInteger('record');
94
		if ($isRelatedView = ('RelatedList' === $view)) {
95
			$pdfModuleName = $request->getByType('relatedModule', \App\Purifier::ALNUM);
96
		}
97
		$recordIds = $this->getRecords($request);
98
99
		$templateIds = $request->getArray('pdf_template', 'Integer');
100
		$singlePdf = 1 === $request->getInteger('single_pdf');
101
		$emailPdf = 1 === $request->getInteger('email_pdf');
102
		$pdfFlag = $request->getByType('flag', \App\Purifier::STANDARD) ?: null;
103
		$key = 'inventoryColumns';
104
		$userVariables = $request->getArray('userVariables', \App\Purifier::TEXT);
105
106
		$handlerClass = Vtiger_Loader::getComponentClassName('Model', 'PDF', $pdfModuleName);
107
		$pdfModel = new $handlerClass();
108
		$templates = ($recordId && !$isRelatedView) ? $pdfModel->getActiveTemplatesForRecord($recordId, $view, $pdfModuleName) : $pdfModel->getActiveTemplatesForModule($pdfModuleName, $view);
0 ignored issues
show
Bug Best Practice introduced by
The expression $recordId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
109
110
		if (($emailPdf && !\App\Mail::checkInternalMailClient())
111
			|| ($request->has($key) && !\App\Privilege::isPermitted($pdfModuleName, 'RecordPdfInventory'))
112
			|| array_diff($templateIds, array_keys($templates))
113
			) {
114
			throw new \App\Exceptions\NoPermitted('LBL_EXPORT_ERROR');
115
		}
116
		$eventHandler = new App\EventHandler();
117
		$eventHandler->setModuleName($pdfModuleName);
118
		$eventHandler->setParams([
119
			'records' => $recordIds,
120
			'templates' => $templateIds,
121
			'viewInstance' => $this,
122
			'pdfModel' => $pdfModel,
123
		]);
124
		$eventHandler->trigger('PdfGenerateInit');
125
		$recordIds = $eventHandler->getParam('records');
126
127
		$increment = $skip = $pdfFiles = [];
128
		$countTemplates = \count($templateIds);
129
		$countRecords = \count($recordIds);
130
		foreach ($recordIds as $recordId) {
131
			foreach ($templateIds as $templateId) {
132
				if (isset($skip[$templateId])) {
133
					continue;
134
				}
135
				$pdf = \App\Pdf\Pdf::getInstanceByTemplateId($templateId);
136
				$template = $pdf->getTemplate();
137
				$filePath = '';
138
				switch ($template->get('type')) {
139
					case Vtiger_PDF_Model::TEMPLATE_TYPE_SUMMARY:
140
						$skip[$templateId] = true;
141
						$validRecords = [];
142
						foreach ($recordIds as $record) {
143
							if ($template->checkFiltersForRecord($record)) {
144
								$validRecords[] = $record;
145
							}
146
						}
147
						$template->setVariable('recordsId', $validRecords);
148
						foreach (['viewname', 'search_value', 'search_key', 'search_params', 'operator', 'cvId', 'relatedModule', 'relationId'] as $keyName) {
149
							if ('search_params' === $keyName) {
150
								$template->setVariable($keyName, App\Condition::validSearchParams($pdfModuleName, $request->getArray($keyName)));
151
							} else {
152
								$template->setVariable($keyName, $request->isEmpty($keyName) ? '' : $request->getByType($keyName, \App\Purifier::ALNUM));
153
							}
154
						}
155
						break;
156
					case Vtiger_PDF_Model::TEMPLATE_TYPE_DYNAMIC:
157
						if (!$template->checkFiltersForRecord($recordId)) {
158
							break 2;
159
						}
160
						$template->setVariable('recordId', $recordId);
161
						$template->setVariable($key, $request->getArray($key, 'Alnum', null));
162
						break;
163
					default:
164
						if (!$template->checkFiltersForRecord($recordId)) {
165
							break 2;
166
						}
167
						$template->setVariable('recordId', $recordId);
168
						break;
169
				}
170
171
				if (isset($userVariables[$template->getId()])) {
172
					foreach ($userVariables[$template->getId()] as $key => $value) {
173
						$template->getParser()->setParam($key, $value);
174
					}
175
				}
176
177
				$pdf->loadTemplateData();
178
				$eventHandler->addParams('pdf', $pdf);
179
				$eventHandler->trigger('PdfGenerate');
180
181
				$attach = $template->attachFiles ?? [];
0 ignored issues
show
Bug introduced by
The property attachFiles does not seem to exist on Vtiger_PDF_Model.
Loading history...
182
				if ($attach || $emailPdf || ($countTemplates > 1 || (1 === $countTemplates && !isset($skip[$templateId]) && $countRecords > 1))) {
183
					$fileName = ($pdf->getFileName() ?: time());
184
					$increment[$fileName] = $increment[$fileName] ?? 0;
185
					$fileName .= ($increment[$fileName]++ > 0 ? '_' . $increment[$fileName] : '') . '.pdf';
186
187
					$filePath = $template->getPath();
188
					$mode = 'F';
189
					$pdfFiles[] = ['name' => $fileName, 'path' => $filePath, 'recordId' => $recordId, 'moduleName' => $pdfModuleName];
190
					foreach ($attach as $info) {
191
						if (!isset($pdfFiles[$info['path']])) {
192
							$tmpFileName = 'cache' . \DIRECTORY_SEPARATOR . 'pdf' . \DIRECTORY_SEPARATOR;
193
							$tmpFileName = $tmpFileName . basename(tempnam($tmpFileName, 'Attach' . time()));
194
							if (\copy($info['path'], $tmpFileName)) {
195
								$pdfFiles[$info['path']] = ['name' => $info['name'], 'path' => $tmpFileName, 'recordId' => $recordId, 'moduleName' => $pdfModuleName];
196
							}
197
						}
198
					}
199
				}
200
				$pdf->output($filePath, $mode ?? $pdfFlag ?? 'D');
201
			}
202
		}
203
		if ($singlePdf) {
204
			\App\Pdf\Pdf::merge(array_column($pdfFiles, 'path'), \App\Fields\File::sanitizeUploadFileName(\App\Language::translate('LBL_PDF_MANY_IN_ONE')) . '.pdf', $pdfFlag ?: 'D');
205
			foreach ($pdfFiles as $pdfFile) {
206
				unlink($pdfFile['path']);
207
			}
208
		} elseif ($emailPdf) {
209
			$pdfFiles = array_values($pdfFiles);
210
			Vtiger_PDF_Model::attachToEmail(\App\Json::encode($pdfFiles));
211
		} elseif ($pdfFiles) {
212
			Vtiger_PDF_Model::zipAndDownload($pdfFiles);
213
		}
214
	}
215
216
	/**
217
	 * Checks if given record has valid pdf template.
218
	 *
219
	 * @param \App\Request $request
220
	 *
221
	 * @return void
222
	 */
223
	public function hasValidTemplate(App\Request $request): void
224
	{
225
		$recordId = $request->isEmpty('record', true) ? null : $request->getInteger('record');
226
		$moduleName = $request->getModule();
227
		if (!\App\Privilege::isPermitted($moduleName, 'DetailView', $recordId)) {
228
			throw new \App\Exceptions\NoPermittedToRecord('ERR_NO_PERMISSIONS_FOR_THE_RECORD', 406);
229
		}
230
		$response = new Vtiger_Response();
231
		$response->setResult(['valid' => (new Vtiger_PDF_Model())->checkActiveTemplates($recordId, $moduleName, $request->getByType('view'))]);
232
		$response->emit();
233
	}
234
235
	/**
236
	 * Save inventory column scheme.
237
	 *
238
	 * @param App\Request $request
239
	 *
240
	 * @return void
241
	 */
242
	public function saveInventoryColumnScheme(App\Request $request): void
243
	{
244
		$moduleName = $request->has('relatedModule') ? $request->getByType('relatedModule', \App\Purifier::ALNUM) : $request->getModule();
245
		if (!\App\Privilege::isPermitted($moduleName, 'RecordPdfInventory')) {
246
			throw new \App\Exceptions\NoPermitted('LBL_PERMISSION_DENIED');
247
		}
248
		$records = $this->getRecords($request);
249
		$columns = $request->getArray('inventoryColumns');
250
		$save = [];
251
		foreach ($records as $recordId) {
252
			$save[$recordId] = $columns;
253
		}
254
		\App\Pdf\InventoryColumns::saveInventoryColumnsForRecords($moduleName, $save);
255
		$response = new Vtiger_Response();
256
		$response->setResult([
257
			'message' => \App\Language::translate('LBL_SCHEME_SAVED', 'Settings:PDF'),
258
			'records' => $records,
259
		]);
260
		$response->emit();
261
	}
262
263
	/**
264
	 * Get record ids.
265
	 *
266
	 * @param \App\Request $request
267
	 *
268
	 * @return int[]
269
	 */
270
	private function getRecords(App\Request $request): array
271
	{
272
		if ($request->has('relatedModule')) {
273
			$records = \Vtiger_RelationAjax_Action::getRecordsListFromRequest($request);
274
		} elseif (!$request->isEmpty('record', true)) {
275
			$records = [$request->getInteger('record')];
276
		} else {
277
			$records = \Vtiger_Mass_Action::getRecordsListFromRequest($request);
278
		}
279
		return $records;
280
	}
281
282
	/** {@inheritdoc} */
283
	public function validateRequest(App\Request $request)
284
	{
285
		if ('generate' === $request->getMode()) {
286
			$request->validateReadAccess();
287
		} else {
288
			$request->validateWriteAccess();
289
		}
290
	}
291
}
292