Passed
Pull Request — developer (#17136)
by Arkadiusz
35:03 queued 17:53
created

Vtiger_CalendarExtSource_Model::delete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 7
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * Calendar extra source model file.
5
 *
6
 * @package Model
7
 *
8
 * @copyright YetiForce S.A.
9
 * @license   YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
10
 * @author    Mariusz Krzaczkowski <[email protected]>
11
 */
12
/**
13
 * Calendar extra source model class.
14
 */
15
class Vtiger_CalendarExtSource_Model extends App\Base
16
{
17
	/** @var string[] Extra source details */
18
	const EXTRA_SOURCE_TYPES = [
19
		1 => 'LBL_SOURCE_TYPE_1',
20
		2 => 'LBL_SOURCE_TYPE_2',
21
		3 => 'LBL_SOURCE_TYPE_3',
22
		4 => 'LBL_SOURCE_TYPE_4',
23
	];
24
	/** @var string Extra source table name */
25
	const EXTRA_SOURCE_TABLE = 's_#__calendar_sources';
26
27
	/** @var string Base module name */
28
	protected $baseModuleName;
29
	/** @var string Target module name */
30
	protected $targetModuleName;
31
	/** @var \Vtiger_Module_Model Target module model */
32
	protected $targetModuleModel;
33
	/** @var \App\QueryGenerator Query generator instance */
34
	protected $queryGenerator;
35
	/** @var string[] Name record fields */
36
	protected $nameFields;
37
38
	/**
39
	 * Get calendar extra sources list.
40
	 *
41
	 * @param int $moduleId
42
	 *
43
	 * @return array
44
	 */
45
	public static function getByModule(int $moduleId): array
46
	{
47
		$user = \App\User::getCurrentUserModel();
48
		$query = (new \App\Db\Query())->from(self::EXTRA_SOURCE_TABLE)
49
			->where(['base_module' => $moduleId]);
50
		if (!$user->isAdmin()) {
51
			$query->andWhere(['or', ['public' => 1], ['user_id' => $user->getId()]]);
52
		}
53
		return $query->createCommand(\App\Db::getInstance('admin'))->queryAllByGroup(1);
54
	}
55
56
	/**
57
	 * Get calendar extra source instance by id.
58
	 *
59
	 * @param int $id
60
	 *
61
	 * @return $this
62
	 */
63
	public static function getInstanceById(int $id)
64
	{
65
		$source = self::getById($id);
66
		if (!$source) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $source of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
67
			throw new \App\Exceptions\AppException('No calendar extra source found');
68
		}
69
		$moduleName = \App\Module::getModuleName($source['base_module']);
70
		$className = Vtiger_Loader::getComponentClassName('Model', 'CalendarExtSource', $moduleName);
71
		if ($source['color']) {
72
			$source['textColor'] = \App\Colors::getContrast($source['color']);
73
		}
74
		$instance = new $className($source);
75
		$instance->baseModuleName = $moduleName;
76
		$instance->targetModuleName = \App\Module::getModuleName($source['target_module']);
77
		return $instance;
78
	}
79
80
	/**
81
	 * Get calendar extra source clean instance by module name.
82
	 *
83
	 * @param string $moduleName
84
	 *
85
	 * @return $this
86
	 */
87
	public static function getCleanInstance(string $moduleName)
88
	{
89
		$className = Vtiger_Loader::getComponentClassName('Model', 'CalendarExtSource', $moduleName);
90
		$handler = new $className();
91
		$handler->baseModuleName = $moduleName;
92
		return $handler;
93
	}
94
95
	/**
96
	 * Get calendar extra sources data by id.
97
	 *
98
	 * @param int $id
99
	 *
100
	 * @return string[]
101
	 */
102
	public static function getById(int $id): array
103
	{
104
		if (\App\Cache::has('Calendar-GetExtraSourceById', $id)) {
105
			return \App\Cache::get('Calendar-GetExtraSourceById', $id);
106
		}
107
		$row = (new \App\Db\Query())->from(self::EXTRA_SOURCE_TABLE)
108
			->where(['id' => $id])
109
			->one(\App\Db::getInstance('admin'));
110
		\App\Cache::save('Calendar-GetExtraSourceById', $id, $row, \App\Cache::LONG);
111
		return $row;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $row could return the type false which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
112
	}
113
114
	/**
115
	 * Save calendar extra sources.
116
	 *
117
	 * @return int
118
	 */
119
	public function save(): int
120
	{
121
		$dbCommand = \App\Db::getInstance('admin')->createCommand();
122
		if ($id = $this->get('id')) {
123
			$dbCommand->update(self::EXTRA_SOURCE_TABLE, $this->getData(), [
124
				'id' => $id
125
			])->execute();
126
			\App\Cache::save('Calendar-GetExtraSourceById', $id, $this->getData(), \App\Cache::LONG);
127
		} else {
128
			$params = $this->getData();
129
			$params['user_id'] = \App\User::getCurrentUserId();
130
			$dbCommand->insert(self::EXTRA_SOURCE_TABLE, $params)
131
				->execute();
132
			$id = \App\Db::getInstance('admin')->getLastInsertID(self::EXTRA_SOURCE_TABLE . '_id_seq');
133
		}
134
		\App\Cache::delete('Calendar-GetExtraSourcesList', $this->get('base_module'));
135
		return $id;
136
	}
137
138
	/**
139
	 * Delete calendar extra sources.
140
	 *
141
	 * @return bool
142
	 */
143
	public function delete(): bool
144
	{
145
		$dbCommand = \App\Db::getInstance('admin')->createCommand();
146
		$status = $dbCommand->delete(self::EXTRA_SOURCE_TABLE, ['id' => $this->get('id')])->execute();
147
		\App\Cache::delete('Calendar-GetExtraSourceById', $this->get('id'));
148
		\App\Cache::delete('Calendar-GetExtraSourcesList', $this->get('base_module'));
149
		return (bool) $status;
150
	}
151
152
	/**
153
	 * Get module model.
154
	 *
155
	 * @return Vtiger_Module_Model
156
	 */
157
	public function getModule(): Vtiger_Module_Model
158
	{
159
		if (!$this->targetModuleModel) {
160
			$this->targetModuleModel = \Vtiger_Module_Model::getInstance($this->targetModuleName);
161
		}
162
		return $this->targetModuleModel;
163
	}
164
165
	/**
166
	 * Get extra sources query.
167
	 *
168
	 * @return \App\Db\Query
169
	 */
170
	protected function getExtraSourcesQuery(): ?App\Db\Query
171
	{
172
		if (
173
			!\App\Privilege::isPermitted($this->targetModuleName)
174
			|| !\App\CustomView::getCustomViewById($this->get('custom_view'))
175
		) {
176
			return null;
177
		}
178
		$this->queryGenerator = new App\QueryGenerator($this->targetModuleName);
179
		$this->queryGenerator->initForCustomViewById($this->get('custom_view'));
180
		$this->targetModuleModel = $this->queryGenerator->getModuleModel();
181
		if ($this->get('include_filters')) {
182
			$this->loadExtraSourcesQueryFilter();
183
		}
184
		$this->queryGenerator->clearFields();
185
		$this->queryGenerator->setField('assigned_user_id');
186
		if ($this->get('field_label')) {
187
			$this->nameFields = [$this->getModule()->getField($this->get('field_label'))->getName()];
188
		} else {
189
			$this->nameFields = $this->getModule()->getNameFields();
190
		}
191
		foreach ($this->nameFields as $field) {
192
			$this->queryGenerator->setField($field);
193
		}
194
		$this->loadExtraSourcesQueryType();
195
		return $this->queryGenerator->createQuery();
196
	}
197
198
	/**
199
	 * Load extra sources query condition by type.
200
	 *
201
	 * @return void
202
	 */
203
	protected function loadExtraSourcesQueryType(): void
204
	{
205
		$fieldA = $this->getModule()->getField($this->get('fieldid_a_date'));
206
		$startDateInstance = DateTimeField::convertToDBTimeZone($this->get('start'));
207
		$startDateTime = $startDateInstance->format('Y-m-d H:i:s');
208
		$startDate = $startDateInstance->format('Y-m-d');
209
		$endDateInstance = DateTimeField::convertToDBTimeZone($this->get('end'));
210
		$endDateTime = $endDateInstance->format('Y-m-d H:i:s');
211
		$endDate = $endDateInstance->format('Y-m-d');
212
		if ('datetime' === $fieldA->getFieldDataType()) {
213
			$startFormatted = $startDateTime;
214
			$endFormatted = $endDateTime;
215
		} else {
216
			$startFormatted = $startDate;
217
			$endFormatted = $endDate;
218
		}
219
		$columnA = $fieldA->getTableName() . '.' . $fieldA->getColumnName();
220
		$this->queryGenerator->setField($fieldA->getName());
221
		switch ($this->get('type')) {
222
			case 1:
223
				$this->queryGenerator->addNativeCondition([
224
					'and', ['>=', $columnA, $startFormatted], ['<=', $columnA,  $endFormatted]
225
				]);
226
				break;
227
			case 3:
228
				$fieldB = $this->getModule()->getField($this->get('fieldid_b_date'));
229
				$columnB = $fieldB->getTableName() . '.' . $fieldB->getColumnName();
230
				$this->queryGenerator->setField($fieldB->getName());
231
				$this->queryGenerator->addNativeCondition([
232
					'or',
233
					['and', ['>=', $columnA, $startFormatted], ['<=', $columnA,  $endFormatted]],
234
					['and', ['>=', $columnB, $startFormatted], ['<=', $columnB,  $endFormatted]],
235
					['and', ['<', $columnA, $startFormatted], ['>', $columnB,  $endFormatted]],
236
				]);
237
				break;
238
			case 2:
239
				$fieldTimeA = $this->getModule()->getField($this->get('fieldid_a_time'));
240
				$this->queryGenerator->setField($fieldTimeA->getName());
241
				$columnATime = $fieldTimeA->getTableName() . '.' . $fieldTimeA->getColumnName();
242
				$this->queryGenerator->addNativeCondition([
243
					'or',
244
					[
245
						'and',
246
						['>=', new \yii\db\Expression("CONCAT($columnA, ' ', $columnATime)"),  $startDateTime],
247
						['<=', new \yii\db\Expression("CONCAT($columnA, ' ', $columnATime)"),  $endDateTime],
248
					],
249
				]);
250
				break;
251
			case 4:
252
				$fieldTimeA = $this->getModule()->getField($this->get('fieldid_a_time'));
253
				$fieldB = $this->getModule()->getField($this->get('fieldid_b_date'));
254
				$fieldTimeB = $this->getModule()->getField($this->get('fieldid_b_time'));
255
				$columnATime = $fieldTimeA->getTableName() . '.' . $fieldTimeA->getColumnName();
256
				$columnB = $fieldB->getTableName() . '.' . $fieldB->getColumnName();
257
				$columnBTime = $fieldTimeB->getTableName() . '.' . $fieldTimeB->getColumnName();
258
				$this->queryGenerator->setField($fieldTimeA->getName());
259
				$this->queryGenerator->setField($fieldB->getName());
260
				$this->queryGenerator->setField($fieldTimeB->getName());
261
				$this->queryGenerator->addNativeCondition([
262
					'or',
263
					[
264
						'and',
265
						['>=', new \yii\db\Expression("CONCAT($columnA, ' ', $columnATime)"),  $startDateTime],
266
						['<=', new \yii\db\Expression("CONCAT($columnA, ' ', $columnATime)"),  $endDateTime],
267
					],
268
					[
269
						'and',
270
						['>=', new \yii\db\Expression("CONCAT($columnB, ' ', $columnBTime)"),  $startDateTime],
271
						['<=', new \yii\db\Expression("CONCAT($columnB, ' ', $columnBTime)"),  $endDateTime],
272
					],
273
					[
274
						'and', ['<', $columnA, $startDate], ['>', $columnB,  $endDate],
275
					],
276
				]);
277
				break;
278
			default:
279
				break;
280
		}
281
	}
282
283
	/**
284
	 * Load extra sources query condition by type.
285
	 *
286
	 * @return void
287
	 */
288
	protected function loadExtraSourcesQueryFilter(): void
289
	{
290
		$conditions = [];
291
		if (!empty($this->get('user')) && isset($this->get('user')['selectedIds'][0])) {
292
			$selectedUsers = $this->get('user');
293
			$selectedIds = $selectedUsers['selectedIds'];
294
			if ('all' !== $selectedIds[0]) {
295
				$conditions[] = ['vtiger_crmentity.smownerid' => $selectedIds];
296
				$subQuery = (new \App\Db\Query())->select(['crmid'])
297
					->from('u_#__crmentity_showners')
298
					->where(['userid' => $selectedIds]);
299
				$conditions[] = ['vtiger_crmentity.crmid' => $subQuery];
300
			}
301
			if (isset($selectedUsers['excludedIds']) && 'all' === $selectedIds[0]) {
302
				$conditions[] = ['not in', 'vtiger_crmentity.smownerid', $selectedUsers['excludedIds']];
303
			}
304
		}
305
		if ($conditions) {
306
			$this->queryGenerator->addNativeCondition(array_merge(['or'], $conditions));
307
		}
308
	}
309
310
	/**
311
	 * Get calendar extra source counter.
312
	 *
313
	 * @return int
314
	 */
315
	public function getExtraSourcesCount(): int
316
	{
317
		$privileges = Users_Privileges_Model::getCurrentUserPrivilegesModel();
318
		if ($privileges->hasModuleActionPermission($this->baseModuleName, 'CalendarExtraSources')) {
319
			if ($query = $this->getExtraSourcesQuery()) {
320
				return $query->count();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->count() could return the type string which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
321
			}
322
		}
323
		return 0;
324
	}
325
326
	/**
327
	 * Get calendar extra source rows.
328
	 *
329
	 * @return array
330
	 */
331
	public function getRows(): array
332
	{
333
		$query = $this->getExtraSourcesQuery();
334
		$privileges = Users_Privileges_Model::getCurrentUserPrivilegesModel();
335
		if (!$query || !$privileges->hasModuleActionPermission($this->baseModuleName, 'CalendarExtraSources')) {
336
			return [];
337
		}
338
		$dataReader = $query->createCommand()->query();
339
		$result = [];
340
		while ($row = $dataReader->read()) {
341
			$result[] = $this->formatRow($row);
342
		}
343
		$dataReader->close();
344
		return $result;
345
	}
346
347
	/**
348
	 * Format record data.
349
	 *
350
	 * @param array $row
351
	 *
352
	 * @return array
353
	 */
354
	protected function formatRow(array $row): array
355
	{
356
		$item = [
357
			'id' => $row['id'],
358
			'editable' => false,
359
		];
360
		$this->formatDate($row, $item);
361
		$title = '';
362
		foreach ($this->nameFields as $field) {
363
			$title .= ' ' . \App\Purifier::encodeHtml($row[$field]);
364
		}
365
		$item['title'] = trim($title);
366
		$item['backgroundColor'] = $this->get('color');
367
		$item['textColor'] = $this->get('textColor');
368
		$item['className'] = 'js-show-modal js-quick-detail-modal js-popover-tooltip--record ownerCBr_' . $row['assigned_user_id'];
369
		$item['url'] = 'index.php?module=' . $this->targetModuleName . '&view=Detail&record=' . $row['id'];
370
		return $item;
371
	}
372
373
	/**
374
	 * Format dates.
375
	 *
376
	 * @param array $row
377
	 * @param array $item
378
	 *
379
	 * @return void
380
	 */
381
	protected function formatDate(array $row, array &$item): void
382
	{
383
		$fieldA = $this->getModule()->getField($this->get('fieldid_a_date'));
384
		$valueA = $row[$fieldA->getColumnName()];
385
		switch ($this->get('type')) {
386
			case 3:
387
				$fieldB = $this->getModule()->getField($this->get('fieldid_b_date'));
388
				$valueB = $row[$fieldB->getColumnName()];
389
				if ($valueB) {
390
					if ('datetime' === $fieldB->getFieldDataType()) {
391
						$date = new DateTimeField($valueB);
392
						$item['end'] = $date->getFullcalenderValue();
393
						$item['end_display'] = $date->getDisplayDateTimeValue();
394
					} else {
395
						$item['end'] = $valueB;
396
						$item['end_display'] = \App\Fields\Date::formatToDisplay($valueB);
397
					}
398
				}
399
				// no break
400
			case 1:
401
				if ($valueA) {
402
					if ('datetime' === $fieldA->getFieldDataType()) {
403
						$date = new DateTimeField($valueA);
404
						$item['start'] = $date->getFullcalenderValue();
405
						$item['start_display'] = $date->getDisplayDateTimeValue();
406
					} else {
407
						$item['start'] = $valueA;
408
						$item['start_display'] = \App\Fields\Date::formatToDisplay($valueA);
409
					}
410
				} else {
411
					$item['start'] = $item['end'];
412
					$item['start_display'] = $item['end_display'];
413
				}
414
				break;
415
			case 4:
416
				$valueB = $row[$this->getModule()->getField($this->get('fieldid_b_date'))->getColumnName()];
417
				$valueTimeB = $row[$this->getModule()->getField($this->get('fieldid_b_time'))->getColumnName()];
418
				if ($valueTimeB) {
419
					$date = new DateTimeField($valueB . ' ' . $valueTimeB);
0 ignored issues
show
Bug introduced by
$valueB . ' ' . $valueTimeB of type string is incompatible with the type type expected by parameter $value of DateTimeField::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

419
					$date = new DateTimeField(/** @scrutinizer ignore-type */ $valueB . ' ' . $valueTimeB);
Loading history...
420
					$item['end'] = $date->getFullcalenderValue();
421
					$item['end_display'] = $date->getDisplayDateTimeValue();
422
				}
423
				// no break
424
			case 2:
425
				$valueTimeA = $row[$this->getModule()->getField($this->get('fieldid_a_time'))->getColumnName()];
426
				if ($valueA) {
427
					$date = new DateTimeField($valueA . ' ' . $valueTimeA);
428
					$item['start'] = $date->getFullcalenderValue();
429
					$item['start_display'] = $date->getDisplayDateTimeValue();
430
				} else {
431
					$item['start'] = $item['end'];
432
					$item['start_display'] = $item['end_display'];
433
				}
434
				break;
435
			default:
436
				break;
437
		}
438
	}
439
}
440