Element::getUid()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace AOE\Languagevisibility;
4
5
/***************************************************************
6
 *  Copyright notice
7
 *
8
 *  (c) 2016 AOE GmbH <[email protected]>
9
 *
10
 *  All rights reserved
11
 *
12
 *  This script is part of the TYPO3 project. The TYPO3 project is
13
 *  free software; you can redistribute it and/or modify
14
 *  it under the terms of the GNU General Public License as published by
15
 *  the Free Software Foundation; either version 3 of the License, or
16
 *  (at your option) any later version.
17
 *
18
 *  The GNU General Public License can be found at
19
 *  http://www.gnu.org/copyleft/gpl.html.
20
 *
21
 *  This script is distributed in the hope that it will be useful,
22
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 *  GNU General Public License for more details.
25
 *
26
 *  This copyright notice MUST APPEAR in all copies of the script!
27
 ***************************************************************/
28
29
/**
30
 * Class tx_languagevisibility_element
31
 *
32
 * Abstract basis class for all elements (elements are any translateable records in the system)
33
 */
34
abstract class Element {
35
36
	/**
37
	 * @var string
38
	 */
39
	protected $table;
40
41
	/**
42
	 * @var string
43
	 */
44
	protected $row;
45
46
	/**
47
	 * This array holds the local visibility settings (from the 'tx_languagevisibility_visibility' field)
48
	 *
49
	 * @var array
50
	 */
51
	protected $localVisibilitySetting;
52
53
	/**
54
	 * This array holds the global visibility setting, the global visibility setting. The translation of an element can overwrite
55
	 * the visibility of its own language.
56
	 *
57
	 * @var array
58
	 */
59
	protected $overlayVisibilitySetting;
60
61
	/**
62
	 * @var \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend
63
	 */
64
	protected $cache = NULL;
65
66
	/**
67
	 * @param string $row
68
	 * @param string $tablename
69
	 * @throws \AOE\Languagevisibility\Exceptions\InvalidRowException
70
	 * @return \AOE\Languagevisibility\Element
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
71
	 */
72
	public function __construct($row, $tablename = '') {
73
		if ((!is_array($row)) || !$this->isRowOriginal($row)) {
74
			throw new Exceptions\InvalidRowException();
75
		}
76
77
		$this->row = $row;
0 ignored issues
show
Documentation Bug introduced by
It seems like $row of type array is incompatible with the declared type string of property $row.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
78
79
		$cacheKey = NULL;
80
		if ($tablename && array_key_exists('uid', $this->row) && $this->row['uid'] > 0) {
81
			$cacheKey = sha1(implode('_', array(get_class($this), $tablename, $this->row['uid'])));
82
		}
83
84
		if ($cacheKey && $this->getCache()->has($cacheKey)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cacheKey of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
85
			$this->localVisibilitySetting = $this->getCache()->get($cacheKey);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getCache()->get($cacheKey) of type * is incompatible with the declared type array of property $localVisibilitySetting.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
86
		} elseif ($cacheKey) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cacheKey of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
87
			$this->localVisibilitySetting = @unserialize($this->row['tx_languagevisibility_visibility']);
88
			$this->getCache()->set($cacheKey, $this->localVisibilitySetting);
89
		} else {
90
			$this->localVisibilitySetting = @unserialize($this->row['tx_languagevisibility_visibility']);
91
		}
92
93
		if (!is_array($this->localVisibilitySetting)) {
94
			$this->localVisibilitySetting = array();
95
		}
96
97
		if (!is_array($this->overlayVisibilitySetting)) {
98
			$this->overlayVisibilitySetting = array();
99
		}
100
101
		$this->initialisations();
102
	}
103
104
	/**
105
	 * Sets the table name
106
	 *
107
	 * @param string $table
108
	 * @return void
109
	 */
110
	public function setTable($table) {
111
		$this->table = $table;
112
	}
113
114
	/**
115
	 * Gets the table name
116
	 *
117
	 * @return string
118
	 */
119
	public function getTable() {
120
		return $this->table;
121
	}
122
123
	/**
124
	 * Method to determine that an Element will not be instantiated with
125
	 * data of an overlay.
126
	 */
127
	protected function isRowOriginal($row) {
128
		if (!isset($row['l18n_parent']) && !isset($row['l10n_parent'])) {
129
			return TRUE;
130
		}
131
		if (isset($row['l18n_parent']) && $row['l18n_parent'] == 0) {
132
			return TRUE;
133
		}
134
		if (isset($row['l10n_parent']) && $row['l10n_parent'] == 0) {
135
			return TRUE;
136
		}
137
		return FALSE;
138
	}
