Completed
Push — dev ( 7310d2...60fbb5 )
by Nicolas
01:35
created

FieldEntry_relationship::createFieldName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 3
1
<?php
2
	/*
3
	Copyright: Deux Huit Huit 2014
4
	LICENCE: MIT http://deuxhuithuit.mit-license.org;
5
	*/
6
7
	if (!defined('__IN_SYMPHONY__')) die('<h2>Symphony Error</h2><p>You cannot directly access this file</p>');
8
9
	require_once(TOOLKIT . '/class.field.php');
10
	require_once(EXTENSIONS . '/entry_relationship_field/lib/class.cacheablefetch.php');
11
	require_once(EXTENSIONS . '/entry_relationship_field/lib/class.erfxsltutilities.php');
12
	
13
	/**
14
	 *
15
	 * Field class that will represent relationships between entries
16
	 * @author Deux Huit Huit
17
	 *
18
	 */
19
	class FieldEntry_relationship extends Field
20
	{
21
		
22
		/**
23
		 *
24
		 * Name of the field table
25
		 *  @var string
26
		 */
27
		const FIELD_TBL_NAME = 'tbl_fields_entry_relationship';
28
		
29
		/**
30
		 * 
31
		 * Separator char for values
32
		 *  @var string
33
		 */
34
		const SEPARATOR = ',';
35
		
36
		
37
		/**
38
		 *
39
		 * Current recursive level of output
40
		 *  @var int
41
		 */
42
		protected $recursiveLevel = 1;
43
		public function getRecursiveLevel()
44
		{
45
			return $this->recursiveLevel;
46
		}
47
		public function incrementRecursiveLevel($inc = 1)
48
		{
49
			return $this->recursiveLevel += $inc;
50
		}
51
		
52
		/**
53
		 *
54
		 * Parent's maximum recursive level of output
55
		 *  @var int
56
		 */
57
		protected $recursiveDeepness = null;
58
		public function getRecursiveDeepness()
59
		{
60
			return $this->recursiveDeepness;
61
		}
62
		public function setRecursiveDeepness($deepness)
63
		{
64
			return $this->recursiveDeepness = $deepness;
65
		}
66
		
67
		/* Cacheable Managers */
68
		private $sectionManager;
69
		private $entryManager;
70
		
71
		/**
72
		 *
73
		 * Constructor for the oEmbed Field object
74
		 */
75
		public function __construct()
76
		{
77
			// call the parent constructor
78
			parent::__construct();
79
			// set the name of the field
80
			$this->_name = __('Entry Relationship');
81
			// permits to make it required
82
			$this->_required = true;
83
			// permits the make it show in the table columns
84
			$this->_showcolumn = true;
85
			// permits association
86
			$this->_showassociation = true;
87
			// current recursive level
88
			$this->recursiveLevel = 1;
89
			// parent's maximum recursive level of output
90
			$this->recursiveDeepness = null;
91
			// set as not required by default
92
			$this->set('required', 'no');
93
			// show association by default
94
			$this->set('show_association', 'yes');
95
			// no sections
96
			$this->set('sections', null);
97
			// no max deepness
98
			$this->set('deepness', null);
99
			// no included elements
100
			$this->set('elements', null);
101
			// no modes
102
			$this->set('mode', null);
103
			$this->set('mode_table', null);
104
			$this->set('mode_header', null);
105
			$this->set('mode_footer', null);
106
			// no limit
107
			$this->set('min_entries', null);
108
			$this->set('max_entries', null);
109
			// all permissions
110
			$this->set('allow_new', 'yes');
111
			$this->set('allow_edit', 'yes');
112
			$this->set('allow_link', 'yes');
113
			$this->set('allow_delete', 'no');
114
			// display options
115
			$this->set('allow_collapse', 'yes');
116
			$this->set('show_header', 'yes');
117
			$this->sectionManager = new CacheableFetch('SectionManager');
118
			$this->entryManager = new CacheableFetch('EntryManager');
119
		}
120
121
		public function isSortable()
122
		{
123
			return false;
124
		}
125
126
		public function canFilter()
127
		{
128
			return true;
129
		}
130
		
131
		public function canPublishFilter()
132
		{
133
			return false;
134
		}
135
136
		public function canImport()
137
		{
138
			return false;
139
		}
140
141
		public function canPrePopulate()
142
		{
143
			return false;
144
		}
145
		
146
		public function mustBeUnique()
147
		{
148
			return false;
149
		}
150
151
		public function allowDatasourceOutputGrouping()
152
		{
153
			return false;
154
		}
155
156
		public function requiresSQLGrouping()
157
		{
158
			return false;
159
		}
160
161
		public function allowDatasourceParamOutput()
162
		{
163
			return true;
164
		}
165
166
		/**
167
		 * @param string $name
168
		 */
169
		public function getInt($name)
170
		{
171
			return General::intval($this->get($name));
172
		}
173
174
		/**
175
		 * Check if a given property is == 'yes'
176
		 * @param string $name
177
		 * @return bool
178
		 *  True if the current field's value is 'yes'
179
		 */
180
		public function is($name)
181
		{
182
			return $this->get($name) == 'yes';
183
		}
184
185
		/**
186
		 * @return bool
187
		 *  True if the current field is required
188
		 */
189
		public function isRequired()
190
		{
191
			return $this->is('required');
192
		}
193
194
		public static function getEntries(array $data)
195
		{
196
			return array_map(array('General', 'intval'), array_filter(array_map(trim, explode(self::SEPARATOR, $data['entries']))));
197
		}
198
199
		/* ********** INPUT AND FIELD *********** */
200
201
202
		/**
203
		 * 
204
		 * Validates input
205
		 * Called before <code>processRawFieldData</code>
206
		 * @param $data
207
		 * @param $message
208
		 * @param $entry_id
209
		 */
210
		public function checkPostFieldData($data, &$message, $entry_id=null)
211
		{
212
			$message = null;
213
			$required = $this->isRequired();
214
			
215
			if ($required && (!is_array($data) || count($data) == 0 || strlen($data['entries']) < 1)) {
216
				$message = __("'%s' is a required field.", array($this->get('label')));
217
				return self::__MISSING_FIELDS__;
218
			}
219
			
220
			$entries = $data['entries'];
221
			
222
			if (!is_array($entries)) {
223
				$entries = static::getEntries($data);
224
			}
225
			
226
			// enforce limits only if required or it contains data
227
			if ($required || count($entries) > 0) {
228
				if ($this->getInt('min_entries') > 0 && $this->getInt('min_entries') > count($entries)) {
229
					$message = __("'%s' requires a minimum of %s entries.", array($this->get('label'), $this->getInt('min_entries')));
230
					return self::__INVALID_FIELDS__;
231
				} else if ($this->getInt('max_entries') > 0 && $this->getInt('max_entries') < count($entries)) {
232
					$message = __("'%s' can not contains more than %s entries.", array($this->get('label'), $this->getInt('max_entries')));
233
					return self::__INVALID_FIELDS__;
234
				}
235
			}
236
			
237
			return self::__OK__;
238
		}
239
240
241
		/**
242
		 *
243
		 * Process data before saving into database.
244
		 *
245
		 * @param array $data
246
		 * @param int $status
247
		 * @param boolean $simulate
248
		 * @param int $entry_id
249
		 *
250
		 * @return Array - data to be inserted into DB
251
		 */
252
		public function processRawFieldData($data, &$status, &$message = null, $simulate = false, $entry_id = null)
253
		{
254
			$status = self::__OK__;
255
			$entries = null;
256
			
257
			if (!is_array($data) && !is_string($data)) {
258
				return null;
259
			}
260
			
261
			if (isset($data['entries'])) {
262
				$entries = $data['entries'];
263
			}
264
			else if (is_string($data)) {
265
				$entries = $data;
266
			}
267
			
268
			$row = array(
269
				'entries' => $entries
270
			);
271
			
272
			// return row
273
			return $row;
274
		}
275
276
		/**
277
		 * This function permits parsing different field settings values
278
		 *
279
		 * @param array $settings
280
		 *	the data array to initialize if necessary.
281
		 */
282
		public function setFromPOST(Array $settings = array())
283
		{
284
			// call the default behavior
285
			parent::setFromPOST($settings);
286
287
			// declare a new setting array
288
			$new_settings = array();
289
290
			// set new settings
291
			$new_settings['sections'] = is_array($settings['sections']) ? 
292
				implode(self::SEPARATOR, $settings['sections']) : 
293
				(is_string($settings['sections']) ? $settings['sections'] : null);
294
				
295
			$new_settings['show_association'] = $settings['show_association'] == 'yes' ? 'yes' : 'no';
296
			$new_settings['deepness'] = General::intval($settings['deepness']);
297
			$new_settings['deepness'] = $new_settings['deepness'] < 1 ? null : $new_settings['deepness'];
298
			$new_settings['elements'] = empty($settings['elements']) ? null : $settings['elements'];
299
			$new_settings['mode'] = empty($settings['mode']) ? null : $settings['mode'];
300
			$new_settings['mode_table'] = empty($settings['mode_table']) ? null : $settings['mode_table'];
301
			$new_settings['mode_header'] = empty($settings['mode_header']) ? null : $settings['mode_header'];
302
			$new_settings['mode_footer'] = empty($settings['mode_footer']) ? null : $settings['mode_footer'];
303
			$new_settings['allow_new'] = $settings['allow_new'] == 'yes' ? 'yes' : 'no';
304
			$new_settings['allow_edit'] = $settings['allow_edit'] == 'yes' ? 'yes' : 'no';
305
			$new_settings['allow_link'] = $settings['allow_link'] == 'yes' ? 'yes' : 'no';
306
			$new_settings['allow_delete'] = $settings['allow_delete'] == 'yes' ? 'yes' : 'no';
307
			$new_settings['allow_collapse'] = $settings['allow_collapse'] == 'yes' ? 'yes' : 'no';
308
			$new_settings['show_header'] = $settings['show_header'] == 'yes' ? 'yes' : 'no';
309
			
310
			// save it into the array
311
			$this->setArray($new_settings);
312
		}
313
314
315
		/**
316
		 *
317
		 * Validates the field settings before saving it into the field's table
318
		 */
319
		public function checkFields(Array &$errors, $checkForDuplicates = true)
320
		{
321
			$parent = parent::checkFields($errors, $checkForDuplicates);
322
			if ($parent != self::__OK__) {
323
				return $parent;
324
			}
325
			
326
			$sections = $this->get('sections');
327
			
328
			if (empty($sections)) {
329
				$errors['sections'] = __('At least one section must be chosen');
330
			}
331
332
			return (!empty($errors) ? self::__ERROR__ : self::__OK__);
333
		}
334
335
		/**
336
		 *
337
		 * Save field settings into the field's table
338
		 */
339
		public function commit()
340
		{
341
			// if the default implementation works...
342
			if(!parent::commit()) return false;
343
			
344
			$id = $this->get('id');
345
			
346
			// exit if there is no id
347
			if($id == false) return false;
348
			
349
			// we are the child, with multiple parents
350
			$child_field_id = $id;
351
			
352
			// delete associations, only where we are the child
353
			self::removeSectionAssociation($child_field_id);
354
			
355
			$sections = $this->getSelectedSectionsArray();
356
			
357
			foreach ($sections as $key => $sectionId) {
358
				if (empty($sectionId)) {
359
					continue;
360
				}
361
				$parent_section_id = General::intval($sectionId);
362
				$parent_section = SectionManager::fetch($sectionId);
363
				$fields = $parent_section->fetchVisibleColumns();
364
				if (empty($fields)) {
365
					// no visible field, revert to all
366
					$fields = $parent_section->fetchFields();
367
				}
368
				$parent_field_id = current(array_keys($fields));
369
				// create association
370
				SectionManager::createSectionAssociation(
371
					$parent_section_id,
372
					$child_field_id,
373
					$parent_field_id,
374
					$this->get('show_association') == 'yes'
375
				);
376
			}
377
			
378
			// declare an array contains the field's settings
379
			$settings = array(
380
				'sections' => $this->get('sections'),
381
				'show_association' => $this->get('show_association'),
382
				'deepness' => $this->get('deepness'),
383
				'elements' => $this->get('elements'),
384
				'mode' => $this->get('mode'),
385
				'mode_table' => $this->get('mode_table'),
386
				'mode_header' => $this->get('mode_header'),
387
				'mode_footer' => $this->get('mode_footer'),
388
				'min_entries' => $this->get('min_entries'),
389
				'max_entries' => $this->get('max_entries'),
390
				'allow_new' => $this->get('allow_new'),
391
				'allow_edit' => $this->get('allow_edit'),
392
				'allow_link' => $this->get('allow_link'),
393
				'allow_delete' => $this->get('allow_delete'),
394
				'allow_collapse' => $this->get('allow_collapse'),
395
				'show_header' => $this->get('show_header'),
396
			);
397
398
			return FieldManager::saveSettings($id, $settings);
399
		}
400
401
		/**
402
		 *
403
		 * This function allows Fields to cleanup any additional things before it is removed
404
		 * from the section.
405
		 * @return boolean
406
		 */
407
		public function tearDown()
408
		{
409
			self::removeSectionAssociation($this->get('id'));
410
			return parent::tearDown();
411
		}
412
		
413
		/**
414
		 * Generates the where filter for searching by entry id
415
		 *
416
		 * @param string $value
417
		 * @param @optional string $col
418
		 * @param @optional boolean $andOperation
419
		 */
420
		public function generateWhereFilter($value, $col = 'd', $andOperation = true)
421
		{
422
			$junction = $andOperation ? 'AND' : 'OR';
423
			if (!$value) {
424
				return "{$junction} (`{$col}`.`entries` IS NULL)";
425
			}
426
			return " {$junction} (`{$col}`.`entries` = '{$value}' OR 
427
					`{$col}`.`entries` LIKE '{$value},%' OR 
428
					`{$col}`.`entries` LIKE '%,{$value}' OR 
429
					`{$col}`.`entries` LIKE '%,{$value},%')";
430
		}
