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) { |
|
|
|
|
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; |
|
|
|
|
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(); |
|
|
|
|
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); |
|
|
|
|
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
|
|
|
|
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.