139
140
	/**
141
	 * possibility to add inits in subclasses
142
	 **/
143
	protected function initialisations() {
144
	}
145
146
	/**
147
	 * Returns the Uid of the Element
148
	 *
149
	 * @return int
150
	 */
151
	public function getUid() {
152
		return $this->row['uid'];
153
	}
154
155
	/**
156
	 * Returns the pid of the Element
157
	 *
158
	 * @return int
159
	 */
160
	public function getPid() {
161
		return $this->row['pid'];
162
	}
163
164
	/**
165
	 * Return the content of the title field
166
	 *
167
	 * @return unknown
168
	 */
169
	public function getTitle() {
170
		return $this->row['title'];
171
	}
172
173
	/**
174
	 * Returns the uid of the original element. This method will only return
175
	 * a non zero value if the element is an overlay;
176
	 *
177
	 * @return int
178
	 */
179
	public function getOrigElementUid() {
180
		if (isset($this->row['l18n_parent'])) {
181
			   return $this->row['l18n_parent'];
182
	   }
183
	   if (isset($this->row['l10n_parent'])) {
184
				return $this->row['l10n_parent'];
185
		}
186
	   return 0;
187
	}
188
189
	/**
190
	 * Returns the workspace uid of an element.
191
	 *
192
	 * @return unknown
193
	 */
194
	public function getWorkspaceUid() {
195
		$wsId = 0;
196
		if (isset($GLOBALS['TCA'][$this->table]['ctrl']['versioningWS']) && $GLOBALS['TCA'][$this->table]['ctrl']['versioningWS'] > 0) {
197
			$wsId = $this->row['t3ver_wsid'];
198
		}
199
		return $wsId;
200
	}
201
202
	/**
203
	 * Returns an description of the element.
204
	 *
205
	 * @return string
206
	 */
207
	public function getInformativeDescription() {
208
		if ($this->isMonolithicTranslated()) {
209
			 return 'this content element is not in default language. Its only visible in the selected language';
210
		}
211
		elseif ( $this->isLanguageSetToAll()) {
212
			return 'Language is set to all - element is visibily in every language';
213
		}
214
		elseif ( $this->isLanguageSetToDefault()) {
215
			return 'this is a normal content element (translations are managed with overlay records)';
216
217
		} else {
218
			return 'this content element is already a translated version therefore content overlays are not suppoted';
219
		}
220
	}
221
222
	/**
223
	 * This method is used to determine the visibility of the element. Technically it merges the visibility of
224
	 * the default language record and the overlay record and returns the visibility. The visibility in the overlayrecord
225
	 * can overwrite the visibility of its own language.
226
	 *
227
	 * @param $languageid
228
	 * @return string
229
	 */
230
	public function getLocalVisibilitySetting($languageid) {
231
		$overlayVisibility = $this->getVisibilitySettingStoredInOverlayRecord($languageid);
232
		$localVisibility = $this->getVisibilitySettingStoredInDefaultRecord($languageid);
233
234
		if ($overlayVisibility == 'no+' || $localVisibility == 'no+') {
235
			$res = 'no+';
236
		} elseif ($overlayVisibility == 'no') {
237
			$res = $overlayVisibility;
238
		} else {
239
			$res = $localVisibility;
240
		}
241
242
		return $res;
243
	}
244
245
	//make protected?
246
	/**
247
	 * Returns the global visibility setting for the element (saved in the overlay)
248
	 *
249
	 * @param $languageid
250
	 * @return string
251
	 */
252
	public function getVisibilitySettingStoredInOverlayRecord($languageid) {
253
			//if global visibility has not been determined, determine and cache it
254
		if (is_array($this->overlayVisibilitySetting)) {
255
			if (! isset($this->overlayVisibilitySetting[$languageid])) {
256
				$overlay = $this->getOverLayRecordForCertainLanguage($languageid);
257
				$overlayVisibilitySettings = @unserialize($overlay['tx_languagevisibility_visibility']);
258
259
				if (is_array($overlayVisibilitySettings)) {
260
					$this->overlayVisibilitySetting[$languageid] = $overlayVisibilitySettings[$languageid];
261
				} else {
262
					$this->overlayVisibilitySetting[$languageid] = '-';
263
				}
264
			}
265
		}
266
267
		return $this->overlayVisibilitySetting[$languageid];
268
	}