431
432
		/**
433
		 * Fetch the number of associated entries for a particular entry id
434
		 *
435
		 * @param string $value
436
		 */
437
		public function fetchAssociatedEntryCount($value)
438
		{
439
			if (!$value) {
440
				return 0;
441
			}
442
			$join = sprintf(" INNER JOIN `tbl_entries_data_%s` AS `d` ON `e`.id = `d`.`entry_id`", $this->get('id'));
443
			$where = $this->generateWhereFilter($value);
444
			
445
			$entries = EntryManager::fetch(null, $this->get('parent_section'), null, 0, $where, $join, false, false, array());
446
			
447
			return count($entries);
448
		}
449
		
450
		public function fetchAssociatedEntrySearchValue($data, $field_id = null, $parent_entry_id = null)
451
		{
452
			return $parent_entry_id;
453
		}
454
		
455
		public function findRelatedEntries($entry_id, $parent_field_id)
456
		{
457
			$joins = '';
458
			$where = '';
459
			$this->buildDSRetrievalSQL(array($entry_id), $joins, $where, true);
460
			
461
			$entries = EntryManager::fetch(null, $this->get('parent_section'), null, 0, $where, $joins, false, false, array());
462
			
463
			$ids = array();
464
			foreach ($entries as $key => $e) {
465
				$ids[] = $e['id'];
466
			}
467
			return $ids;
468
		}
469
		
470
		public function prepareAssociationsDrawerXMLElement(Entry $e, array $parent_association, $prepolutate = '')
471
		{
472
			$currentSection = SectionManager::fetch($parent_association['child_section_id']);
473
			$visibleCols = $currentSection->fetchVisibleColumns();
474
			$outputFieldId = current(array_keys($visibleCols));
475
			$outputField = FieldManager::fetch($outputFieldId);
476
			
477
			$value = $outputField->prepareReadableValue($e->getData($outputFieldId), $e->get('id'), true, __('None'));
478
			
479
			$li = new XMLElement('li');
480
			$li->setAttribute('class', 'field-' . $this->get('type'));
481
			$a = new XMLElement('a', strip_tags($value));
482
			$a->setAttribute('href', SYMPHONY_URL . '/publish/' . $parent_association['handle'] . '/edit/' . $e->get('id') . '/');
483
			$li->appendChild($a);
484
485
			return $li;
486
		}
487
		
488
		/**
489
		 * @param string $joins
490
		 * @param string $where
491
		 */
492
		public function buildDSRetrievalSQL($data, &$joins, &$where, $andOperation = false)
493
		{
494
			$field_id = $this->get('id');
495
			
496
			// REGEX filtering is a special case, and will only work on the first item
497
			// in the array. You cannot specify multiple filters when REGEX is involved.
498
			if (self::isFilterRegex($data[0])) {
499
				return $this->buildRegexSQL($data[0], array('entries'), $joins, $where);
500
			}
501
			
502
			$this->_key++;
503
			
504
			$where .= ' AND (1=' . ($andOperation ? '1' : '0') . ' ';
505
			
506
			$joins .= "
507
				INNER JOIN
508
					`tbl_entries_data_{$field_id}` AS `t{$field_id}_{$this->_key}`
509
					ON (`e`.`id` = `t{$field_id}_{$this->_key}`.`entry_id`)
510
			";
511
			
512
			foreach ($data as $value) {
513
				$where .= $this->generateWhereFilter($this->cleanValue($value), "t{$field_id}_{$this->_key}", $andOperation);
514
			}
515
			
516
			$where .= ')';
517
			
518
			return true; // this tells the DS Manager that filters are OK!!
519
		}
520
521
		/* ******* EVENTS ******* */
522
523
		public function getExampleFormMarkup()
524
		{
525
			$label = Widget::Label($this->get('label'));
526
			$label->appendChild(Widget::Input('fields['.$this->get('element_name').'][entries]', null, 'hidden'));
527
528
			return $label;
529
		}
530
531
532
		/* ******* DATA SOURCE ******* */
533
		
534
		private function fetchEntry($eId, $elements = array())
535
		{
536
			$entry = EntryManager::fetch($eId, null, 1, 0, null, null, false, true, $elements, false);
537
			if (!is_array($entry) || count($entry) !== 1) {
538
				return null;
539
			}
540
			return $entry[0];
541
		}
542
		
543
		public function fetchIncludableElements()
544
		{
545
			$label = $this->get('element_name');
546
			$elements = array_filter(array_map(trim, explode(self::SEPARATOR, trim($this->get('elements')))));
547
			$includedElements = array($label . ': *');
548
			foreach ($elements as $elem) {
549
				$elem = trim($elem);
550
				if ($elem !== '*') {
551
					$includedElements[] = $label . ': ' . $elem;
552
				}
553
			}
554
			return $includedElements;
555
		}
556
		
557
		/**
558
		 * Appends data into the XML tree of a Data Source
559
		 * @param $wrapper
560
		 * @param $data
561
		 */
562
		public function appendFormattedElement(XMLElement &$wrapper, $data, $encode = false, $mode = null, $entry_id = null)