269
270
	/**
271
	 * This method is only need to display the visibility setting in the backend.
272
	 *
273
	 * @param int $languageid
274
	 * @return string
275
	 */
276
	public function getVisibilitySettingStoredInDefaultRecord($languageid) {
277
		return $this->localVisibilitySetting[$languageid];
278
	}
279
280
	/**
281
	 * This method returns an overlay of a record, independent from
282
	 * a frontend or backend context
283
	 *
284
	 * @param string $table
285
	 * @param string $olrow
286
	 * @return array
287
	 */
288
	protected function getContextIndependentWorkspaceOverlay($table, $olrow) {
289
		if (is_object($GLOBALS['TSFE']->sys_page)) {
290
			$GLOBALS['TSFE']->sys_page->versionOL($table, $olrow);
291
		} else {
292
			\TYPO3\CMS\Backend\Utility\BackendUtility::workspaceOL($table, $olrow);
0 ignored issues
show
Documentation introduced by
$olrow is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
293
		}
294
295
		return $olrow;
296
	}
297
298
	/**
299
	 * receive relevant fallbackOrder
300
	 */
301
	public function getFallbackOrder(Language $language) {
302
		return $language->getFallbackOrder($this);
303
	}
304
305
306
	/**
307
	 * Check if the element is set to the default language
308
	 *
309
	 * @return boolean
310
	 */
311
	public function isLanguageSetToDefault() {
312
		return $this->row['sys_language_uid'] == '0';
313
	}
314
315
	/**
316
	 * Determines if the elements is a original or a overlay-element
317
	 *
318
	 * @return boolean
319
	 */
320
	protected function isOrigElement() {
321
		if ($this->getOrigElementUid() > 0 ) {
322
			return FALSE;
323
	   }
324
	   return TRUE;
325
	}
326
327
	/**
328
	 * Checks if the current record is set to language all (that is typically used to indicate that per default this element is visible in all langauges)
329
	 *
330
	 * @return boolean
331
	 */
332
	public function isLanguageSetToAll() {
333
		if ($this->row['sys_language_uid'] == '-1') {
334
			return TRUE;
335
		} else {
336
			return FALSE;
337
		}
338
	}
339
340
	/**
341
	 * Method to check the element is an Workspaceelement or not.
342
	 *
343
	 * @return boolean
344
	 */
345
	public function isLiveWorkspaceElement() {
346
		return ($this->row['pid'] != - 1);
347
	}
348
349
	/**
350
	 * Determines whether the element is a translated original record ...
351
	 *
352
	 * @return boolean
353
	 */
354
	public function isMonolithicTranslated() {
355
		/*
356
		 * Timo: this does not work with pages because pages do not have the field 'sys_language_uid'
357
		 * and the languagevisibility_pages class only represent elements from the table pages not
358
		 * from page_language_overlay
359
		 */
360
		return ( !$this->isLanguageSetToDefault()) && (!$this->isLanguageSetToAll())  && $this->isOrigElement();
361
	}
362
363
	/**
364
	 * Compare element-language and foreign language.
365
	 * @ todo make this method work for pages
366
	 *
367
	 * @param Language $language
368
	 * @return boolean
369
	 */
370
	public function languageEquals(Language $language) {
371
		return $this->row['sys_language_uid'] == $language->getUid();
372
	}
373
374
	/**
375
	 * Checks if this element has a translation, therefor several DB accesses are required
376
	 *
377
	 * @param $languageid
378
	 * @return boolean
379
	 */
380
	public function hasTranslation($languageid) {
381
382
		$result = FALSE;
383
		if (! is_numeric($languageid)) {
384
			$result = FALSE;
385
		} else if ($languageid == 0) {
386
			$result = TRUE;
387
		} else if ($this->_hasOverlayRecordForLanguage($languageid)) {
388
			$result = TRUE;
389
		}
390
391
		return $result;
392
	}
393
394
	/**
395
	 * Checks if this Element has a Translation in any workspace.
396
	 *
397
	 * @return boolean
398
	 */
399
	public function hasAnyTranslationInAnyWorkspace() {
400
		if ($this->hasOverLayRecordForAnyLanguageInAnyWorkspace()) {
401
			return TRUE;
402
		} else {
403
			return FALSE;
404
		}
405
	}
406
407
	/**
408
	 * This method can be used to determine if an overlay for a language exists.
409
	 *
410
	 * @return boolean
411
	 * @param int $langid
412
	 */
413
	protected function _hasOverlayRecordForLanguage($langid) {
414
		$row = $this->getOverLayRecordForCertainLanguage($langid, TRUE);
415
		return $row['uid'] != '';
416
	}