563
		{
564
			if(!is_array($data) || empty($data)) return;
565
566
			// root for all values
567
			$root = new XMLElement($this->get('element_name'));
568
			
569
			// selected items
570
			$entries = static::getEntries($data);
571
			
572
			// current linked entries
573
			$root->setAttribute('entries', $data['entries']);
574
			
575
			// available sections
576
			$root->setAttribute('sections', $this->get('sections'));
577
			
578
			// included elements
579
			$elements = static::parseElements($this);
580
			
581
			// DS mode
582
			if (!$mode) {
583
				$mode = '*';
584
			}
585
			
586
			$parentDeepness = General::intval($this->recursiveDeepness);
587
			$deepness = General::intval($this->get('deepness'));
588
			
589
			// both deepnesses are defined and parent restricts more
590
			if ($parentDeepness > 0 && $deepness > 0 && $parentDeepness < $deepness) {
591
				$deepness = $parentDeepness;
592
			}
593
			// parent is defined, current is not
594
			else if ($parentDeepness > 0 && $deepness < 1) {
595
				$deepness = $parentDeepness;
596
			}
597
			
598
			// cache recursive level because recursion might
599
			// change its value later on.
600
			$recursiveLevel = $this->recursiveLevel;
601
			
602
			// build entries
603
			foreach ($entries as $eId) {
604
				$item = new XMLElement('item');
605
				// output id
606
				$item->setAttribute('id', $eId);
607
				// output recursive level
608
				$item->setAttribute('level', $recursiveLevel);
609
				$item->setAttribute('max-level', $deepness);
610
				
611
				// max recursion check
612
				if ($deepness < 1 || $recursiveLevel < $deepness) {
613
					// current entry, without data
614
					$entry = $this->fetchEntry($eId);
615
					
616
					// entry not found...
617
					if (!$entry || empty($entry)) {
618
						$error = new XMLElement('error');
619
						$error->setAttribute('id', $eId);
620
						$error->setValue(__('Error: entry `%s` not found', array($eId)));
621
						$root->prependChild($error);
622
						continue;
623
					}
624
					
625
					// fetch section infos
626
					$sectionId = $entry->get('section_id');
627
					$section = $this->sectionManager->fetch($sectionId);
628
					$sectionName = $section->get('handle');
629
					// cache fields info
630
					if (!isset($section->er_field_cache)) {
631
						$section->er_field_cache = $section->fetchFields();
632
					}
633
					
634
					// set section related attributes
635
					$item->setAttribute('section-id', $sectionId);
636
					$item->setAttribute('section', $sectionName);
637
					
638
					// Get the valid elements for this section only
639
					$validElements = $elements[$sectionName];
640
					
641
					// adjust the mode for the current section
642
					$curMode = $mode;
643
					
644
					// remove section name from current mode, i.e sectionName.field
645
					if (preg_match('/^(' . $sectionName . '\.)(.*)$/sU', $curMode)) {
646
						$curMode = preg_replace('/^' . $sectionName . '\./sU', '', $curMode);
647
					}
648
					// remove section name from current mode, i.e sectionName
649
					else if (preg_match('/^(' . $sectionName . ')$/sU', $curMode)) {
650
						$curMode = '*';
651
					}
652
					// section name was not found in mode
653
					else if ($curMode != '*') {
654
						// mode forbids this section
655
						$validElements = null;
656
					}
657
					
658
					// this section is not selected, bail out
659
					if (!is_array($validElements)) {
660
						$item->setAttribute('forbidden-by', $curMode);
661
						$root->appendChild($item);
662
						continue;
663
					}
664
					
665
					// selected fields for fetching
666
					$sectionElements = array();
0 ignored issues
show
Unused Code introduced by
$sectionElements is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
667
					
668
					// everything is allowed
669
					if (in_array('*', $validElements)) {
670
						if ($curMode !== '*') {
671
							// get only the mode
672
							$sectionElements = array($curMode);
673
						}
674
						else {
675
							// setting null = get all
676
							$sectionElements = null;
677
						}
678
					}
679
					// only use valid elements
680
					else {
681
						if ($curMode !== '*') {
682
							// is this field allowed ?
683
							if (self::isFieldIncluded($curMode, $validElements)) {
684
								// get only the mode
685
								$sectionElements = array($curMode);
686
							}
687
							else {
688
								// $curMode selects something outside of
689
								// the valid elements: select nothing
690
								$sectionElements = array();
691
							}
692
						}
693
						else {
694
							// use field's valid elements
695
							$sectionElements = $validElements;
696
						}
697
					}
698
					
699
					if (is_array($sectionElements) && empty($sectionElements)) {
700
						$item->setAttribute('selection-empty', 'yes');
701
						$item->setAttribute('forbidden-by', $curMode);
702
						$root->appendChild($item);
703
						continue;
704
					}
705
					
706
					// current entry again, but with data and the allowed schema
707
					$entry = $this->fetchEntry($eId, $sectionElements);
708
					
709
					// cache the entry data
710
					$entryData = $entry->getData();
711
					
712
					// for each field returned for this entry...
713
					foreach ($entryData as $fieldId => $data) {
714
						$filteredData = array_filter($data, function ($value) {
715
							return $value != null;
716
						});
717
						
718
						if (empty($filteredData)) {
719
							continue;
720
						}
721
						
722
						$field = $section->er_field_cache[$fieldId];
723
						$fieldName = $field->get('element_name');
724
						$fieldCurMode = self::extractMode($fieldName, $curMode);
725
						
726
						$parentIncludableElement = self::getSectionElementName($fieldName, $validElements);
727
						$parentIncludableElementMode = self::extractMode($fieldName, $parentIncludableElement);
728
						
729
						// Special treatments for ERF
730
						if ($field instanceof FieldEntry_relationship) {
731
							// Increment recursive level
732
							$field->recursiveLevel = $recursiveLevel + 1;
733
							$field->recursiveDeepness = $deepness;
734
						}
735
						
736
						$submodes = null;
0 ignored issues
show
Unused Code introduced by
$submodes is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
737
						if ($parentIncludableElementMode == null) {
738
							if ($fieldCurMode == null) {
739
								$submodes = null;
740
							}
741
							else {
742
								$submodes = array($fieldCurMode);
743
							}
744
						}
745
						else {
746
							if ($fieldCurMode == null || $fieldCurMode == $parentIncludableElementMode) {
747
								$submodes = array($parentIncludableElementMode);
748
							}
749
							else {
750
								$item->setAttribute('selection-mode-empty', 'yes');
751
								$submodes = array();
752
							}
753
						}
754
						
755
						// current selection does not specify a mode
756 View Code Duplication
						if ($submodes == null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
757
							$submodes = array_map(function ($fieldIncludableElement) use ($fieldName) {
758
								return FieldEntry_relationship::extractMode($fieldName, $fieldIncludableElement);
759
							}, $field->fetchIncludableElements());
760
						}
761
						
762
						foreach ($submodes as $submode) {
763
							$field->appendFormattedElement($item, $data, $encode, $submode, $eId);
764
						}
765
					}
766
					// output current mode
767
					$item->setAttribute('matched-element', $curMode);
768
					// no field selected
769
					if (is_array($sectionElements) && empty($sectionElements)) {
770
						$item->setAttribute('empty-selection', 'yes');
771
					}
772
				}
773
				// append item when done
774
				$root->appendChild($item);
775
			} // end each entries
776
			
777
			// output mode for this field
778
			$root->setAttribute('data-source-mode', $mode);
779
			$root->setAttribute('field-included-elements', $this->get('elements'));
780
			
781
			// add all our data to the wrapper;
782
			$wrapper->appendChild($root);
783
			
784
			// clean up
785
			$this->recursiveLevel = 1;
786
			$this->recursiveDeepness = null;
787
		}
788
789
		public function getParameterPoolValue(array $data, $entry_id = null)
790
		{
791
			if(!is_array($data) || empty($data)) return;
792
			return static::getEntries($data);
793
		}
794
795
		/* ********* Utils *********** */
796
		
797
		/**
798
		 * Return true if $fieldName is allowed in $sectionElements
799
		 * @param string $fieldName
800
		 * @param string $sectionElements
801
		 * @return bool
802
		 */
803
		public static function isFieldIncluded($fieldName, $sectionElements)
804
		{
805
			return self::getSectionElementName($fieldName, $sectionElements) !== null;
806
		}
807
808
		public static function getSectionElementName($fieldName, $sectionElements)
809
		{
810
			if (is_array($sectionElements)) {
811
				foreach ($sectionElements as $element) {
812
					if ($element == '*') {
813
						return $fieldName;
814
					}
815
					if ($fieldName == $element || preg_match('/^' . $fieldName . '\s*:/sU', $element)) {
816
						return $element;
817
					}
818
				}
819
			}
820
			return null;
821
		}
822
		
823
		public static function parseElements($field)
824
		{
825
			$elements = array();
826
			$exElements = array_map(trim, explode(self::SEPARATOR, $field->get('elements')));
827
			
828
			if (in_array('*', $exElements)) {
829
				$sections = array_map(trim, explode(self::SEPARATOR, $field->get('sections')));
830
				$sections = SectionManager::fetch($sections);
831
				return array_reduce($sections, function ($result, $section) {
832
					$result[$section->get('handle')] = array('*');
833
					return $result;
834
				}, array());
835
			}
836
			
837
			foreach ($exElements as $value) {
838
				if (!$value) {
839
					continue;
840
				}
841
				// sectionName.fieldName or sectionName.*
842
				$parts = array_map(trim, explode('.', $value));
843
				// first time seeing this section
844
				if (!isset($elements[$parts[0]])) {
845
					$elements[$parts[0]] = array();
846
				}
847
				// we have a value after the dot
848
				if (isset($parts[1]) && !!$parts[1]) {
849
					$elements[$parts[0]][] = $parts[1];
850
				}
851
				// sectionName only
852
				else if (!isset($parts[1])) {
853
					$elements[$parts[0]][] = '*';
854
				}
855
			}
856
			
857
			return $elements;
858
		}
859
860
		public static function extractMode($fieldName, $mode)
861
		{
862
			$pattern = '/^' . $fieldName . '\s*:\s*/s';
863
			if (!preg_match($pattern, $mode)) {
864
				return null;
865
			}
866
			$mode = preg_replace($pattern, '', $mode, 1);
867
			if ($mode === '*') {
868
				return null;
869
			}
870
			return $mode;
871
		}
872
873
		/**
874
		 * @param string $prefix
875
		 * @param string $name
876
		 * @param @optional bool $multiple
877
		 */
878
		private function createFieldName($prefix, $name, $multiple = false)
879
		{
880
			$name = "fields[$prefix][$name]";
881
			if ($multiple) {
882
				$name .= '[]';
883
			}
884
			return $name;
885
		}
886
		
887
		/**
888
		 * @param string $name
889
		 */
890
		private function createSettingsFieldName($name, $multiple = false)
891
		{
892
			return $this->createFieldName($this->get('sortorder'), $name, $multiple);
893
		}
894
		
895
		/**
896
		 * @param string $name
897
		 */
898
		private function createPublishFieldName($name, $multiple = false)
899
		{
900
			return $this->createFieldName($this->get('element_name'), $name, $multiple);
901
		}
902
		
903
		private function getSelectedSectionsArray()
904
		{
905
			$selectedSections = $this->get('sections');
906
			if (!is_array($selectedSections)) {
907
				if (is_string($selectedSections) && strlen($selectedSections) > 0) {
908
					$selectedSections = explode(self::SEPARATOR, $selectedSections);
909
				}
910
				else {
911
					$selectedSections = array();
912
				}
913
			}
914
			return $selectedSections;
915
		}
916
		
917
		private function buildSectionSelect($name)
918
		{
919
			$sections = SectionManager::fetch();
920
			$options = array();
921
			$selectedSections = $this->getSelectedSectionsArray();
922
			
923
			foreach ($sections as $section) {
924
				$driver = $section->get('id');
925
				$selected = in_array($driver, $selectedSections);
926
				$options[] = array($driver, $selected, $section->get('name'));
927
			}
928
			
929
			return Widget::Select($name, $options, array('multiple' => 'multiple'));
930
		} 
931
		
932
		private function appendSelectionSelect(&$wrapper)
933
		{
934
			$name = $this->createSettingsFieldName('sections', true);
935
936
			$input = $this->buildSectionSelect($name);
937
			$input->setAttribute('class', 'entry_relationship-sections');
938
939
			$label = Widget::Label();
940
			$label->setAttribute('class', 'column');
941
942
			$label->setValue(__('Available sections %s', array($input->generate())));
943
944
			$wrapper->appendChild($label);
945
		}
946
947
		private function createEntriesList($entries)
948
		{
949
			$wrap = new XMLElement('div');
950
			$wrapperClass = 'frame collapsible orderable';
951
			if (count($entries) == 0) {
952
				$wrapperClass .= ' empty';
953
			}
954
			if (!$this->is('show_header')) {
955
				$wrapperClass .= ' no-header';
956
			}
957
			$wrap->setAttribute('class', $wrapperClass);
958
			
959
			$list = new XMLElement('ul');
960
			$list->setAttribute('class', '');
961
			if ($this->is('allow_collapse')) {
962
				$list->setAttribute('data-collapsible', '');
963
			}
964
			
965
			$wrap->appendChild($list);
966
			
967
			return $wrap;
968
		}
969
		
970
		private function createEntriesHiddenInput($data)
971
		{
972
			$hidden = new XMLElement('input', null, array(
973
				'type' => 'hidden',
974
				'name' => $this->createPublishFieldName('entries'),
975
				'value' => $data['entries']
976
			));
977
			
978
			return $hidden;
979
		}
980
		
981
		private function createActionBarMenu($sections)
982
		{
983
			$wrap = new XMLElement('div');
984
			$actionBar = '';
985
			$modeFooter = $this->get('mode_footer');
986
			if ($modeFooter) {
987
				$section = $this->sectionManager->fetch($this->get('parent_section'));
988
				$actionBar = ERFXSLTUTilities::processXSLT($this, null, $section->get('handle'), null, 'mode_footer', isset($_REQUEST['debug']), 'field');
989
			}
990
			if (empty($actionBar)) {
991
				$fieldset = new XMLElement('fieldset');
992
				$fieldset->setAttribute('class', 'single');
993
				if ($this->is('allow_new') || $this->is('allow_link')) {
994
					$selectWrap = new XMLElement('div');
995
					$selectWrap->appendChild(new XMLElement('span', __('Related section: ')));
996
					$options = array();
997
					foreach ($sections as $section) {
998
						$options[] = array($section->get('handle'), false, $section->get('name'));
999
					}
1000
					$select = Widget::Select('', $options, array('class' => 'sections'));
1001
					$selectWrap->appendChild($select);
1002
					$fieldset->appendChild($selectWrap);
1003
				}
1004 View Code Duplication
				if ($this->is('allow_new')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1005
					$fieldset->appendChild(new XMLElement('button', __('Create new'), array(
1006
						'type' => 'button',
1007
						'class' => 'create',
1008
						'data-create' => '',
1009
					)));
1010
				}
1011 View Code Duplication
				if ($this->is('allow_link')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1012
					$fieldset->appendChild(new XMLElement('button', __('Link to entry'), array(
1013
						'type' => 'button',
1014
						'class' => 'link',
1015
						'data-link' => '',
1016
					)));
1017
				}
1018
				$wrap->appendChild($fieldset);
1019
			}
1020
			else {
1021
				$wrap->setValue($actionBar);
1022
			}
1023
			
1024
			return $wrap;
1025
		}