417
418
	/**
419
	 * Returns which field in the language should be used to read the default visibility
420
	 *
421
	 *@return string (blank=default / page=page)
422
	 **/
423
	public function getFieldToUseForDefaultVisibility() {
424
		return '';
425
	}
426
427
	/**
428
	 * Method to get a short description  of the elementtype.
429
	 * An extending class should overwrite this method.
430
	 *
431
	 * @return string
432
	 */
433
	public function getElementDescription() {
434
		return 'TYPO3 Element';
435
	}
436
437
	/**
438
	 * By default no element supports inheritance
439
	 *
440
	 * @param void
441
	 * @return boolean
442
	 */
443
	public function supportsInheritance() {
444
		return FALSE;
445
	}
446
447
	/**
448
	 * Gets the cache
449
	 *
450
	 * @return \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend
451
	 */
452
	protected function getCache() {
453
		if (!$this->cache) {
454
			$this->cache = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')
455
				->getCache('tx_languagevisibility');
456
		}
457
458
		return $this->cache;
459
	}
460
461
	/**
462
	 * This method is used to retrieve an overlay record of a given record.
463
	 *
464
	 * @param $languageId
465
	 * @param $onlyUid
466
	 * @return array
467
	 */
468
	public function getOverLayRecordForCertainLanguage($languageId, $onlyUid = FALSE) {
0 ignored issues
show
Unused Code introduced by
The parameter $onlyUid is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
469
		//get caching hints
470
		$table = $this->getTable();
471
		$uid = $this->getUid();
472
		$workspace = intval($GLOBALS['BE_USER']->workspace);
473
474
		$cacheManager = CacheManager::getInstance();
475
476
		$cacheData = $cacheManager->get('overlayRecordCache');
477
		$isCacheEnabled = $cacheManager->isCacheEnabled();
478
		if (! $isCacheEnabled || ! isset($cacheData[$table][$uid][$languageId][$workspace])) {
479
			$cacheData[$table][$uid][$languageId][$workspace] = $this->getOverLayRecordForCertainLanguageImplementation($languageId);
480
			$cacheManager->set('overlayRecordCache', $cacheData);
481
		}
482
483
		return $cacheData[$table][$uid][$languageId][$workspace];
484
	}
485
486
	/**
487
	 * Check the records enableColumns
488
	 *
489
	 * @param  $row
490
	 * @return bool
491
	 */
492
	protected function getEnableFieldResult($row) {
493
		$ctrl = $GLOBALS['TCA'][$this->table]['ctrl'];
494
		$enabled = TRUE;
495
		if (is_array($ctrl['enablecolumns'])) {
496
			if ($ctrl['enablecolumns']['disabled']) {
497
				$enabled = $row[$ctrl['enablecolumns']['disabled']] == 0;
498
			}
499
			if ($ctrl['enablecolumns']['starttime']) {
500
				$enabled &= $row[$ctrl['enablecolumns']['starttime']] <= $GLOBALS['SIM_ACCESS_TIME'];
501
			}
502
			if ($ctrl['enablecolumns']['endtime']) {
503
				$endtime = $row[$ctrl['enablecolumns']['endtime']];
504
				$enabled &= $endtime == 0 || $endtime > $GLOBALS['SIM_ACCESS_TIME'];
505
			}
506
507
			if ($ctrl['enablecolumns']['fe_group'] && is_object($GLOBALS['TSFE'])) {
508
				$fe_group = $row[$ctrl['enablecolumns']['fe_group']];
509
				if ($fe_group) {
510
					$currentUserGroups = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $GLOBALS['TSFE']->gr_list);
511
					$recordGroups = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $fe_group);
512
					$sharedGroups = array_intersect($recordGroups, $currentUserGroups);
513
					$enabled &= count($sharedGroups) > 0;
514
				}
515
			}
516
		}
517
		return $enabled;
518
	}
519
520
	/**
521
	 * Abstract method to determine if there exsists any translation in any workspace.
522
	 *
523
	 * @return boolean
524
	 */
525
	abstract public function hasOverLayRecordForAnyLanguageInAnyWorkspace();
526
527
	/**
528
	 * This method should provide the implementation to get the overlay of an element for a
529
	 * certain language. The result is cached be the method getOverLayRecordForCertainLanguage.
530
	 *
531
	 * @param int $languageId
532
	 * @return
533
	 */
534
	abstract protected function getOverLayRecordForCertainLanguageImplementation($languageId);
535
}
536