1026
1027
		/* ********* UI *********** */
1028
		
1029
		/**
1030
		 *
1031
		 * Builds the UI for the field's settings when creating/editing a section
1032
		 * @param XMLElement $wrapper
1033
		 * @param array $errors
1034
		 */
1035
		public function displaySettingsPanel(XMLElement &$wrapper, $errors=null)
1036
		{
1037
			/* first line, label and such */
1038
			parent::displaySettingsPanel($wrapper, $errors);
1039
			
1040
			// sections
1041
			$sections = new XMLElement('fieldset');
1042
			
1043
			$this->appendSelectionSelect($sections);
1044
			if (is_array($errors) && isset($errors['sections'])) {
1045
				$sections = Widget::Error($sections, $errors['sections']);
1046
			}
1047
			$wrapper->appendChild($sections);
1048
			
1049
			// elements
1050
			$elements = new XMLElement('div');
1051
			$element = Widget::Label();
1052
			$element->setValue(__('Included elements in Data Sources and Backend Templates'));
1053
			$element->setAttribute('class', 'column');
1054
			$element->appendChild(Widget::Input($this->createSettingsFieldName('elements'), $this->get('elements'), 'text', array(
1055
				'class' => 'entry_relationship-elements'
1056
			)));
1057
			$elements->appendChild($element);
1058
			$elements_choices = new XMLElement('ul', null, array('class' => 'tags singular entry_relationship-field-choices'));
1059
			
1060
			$elements->appendChild($elements_choices);
1061
			$wrapper->appendChild($elements);
1062
			
1063
			// limit entries
1064
			$limits = new XMLElement('fieldset');
1065
			$limits->appendChild(new XMLElement('legend', __('Limits')));
1066
			$limits_cols = new XMLElement('div');
1067
			$limits_cols->setAttribute('class', 'three columns');
1068
			// min
1069
			$limit_min = Widget::Label();
1070
			$limit_min->setValue(__('Minimum count of entries in this field'));
1071
			$limit_min->setAttribute('class', 'column');
1072
			$limit_min->appendChild(Widget::Input($this->createSettingsFieldName('min_entries'), $this->get('min_entries'), 'number', array(
1073
				'min' => 0,
1074
				'max' => 99999
1075
			)));
1076
			$limits_cols->appendChild($limit_min);
1077
			// max
1078
			$limit_max = Widget::Label();
1079
			$limit_max->setValue(__('Maximum count of entries in this field'));
1080
			$limit_max->setAttribute('class', 'column');
1081
			$limit_max->appendChild(Widget::Input($this->createSettingsFieldName('max_entries'), $this->get('max_entries'), 'number', array(
1082
				'min' => 0,
1083
				'max' => 99999
1084
			)));
1085
			$limits_cols->appendChild($limit_max);
1086
			
1087
			// deepness
1088
			$deepness = Widget::Label();
1089
			$deepness->setValue(__('Maximum level of recursion in Data Sources'));
1090
			$deepness->setAttribute('class', 'column');
1091
			$deepness->appendChild(Widget::Input($this->createSettingsFieldName('deepness'), $this->get('deepness'), 'number', array(
1092
				'min' => 0,
1093
				'max' => 99
1094
			)));
1095
			$limits_cols->appendChild($deepness);
1096
			$limits->appendChild($limits_cols);
1097
			$wrapper->appendChild($limits);
1098
			
1099
			// xsl
1100
			$xsl = new XMLElement('fieldset');
1101
			$xsl->appendChild(new XMLElement('legend', __('Backend XSL templates options')));
1102
			$xsl_cols = new XMLElement('div');
1103
			$xsl_cols->setAttribute('class', 'four columns');
1104
			
1105
			// xsl mode
1106
			$xslmode = Widget::Label();
1107
			$xslmode->setValue(__('XSL mode for entries content template'));
1108
			$xslmode->setAttribute('class', 'column');
1109
			$xslmode->appendChild(Widget::Input($this->createSettingsFieldName('mode'), $this->get('mode'), 'text'));
1110
			$xsl_cols->appendChild($xslmode);
1111
			// xsl header mode
1112
			$xslmodetable = Widget::Label();
1113
			$xslmodetable->setValue(__('XSL mode for entries header template'));
1114
			$xslmodetable->setAttribute('class', 'column');
1115
			$xslmodetable->appendChild(Widget::Input($this->createSettingsFieldName('mode_header'), $this->get('mode_header'), 'text'));
1116
			$xsl_cols->appendChild($xslmodetable);
1117
			// xsl table mode
1118
			$xslmodetable = Widget::Label();
1119
			$xslmodetable->setValue(__('XSL mode for publish table value'));
1120
			$xslmodetable->setAttribute('class', 'column');
1121
			$xslmodetable->appendChild(Widget::Input($this->createSettingsFieldName('mode_table'), $this->get('mode_table'), 'text'));
1122
			$xsl_cols->appendChild($xslmodetable);
1123
			// xsl action bar mode
1124
			$xslmodetable = Widget::Label();
1125
			$xslmodetable->setValue(__('XSL mode for publish action bar'));
1126
			$xslmodetable->setAttribute('class', 'column');
1127
			$xslmodetable->appendChild(Widget::Input($this->createSettingsFieldName('mode_footer'), $this->get('mode_footer'), 'text'));
1128
			$xsl_cols->appendChild($xslmodetable);
1129
			
1130
			$xsl->appendChild($xsl_cols);
1131
			$wrapper->appendChild($xsl);
1132
			
1133
			// permissions
1134
			$permissions = new XMLElement('fieldset');
1135
			$permissions->appendChild(new XMLElement('legend', __('Permissions')));
1136
			$permissions_cols = new XMLElement('div');
1137
			$permissions_cols->setAttribute('class', 'four columns');
1138
			$permissions_cols->appendChild($this->createCheckbox('allow_new', 'Show new button'));
1139
			$permissions_cols->appendChild($this->createCheckbox('allow_edit', 'Show edit button'));
1140
			$permissions_cols->appendChild($this->createCheckbox('allow_link', 'Show link button'));
1141
			$permissions_cols->appendChild($this->createCheckbox('allow_delete', 'Show delete button'));
1142
			$permissions->appendChild($permissions_cols);
1143
			$wrapper->appendChild($permissions);
1144
			
1145
			// display options
1146
			$display = new XMLElement('fieldset');
1147
			$display->appendChild(new XMLElement('legend', __('Display options')));
1148
			$display_cols = new XMLElement('div');
1149
			$display_cols->setAttribute('class', 'four columns');
1150
			$display_cols->appendChild($this->createCheckbox('allow_collapse', 'Allow content collapsing'));
1151
			$display_cols->appendChild($this->createCheckbox('show_header', 'Show the header box before entries templates'));
1152
			$display->appendChild($display_cols);
1153
			$wrapper->appendChild($display);
1154
			
1155
			// assoc
1156
			$assoc = new XMLElement('fieldset');
1157
			$assoc->appendChild(new XMLElement('legend', __('Associations')));
1158
			$assoc_cols = new XMLElement('div');
1159
			$assoc_cols->setAttribute('class', 'three columns');
1160
			$this->appendShowAssociationCheckbox($assoc_cols);
1161
			$assoc->appendChild($assoc_cols);
1162
			$wrapper->appendChild($assoc);
1163
			
1164
			// footer
1165
			$this->appendStatusFooter($wrapper);
1166
		}
1167
		
1168
		/**
1169
		 * @param string $fieldName
1170
		 * @param string $text
1171
		 */
1172
		private function createCheckbox($fieldName, $text) {
1173
			$chk = Widget::Label();
1174
			$chk->setAttribute('class', 'column');
1175
			$attrs = null;
1176
			if ($this->get($fieldName) == 'yes') {
1177
				$attrs = array('checked' => 'checked');
1178
			}
1179
			$chk->appendChild(Widget::Input($this->createSettingsFieldName($fieldName), 'yes', 'checkbox', $attrs));
1180
			$chk->setValue(__($text));
1181
			return $chk;
1182
		}
1183
1184
		/**
1185
		 *
1186
		 * Builds the UI for the publish page
1187
		 * @param XMLElement $wrapper
1188
		 * @param mixed $data
1189
		 * @param mixed $flagWithError
1190
		 * @param string $fieldnamePrefix
1191
		 * @param string $fieldnamePostfix
1192
		 */
1193
		public function displayPublishPanel(XMLElement &$wrapper, $data = null, $flagWithError = null, $fieldnamePrefix = null, $fieldnamePostfix = null, $entry_id = null)
1194
		{
1195
			$entriesId = array();
1196
			$sectionsId = $this->getSelectedSectionsArray();
1197
			
1198
			if ($data['entries'] != null) {
1199
				$entriesId = static::getEntries($data);
1200
			}
1201
			
1202
			$sectionsId = array_map(array('General', 'intval'), $sectionsId);
1203
			$sections = SectionManager::fetch($sectionsId);
1204
			
1205
			$label = Widget::Label($this->get('label'));
1206
			$notes = '';
1207
			
1208
			// min note
1209
			if ($this->getInt('min_entries') > 0) {
1210
				$notes .= __('Minimum number of entries: <b>%s</b>. ', array($this->get('min_entries')));
1211
			}
1212
			// max note
1213
			if ($this->getInt('max_entries') > 0) {
1214
				$notes .= __('Maximum number of entries: <b>%s</b>. ', array($this->get('max_entries')));
1215
			}
1216
			// not required note
1217
			if (!$this->isRequired()) {
1218
				$notes .= __('Optional');
1219
			}
1220
			// append notes
1221
			if ($notes) {
1222
				$label->appendChild(new XMLElement('i', $notes));
1223
			}
1224
			
1225
			// label error management
1226
			if ($flagWithError != null) {
1227
				$wrapper->appendChild(Widget::Error($label, $flagWithError));
1228
			} else {
1229
				$wrapper->appendChild($label);
1230
			}
1231
			
1232
			$wrapper->appendChild($this->createEntriesList($entriesId));
1233
			$wrapper->appendChild($this->createActionBarMenu($sections));
1234
			$wrapper->appendChild($this->createEntriesHiddenInput($data));
1235
			$wrapper->setAttribute('data-value', $data['entries']);
1236
			$wrapper->setAttribute('data-field-id', $this->get('id'));
1237
			$wrapper->setAttribute('data-field-label', $this->get('label'));
1238
			$wrapper->setAttribute('data-min', $this->get('min_entries'));
1239
			$wrapper->setAttribute('data-max', $this->get('max_entries'));
1240
			$wrapper->setAttribute('data-required', $this->get('required'));
1241
			if (isset($_REQUEST['debug'])) {
1242
				$wrapper->setAttribute('data-debug', true);
1243
			}
1244
		}
1245
1246
		/**
1247
		 * @param integer $count
1248
		 */
1249
		private static function formatCount($count)
1250
		{
1251
			if ($count == 0) {
1252
				return __('No item');
1253
			} else if ($count == 1) {
1254
				return __('1 item');
1255
			}
1256
			return __('%s items', array($count));
1257
		}
1258
1259
		/**
1260
		 *
1261
		 * Return a plain text representation of the field's data
1262
		 * @param array $data
1263
		 * @param int $entry_id
1264
		 */
1265
		public function prepareTextValue($data, $entry_id = null)
1266
		{
1267
			if ($entry_id == null || !is_array($data) || empty($data)) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $entry_id of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
1268
				return '';
1269
			}
1270
			return $data['entries'];
1271
		}
1272
1273
		/**
1274
		 * Format this field value for display as readable text value.
1275
		 *
1276
		 * @param array $data
1277
		 *  an associative array of data for this string. At minimum this requires a
1278
		 *  key of 'value'.
1279
		 * @param integer $entry_id (optional)
1280
		 *  An option entry ID for more intelligent processing. Defaults to null.
1281
		 * @param string $defaultValue (optional)
1282
		 *  The value to use when no plain text representation of the field's data
1283
		 *  can be made. Defaults to null.
1284
		 * @return string
1285
		 *  the readable text summary of the values of this field instance.
1286
		 */
1287
		public function prepareReadableValue($data, $entry_id = null, $truncate = false, $defaultValue = 'None')
1288
		{
1289
			if ($entry_id == null || !is_array($data) || empty($data)) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $entry_id of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
1290
				return __($defaultValue);
1291
			}
1292
			$entries = static::getEntries($data);
1293
			$realEntries = array();
1294
			foreach ($entries as $entryId) {
1295
				$e = EntryManager::fetch($entryId);
1296
				if (is_array($e) && !empty($e)) {
1297
					$realEntries = array_merge($realEntries, $e);
1298
				}
1299
			}
1300
			$count = count($entries);
1301
			$realCount = count($realEntries);
1302
			if ($count === $realCount) {
1303
				return self::formatCount($count);
1304
			}
1305
			return self::formatCount($realCount) . ' (' . self::formatCount($count - $realCount) . ' not found)';
1306
		}
1307
1308
		/**
1309
		 * Format this field value for display in the publish index tables.
1310
		 *
1311
		 * @param array $data
1312
		 *  an associative array of data for this string. At minimum this requires a
1313
		 *  key of 'value'.
1314
		 * @param XMLElement $link (optional)
1315
		 *  an XML link structure to append the content of this to provided it is not
1316
		 *  null. it defaults to null.
1317
		 * @param integer $entry_id (optional)
1318
		 *  An option entry ID for more intelligent processing. defaults to null
1319
		 * @return string
1320
		 *  the formatted string summary of the values of this field instance.
1321
		 */
1322
		public function prepareTableValue($data, XMLElement $link = null, $entry_id = null)
1323
		{
1324
			$value = $this->prepareReadableValue($data, $entry_id, false, __('None'));
1325
1326
			if ($link) {
1327
				$link->setValue($value);
1328
				return $link->generate();
1329
			}
1330
			else if ($entry_id != null && $this->get('mode_table')) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $entry_id of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison !== instead.
Loading history...
1331
				$entries = static::getEntries($data);
1332
				$cellcontent = '';
1333
				foreach ($entries as $child_entry_id) {
1334
					$entry = current($this->entryManager->fetch($child_entry_id));
1335
					$section = $this->sectionManager->fetch($entry->get('section_id'));
1336
					$content = ERFXSLTUTilities::processXSLT($this, $entry, $section->get('handle'), $section->fetchFields(), 'mode_table', isset($_REQUEST['debug']));
1337
					if ($content) {
1338
						$cellcontent .= $content;
1339
					}
1340
				}
1341
				
1342
				if (General::strlen(trim($cellcontent))) {
1343
					return $cellcontent;
1344
				}
1345
			}
1346
1347
			return $value;
1348
		}
1349
1350
		/* ********* SQL Data Definition ************* */
1351
1352
		/**
1353
		 *
1354
		 * Creates table needed for entries of individual fields
1355
		 */
1356
		public function createTable()
1357
		{
1358
			$id = $this->get('id');
1359
1360
			return Symphony::Database()->query("
1361
				CREATE TABLE `tbl_entries_data_$id` (
1362
					`id` int(11) 		unsigned NOT NULL AUTO_INCREMENT,
1363
					`entry_id` 			int(11) unsigned NOT NULL,
1364
					`entries` 			text COLLATE utf8_unicode_ci NULL,
1365
					PRIMARY KEY  (`id`),
1366
					UNIQUE KEY `entry_id` (`entry_id`)
1367
				) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
1368
			");
1369
		}
1370
1371
		/**
1372
		 * Creates the table needed for the settings of the field
1373
		 */
1374
		public static function createFieldTable()
1375
		{
1376
			$tbl = self::FIELD_TBL_NAME;
1377
1378
			return Symphony::Database()->query("
1379
				CREATE TABLE IF NOT EXISTS `$tbl` (
1380
					`id` 				int(11) unsigned NOT NULL AUTO_INCREMENT,
1381
					`field_id` 			int(11) unsigned NOT NULL,
1382
					`sections`			varchar(255) NULL COLLATE utf8_unicode_ci,
1383
					`show_association` 	enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1384
					`deepness` 			int(2) unsigned NULL,
1385
					`elements` 			varchar(1024) NULL COLLATE utf8_unicode_ci,
1386
					`mode`				varchar(50) NULL COLLATE utf8_unicode_ci,
1387
					`mode_table`		varchar(50) NULL COLLATE utf8_unicode_ci DEFAULT NULL,
1388
					`mode_header`		varchar(50) NULL COLLATE utf8_unicode_ci DEFAULT NULL,
1389
					`mode_footer`		varchar(50) NULL COLLATE utf8_unicode_ci DEFAULT NULL,
1390
					`min_entries`		int(5) unsigned NULL,
1391
					`max_entries`		int(5) unsigned NULL,
1392
					`allow_edit` 		enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1393
					`allow_new` 		enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1394
					`allow_link` 		enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1395
					`allow_delete` 		enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'no',
1396
					`allow_collapse` 	enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1397
					`show_header` 		enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1398
					PRIMARY KEY (`id`),
1399
					UNIQUE KEY `field_id` (`field_id`)
1400
				) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
1401
			");
1402
		}
1403
		
1404
		public static function update_102()
1405
		{
1406
			$tbl = self::FIELD_TBL_NAME;
1407
			$sql = "
1408
				ALTER TABLE `$tbl`
1409
					ADD COLUMN `allow_edit` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1410
					ADD COLUMN `allow_new` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1411
					ADD COLUMN `allow_link` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes'
1412
					AFTER `max_entries`
1413
			";
1414
			$addColumns = Symphony::Database()->query($sql);
1415
			if (!$addColumns) {
1416
				return false;
1417
			}
1418
1419
			$fields = FieldManager::fetch(null, null, null, 'id', 'entry_relationship');
1420
			if (!empty($fields) && is_array($fields)) {
1421
				foreach ($fields as $fieldId => $field) {
1422
					$sql = "ALTER TABLE `tbl_entries_data_$fieldId` MODIFY `entries` TEXT";
1423
					if (!Symphony::Database()->query($sql)) {
1424
						throw new Exception(__('Could not update table `tbl_entries_data_%s`.', array($fieldId)));
1425
					}
1426
				}
1427
			}
1428
			return true;
1429
		}
1430
		
1431
		public static function update_103()
1432
		{
1433
			$tbl = self::FIELD_TBL_NAME;
1434
			$sql = "
1435
				ALTER TABLE `$tbl`
1436
					ADD COLUMN `allow_delete` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'no'
1437
						AFTER `allow_link`
1438
			";
1439
			return Symphony::Database()->query($sql);
1440
		}
1441
		
1442
		public static function update_200()
1443
		{
1444
			$tbl = self::FIELD_TBL_NAME;
1445
			$sql = "
1446
				ALTER TABLE `$tbl`
1447
					ADD COLUMN `allow_collapse` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes'
1448
						AFTER `allow_delete`,
1449
					ADD COLUMN `mode_table` varchar(50) NULL COLLATE utf8_unicode_ci DEFAULT NULL
1450
						AFTER `mode`,
1451
					ADD COLUMN `mode_header` varchar(50) NULL COLLATE utf8_unicode_ci DEFAULT NULL
1452
						AFTER `mode_table`,
1453
					ADD COLUMN `show_header` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes'
1454
						AFTER `allow_collapse`,
1455
					ADD COLUMN `mode_footer` varchar(50) NULL COLLATE utf8_unicode_ci DEFAULT NULL
1456
						AFTER `mode_header`
1457
			";
1458
			return Symphony::Database()->query($sql);
1459
		}
1460
		
1461
		/**
1462
		 *
1463
		 * Drops the table needed for the settings of the field
1464
		 */
1465
		public static function deleteFieldTable()
1466
		{
1467
			$tbl = self::FIELD_TBL_NAME;
1468
			
1469
			return Symphony::Database()->query("
1470
				DROP TABLE IF EXISTS `$tbl`
1471
			");
1472
		}
1473
		
1474
		private static function removeSectionAssociation($child_field_id)
1475
		{
1476
			return Symphony::Database()->delete('tbl_sections_association', "`child_section_field_id` = {$child_field_id}");
1477
		}
1478
	}