Completed
Push — dev ( b0a1ff...137b1d )
by Nicolas
01:53
created

FieldEntry_relationship::createEntriesList()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 22
rs 8.9197
cc 4
eloc 14
nc 8
nop 1
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
		
44
		/**
45
		 *
46
		 * Parent's maximum recursive level of output
47
		 *  @var int
48
		 */
49
		protected $recursiveDeepness = null;
50
		
51
		/* Cacheable Managers */
52
		private $sectionManager;
53
		private $entryManager;
54
		
55
		/**
56
		 *
57
		 * Constructor for the oEmbed Field object
58
		 */
59
		public function __construct()
60
		{
61
			// call the parent constructor
62
			parent::__construct();
63
			// set the name of the field
64
			$this->_name = __('Entry Relationship');
65
			// permits to make it required
66
			$this->_required = true;
67
			// permits the make it show in the table columns
68
			$this->_showcolumn = true;
69
			// permits association
70
			$this->_showassociation = true;
71
			// current recursive level
72
			$this->recursiveLevel = 1;
73
			// parent's maximum recursive level of output
74
			$this->recursiveDeepness = null;
75
			// set as not required by default
76
			$this->set('required', 'no');
77
			// show association by default
78
			$this->set('show_association', 'yes');
79
			// no sections
80
			$this->set('sections', null);
81
			// no max deepness
82
			$this->set('deepness', null);
83
			// no included elements
84
			$this->set('elements', null);
85
			// no modes
86
			$this->set('mode', null);
87
			$this->set('mode_table', null);
88
			$this->set('mode_header', null);
89
			// no limit
90
			$this->set('min_entries', null);
91
			$this->set('max_entries', null);
92
			// all permissions
93
			$this->set('allow_new', 'yes');
94
			$this->set('allow_edit', 'yes');
95
			$this->set('allow_link', 'yes');
96
			$this->set('allow_delete', 'no');
97
			// display options
98
			$this->set('allow_collapse', 'yes');
99
			$this->set('show_header', 'yes');
100
			$this->sectionManager = new CacheableFetch('SectionManager');
101
			$this->entryManager = new CacheableFetch('EntryManager');
102
		}
103
104
		public function isSortable()
105
		{
106
			return false;
107
		}
108
109
		public function canFilter()
110
		{
111
			return true;
112
		}
113
		
114
		public function canPublishFilter()
115
		{
116
			return false;
117
		}
118
119
		public function canImport()
120
		{
121
			return false;
122
		}
123
124
		public function canPrePopulate()
125
		{
126
			return false;
127
		}
128
		
129
		public function mustBeUnique()
130
		{
131
			return false;
132
		}
133
134
		public function allowDatasourceOutputGrouping()
135
		{
136
			return false;
137
		}
138
139
		public function requiresSQLGrouping()
140
		{
141
			return false;
142
		}
143
144
		public function allowDatasourceParamOutput()
145
		{
146
			return true;
147
		}
148
149
		/**
150
		 * @param string $name
151
		 */
152
		public function getInt($name)
153
		{
154
			return General::intval($this->get($name));
155
		}
156
157
		/**
158
		 * Check if a given property is == 'yes'
159
		 * @param string $name
160
		 * @return bool
161
		 *  True if the current field's value is 'yes'
162
		 */
163
		public function is($name)
164
		{
165
			return $this->get($name) == 'yes';
166
		}
167
168
		/**
169
		 * @return bool
170
		 *  True if the current field is required
171
		 */
172
		public function isRequired()
173
		{
174
			return $this->is('required');
175
		}
176
177
		public static function getEntries(array $data)
178
		{
179
			return array_map(array('General', 'intval'), array_filter(array_map(trim, explode(self::SEPARATOR, $data['entries']))));
180
		}
181
182
		/* ********** INPUT AND FIELD *********** */
183
184
185
		/**
186
		 * 
187
		 * Validates input
188
		 * Called before <code>processRawFieldData</code>
189
		 * @param $data
190
		 * @param $message
191
		 * @param $entry_id
192
		 */
193
		public function checkPostFieldData($data, &$message, $entry_id=NULL)
194
		{
195
			$message = NULL;
196
			$required = $this->isRequired();
197
			
198
			if ($required && (!is_array($data) || count($data) == 0 || strlen($data['entries']) < 1)) {
199
				$message = __("'%s' is a required field.", array($this->get('label')));
200
				return self::__MISSING_FIELDS__;
201
			}
202
			
203
			$entries = $data['entries'];
204
			
205
			if (!is_array($entries)) {
206
				$entries = static::getEntries($data);
207
			}
208
			
209
			// enforce limits only if required or it contains data
210
			if ($required || count($entries) > 0) {
211
				if ($this->getInt('min_entries') > 0 && $this->getInt('min_entries') > count($entries)) {
212
					$message = __("'%s' requires a minimum of %s entries.", array($this->get('label'), $this->getInt('min_entries')));
213
					return self::__INVALID_FIELDS__;
214
				} else if ($this->getInt('max_entries') > 0 && $this->getInt('max_entries') < count($entries)) {
215
					$message = __("'%s' can not contains more than %s entries.", array($this->get('label'), $this->getInt('max_entries')));
216
					return self::__INVALID_FIELDS__;
217
				}
218
			}
219
			
220
			return self::__OK__;
221
		}
222
223
224
		/**
225
		 *
226
		 * Process data before saving into database.
227
		 *
228
		 * @param array $data
229
		 * @param int $status
230
		 * @param boolean $simulate
231
		 * @param int $entry_id
232
		 *
233
		 * @return Array - data to be inserted into DB
234
		 */
235
		public function processRawFieldData($data, &$status, &$message = null, $simulate = false, $entry_id = null)
236
		{
237
			$status = self::__OK__;
238
			$entries = null;
239
			
240
			if (!is_array($data) && !is_string($data)) {
241
				return null;
242
			}
243
			
244
			if (isset($data['entries'])) {
245
				$entries = $data['entries'];
246
			}
247
			else if (is_string($data)) {
248
				$entries = $data;
249
			}
250
			
251
			$row = array(
252
				'entries' => $entries
253
			);
254
			
255
			// return row
256
			return $row;
257
		}
258
259
		/**
260
		 * This function permits parsing different field settings values
261
		 *
262
		 * @param array $settings
263
		 *	the data array to initialize if necessary.
264
		 */
265
		public function setFromPOST(Array &$settings = array())
266
		{
267
			// call the default behavior
268
			parent::setFromPOST($settings);
269
270
			// declare a new setting array
271
			$new_settings = array();
272
273
			// set new settings
274
			$new_settings['sections'] = is_array($settings['sections']) ? 
275
				implode(self::SEPARATOR, $settings['sections']) : 
276
				(is_string($settings['sections']) ? $settings['sections'] : null);
277
				
278
			$new_settings['show_association'] = $settings['show_association'] == 'yes' ? 'yes' : 'no';
279
			$new_settings['deepness'] = General::intval($settings['deepness']);
280
			$new_settings['deepness'] = $new_settings['deepness'] < 1 ? null : $new_settings['deepness'];
281
			$new_settings['elements'] = empty($settings['elements']) ? null : $settings['elements'];
282
			$new_settings['mode'] = empty($settings['mode']) ? null : $settings['mode'];
283
			$new_settings['mode_table'] = empty($settings['mode_table']) ? null : $settings['mode_table'];
284
			$new_settings['mode_header'] = empty($settings['mode_header']) ? null : $settings['mode_header'];
285
			$new_settings['allow_new'] = $settings['allow_new'] == 'yes' ? 'yes' : 'no';
286
			$new_settings['allow_edit'] = $settings['allow_edit'] == 'yes' ? 'yes' : 'no';
287
			$new_settings['allow_link'] = $settings['allow_link'] == 'yes' ? 'yes' : 'no';
288
			$new_settings['allow_delete'] = $settings['allow_delete'] == 'yes' ? 'yes' : 'no';
289
			$new_settings['allow_collapse'] = $settings['allow_collapse'] == 'yes' ? 'yes' : 'no';
290
			$new_settings['show_header'] = $settings['show_header'] == 'yes' ? 'yes' : 'no';
291
			
292
			// save it into the array
293
			$this->setArray($new_settings);
294
		}
295
296
297
		/**
298
		 *
299
		 * Validates the field settings before saving it into the field's table
300
		 */
301
		public function checkFields(Array &$errors, $checkForDuplicates)
302
		{
303
			$parent = parent::checkFields($errors, $checkForDuplicates);
304
			if ($parent != self::__OK__) {
305
				return $parent;
306
			}
307
			
308
			$sections = $this->get('sections');
309
			
310
			if (empty($sections)) {
311
				$errors['sections'] = __('At least one section must be chosen');
312
			}
313
314
			return (!empty($errors) ? self::__ERROR__ : self::__OK__);
315
		}
316
317
		/**
318
		 *
319
		 * Save field settings into the field's table
320
		 */
321
		public function commit()
322
		{
323
			// if the default implementation works...
324
			if(!parent::commit()) return false;
325
			
326
			$id = $this->get('id');
327
			
328
			// exit if there is no id
329
			if($id == false) return false;
330
			
331
			// we are the child, with multiple parents
332
			$child_field_id = $id;
333
			
334
			// delete associations, only where we are the child
335
			self::removeSectionAssociation($child_field_id);
336
			
337
			$sections = $this->getSelectedSectionsArray();
338
			
339
			foreach ($sections as $key => $sectionId) {
340
				if (empty($sectionId)) {
341
					continue;
342
				}
343
				$parent_section_id = General::intval($sectionId);
344
				$parent_section = SectionManager::fetch($sectionId);
345
				$fields = $parent_section->fetchVisibleColumns();
346
				if (empty($fields)) {
347
					// no visible field, revert to all
348
					$fields = $parent_section->fetchFields();
349
				}
350
				$parent_field_id = current(array_keys($fields));
351
				// create association
352
				SectionManager::createSectionAssociation(
353
					$parent_section_id,
354
					$child_field_id,
355
					$parent_field_id,
356
					$this->get('show_association') == 'yes'
357
				);
358
			}
359
			
360
			// declare an array contains the field's settings
361
			$settings = array(
362
				'sections' => $this->get('sections'),
363
				'show_association' => $this->get('show_association'),
364
				'deepness' => $this->get('deepness'),
365
				'elements' => $this->get('elements'),
366
				'mode' => $this->get('mode'),
367
				'mode_table' => $this->get('mode_table'),
368
				'mode_header' => $this->get('mode_header'),
369
				'min_entries' => $this->get('min_entries'),
370
				'max_entries' => $this->get('max_entries'),
371
				'allow_new' => $this->get('allow_new'),
372
				'allow_edit' => $this->get('allow_edit'),
373
				'allow_link' => $this->get('allow_link'),
374
				'allow_delete' => $this->get('allow_delete'),
375
				'allow_collapse' => $this->get('allow_collapse'),
376
				'show_header' => $this->get('show_header'),
377
			);
378
379
			return FieldManager::saveSettings($id, $settings);
380
		}
381
382
		/**
383
		 *
384
		 * This function allows Fields to cleanup any additional things before it is removed
385
		 * from the section.
386
		 * @return boolean
387
		 */
388
		public function tearDown()
389
		{
390
			self::removeSectionAssociation($this->get('id'));
391
			return parent::tearDown();
392
		}
393
		
394
		/**
395
		 * Generates the where filter for searching by entry id
396
		 *
397
		 * @param string $value
398
		 * @param @optional string $col
399
		 * @param @optional boolean $andOperation
400
		 */
401
		public function generateWhereFilter($value, $col = 'd', $andOperation = true)
402
		{
403
			$junction = $andOperation ? 'AND' : 'OR';
404
			if (!$value) {
405
				return "{$junction} (`{$col}`.`entries` IS NULL)";
406
			}
407
			return " {$junction} (`{$col}`.`entries` = '{$value}' OR 
408
					`{$col}`.`entries` LIKE '{$value},%' OR 
409
					`{$col}`.`entries` LIKE '%,{$value}' OR 
410
					`{$col}`.`entries` LIKE '%,{$value},%')";
411
		}
412
413
		/**
414
		 * Fetch the number of associated entries for a particular entry id
415
		 *
416
		 * @param string $value
417
		 */
418
		public function fetchAssociatedEntryCount($value)
419
		{
420
			if (!$value) {
421
				return 0;
422
			}
423
			$join = sprintf(" INNER JOIN `tbl_entries_data_%s` AS `d` ON `e`.id = `d`.`entry_id`", $this->get('id'));
424
			$where = $this->generateWhereFilter($value);
425
			
426
			$entries = EntryManager::fetch(null, $this->get('parent_section'), null, 0, $where, $join, false, false, array());
427
			
428
			return count($entries);
429
		}
430
		
431
		public function fetchAssociatedEntrySearchValue($data, $field_id = null, $parent_entry_id = null)
432
		{
433
			return $parent_entry_id;
434
		}
435
		
436
		public function findRelatedEntries($entry_id)
437
		{
438
			$joins = '';
439
			$where = '';
440
			$this->buildDSRetrievalSQL(array($entry_id), $joins, $where, true);
441
			
442
			$entries = EntryManager::fetch(null, $this->get('parent_section'), null, 0, $where, $joins, false, false, array());
443
			
444
			$ids = array();
445
			foreach ($entries as $key => $e) {
446
				$ids[] = $e['id'];
447
			}
448
			return $ids;
449
		}
450
		
451
		public function prepareAssociationsDrawerXMLElement(Entry $e, array $parent_association, $prepolutate = '')
452
		{
453
			$currentSection = SectionManager::fetch($parent_association['child_section_id']);
454
			$visibleCols = $currentSection->fetchVisibleColumns();
455
			$outputFieldId = current(array_keys($visibleCols));
456
			$outputField = FieldManager::fetch($outputFieldId);
457
			
458
			$value = $outputField->prepareReadableValue($e->getData($outputFieldId), $e->get('id'), true, __('None'));
459
			
460
			$li = new XMLElement('li');
461
			$li->setAttribute('class', 'field-' . $this->get('type'));
462
			$a = new XMLElement('a', strip_tags($value));
463
			$a->setAttribute('href', SYMPHONY_URL . '/publish/' . $parent_association['handle'] . '/edit/' . $e->get('id') . '/');
464
			$li->appendChild($a);
465
466
			return $li;
467
		}
468
		
469
		/**
470
		 * @param string $joins
471
		 * @param string $where
472
		 */
473
		public function buildDSRetrievalSQL($data, &$joins, &$where, $andOperation = false)
474
		{
475
			$field_id = $this->get('id');
476
			
477
			// REGEX filtering is a special case, and will only work on the first item
478
			// in the array. You cannot specify multiple filters when REGEX is involved.
479
			if (self::isFilterRegex($data[0])) {
480
				return $this->buildRegexSQL($data[0], array('entries'), $joins, $where);
481
			}
482
			
483
			$this->_key++;
484
			
485
			$where .= ' AND (1=' . ($andOperation ? '1' : '0') . ' ';
486
			
487
			$joins .= "
488
				INNER JOIN
489
					`tbl_entries_data_{$field_id}` AS `t{$field_id}_{$this->_key}`
490
					ON (`e`.`id` = `t{$field_id}_{$this->_key}`.`entry_id`)
491
			";
492
			
493
			foreach ($data as $value) {
494
				$where .= $this->generateWhereFilter($this->cleanValue($value), "t{$field_id}_{$this->_key}", $andOperation);
495
			}
496
			
497
			$where .= ')';
498
			
499
			return true; // this tells the DS Manager that filters are OK!!
500
		}
501
502
		/* ******* EVENTS ******* */
503
504
		public function getExampleFormMarkup()
505
		{
506
			$label = Widget::Label($this->get('label'));
507
			$label->appendChild(Widget::Input('fields['.$this->get('element_name').'][entries]', null, 'hidden'));
508
509
			return $label;
510
		}
511
512
513
		/* ******* DATA SOURCE ******* */
514
		
515
		private function fetchEntry($eId, $elements = array())
516
		{
517
			$entry = EntryManager::fetch($eId, null, 1, 0, null, null, false, true, $elements, false);
518
			if (!is_array($entry) || count($entry) !== 1) {
519
				return null;
520
			}
521
			return $entry[0];
522
		}
523
		
524
		public function fetchIncludableElements()
525
		{
526
			$label = $this->get('element_name');
527
			$elements = array_filter(array_map(trim, explode(self::SEPARATOR, trim($this->get('elements')))));
528
			$includedElements = array($label . ': *');
529
			foreach ($elements as $elem) {
530
				$elem = trim($elem);
531
				if ($elem !== '*') {
532
					$includedElements[] = $label . ': ' . $elem;
533
				}
534
			}
535
			return $includedElements;
536
		}
537
		
538
		/**
539
		 * Appends data into the XML tree of a Data Source
540
		 * @param $wrapper
541
		 * @param $data
542
		 */
543
		public function appendFormattedElement(&$wrapper, $data, $encode = false, $mode = null, $entry_id = null)
544
		{
545
			if(!is_array($data) || empty($data)) return;
546
547
			// root for all values
548
			$root = new XMLElement($this->get('element_name'));
549
			
550
			// selected items
551
			$entries = static::getEntries($data);
552
			
553
			// current linked entries
554
			$root->setAttribute('entries', $data['entries']);
555
			
556
			// available sections
557
			$root->setAttribute('sections', $this->get('sections'));
558
			
559
			// included elements
560
			$elements = static::parseElements($this);
561
			
562
			// DS mode
563
			if (!$mode) {
564
				$mode = '*';
565
			}
566
			
567
			$parentDeepness = General::intval($this->recursiveDeepness);
568
			$deepness = General::intval($this->get('deepness'));
569
			
570
			// both deepnesses are defined and parent restricts more
571
			if ($parentDeepness > 0 && $deepness > 0 && $parentDeepness < $deepness) {
572
				$deepness = $parentDeepness;
573
			}
574
			// parent is defined, current is not
575
			else if ($parentDeepness > 0 && $deepness < 1) {
576
				$deepness = $parentDeepness;
577
			}
578
			
579
			// cache recursive level because recursion might
580
			// change its value later on.
581
			$recursiveLevel = $this->recursiveLevel;
582
			
583
			// build entries
584
			foreach ($entries as $eId) {
585
				$item = new XMLElement('item');
586
				// output id
587
				$item->setAttribute('id', $eId);
588
				// output recursive level
589
				$item->setAttribute('level', $recursiveLevel);
590
				$item->setAttribute('max-level', $deepness);
591
				
592
				// max recursion check
593
				if ($deepness < 1 || $recursiveLevel < $deepness) {
594
					// current entry, without data
595
					$entry = $this->fetchEntry($eId);
596
					
597
					// entry not found...
598
					if (!$entry || empty($entry)) {
599
						$error = new XMLElement('error');
600
						$error->setAttribute('id', $eId);
601
						$error->setValue(__('Error: entry `%s` not found', array($eId)));
602
						$root->prependChild($error);
603
						continue;
604
					}
605
					
606
					// fetch section infos
607
					$sectionId = $entry->get('section_id');
608
					$section = $this->sectionsManager->fetch($sectionId);
609
					$sectionName = $section->get('handle');
610
					// cache fields info
611
					if (!isset($section->er_field_cache)) {
612
						$section->er_field_cache = $section->fetchFields();
613
					}
614
					
615
					// set section related attributes
616
					$item->setAttribute('section-id', $sectionId);
617
					$item->setAttribute('section', $sectionName);
618
					
619
					// Get the valid elements for this section only
620
					$validElements = $elements[$sectionName];
621
					
622
					// adjust the mode for the current section
623
					$curMode = $mode;
624
					
625
					// remove section name from current mode, i.e sectionName.field
626
					if (preg_match('/^(' . $sectionName . '\.)(.*)$/sU', $curMode)) {
627
						$curMode = preg_replace('/^' . $sectionName . '\./sU', '', $curMode);
628
					}
629
					// remove section name from current mode, i.e sectionName
630
					else if (preg_match('/^(' . $sectionName . ')$/sU', $curMode)) {
631
						$curMode = '*';
632
					}
633
					// section name was not found in mode
634
					else if ($curMode != '*') {
635
						// mode forbids this section
636
						$validElements = null;
637
					}
638
					
639
					// this section is not selected, bail out
640
					if (!is_array($validElements)) {
641
						$item->setAttribute('forbidden-by', $curMode);
642
						$root->appendChild($item);
643
						continue;
644
					}
645
					
646
					// selected fields for fetching
647
					$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...
648
					
649
					// everything is allowed
650
					if (in_array('*', $validElements)) {
651
						if ($curMode !== '*') {
652
							// get only the mode
653
							$sectionElements = array($curMode);
654
						}
655
						else {
656
							// setting null = get all
657
							$sectionElements = null;
658
						}
659
					}
660
					// only use valid elements
661
					else {
662
						if ($curMode !== '*') {
663
							// is this field allowed ?
664
							if (self::isFieldIncluded($curMode, $validElements)) {
665
								// get only the mode
666
								$sectionElements = array($curMode);
667
							}
668
							else {
669
								// $curMode selects something outside of
670
								// the valid elements: select nothing
671
								$sectionElements = array();
672
							}
673
						}
674
						else {
675
							// use field's valid elements
676
							$sectionElements = $validElements;
677
						}
678
					}
679
					
680
					if (is_array($sectionElements) && empty($sectionElements)) {
681
						$item->setAttribute('selection-empty', 'yes');
682
						$item->setAttribute('forbidden-by', $curMode);
683
						$root->appendChild($item);
684
						continue;
685
					}
686
					
687
					// current entry again, but with data and the allowed schema
688
					$entry = $this->fetchEntry($eId, $sectionElements);
689
					
690
					// cache the entry data
691
					$entryData = $entry->getData();
692
					
693
					// for each field returned for this entry...
694
					foreach ($entryData as $fieldId => $data) {
695
						$filteredData = array_filter($data, function ($value) {
696
							return $value != null;
697
						});
698
						
699
						if (empty($filteredData)) {
700
							continue;
701
						}
702
						
703
						$field = $section->er_field_cache[$fieldId];
704
						$fieldName = $field->get('element_name');
705
						$fieldCurMode = self::extractMode($fieldName, $curMode);
706
						
707
						$parentIncludableElement = self::getSectionElementName($fieldName, $validElements);
708
						$parentIncludableElementMode = self::extractMode($fieldName, $parentIncludableElement);
709
						
710
						// Special treatments for ERF
711
						if ($field instanceof FieldEntry_relationship) {
712
							// Increment recursive level
713
							$field->recursiveLevel = $recursiveLevel + 1;
714
							$field->recursiveDeepness = $deepness;
715
						}
716
						
717
						$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...
718
						if ($parentIncludableElementMode == null) {
719
							if ($fieldCurMode == null) {
720
								$submodes = null;
721
							}
722
							else {
723
								$submodes = array($fieldCurMode);
724
							}
725
						}
726
						else {
727
							if ($fieldCurMode == null || $fieldCurMode == $parentIncludableElementMode) {
728
								$submodes = array($parentIncludableElementMode);
729
							}
730
							else {
731
								$item->setAttribute('selection-mode-empty', 'yes');
732
								$submodes = array();
733
							}
734
						}
735
						
736
						// current selection does not specify a mode
737 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...
738
							$submodes = array_map(function ($fieldIncludableElement) use ($fieldName) {
739
								return FieldEntry_relationship::extractMode($fieldName, $fieldIncludableElement);
740
							}, $field->fetchIncludableElements());
741
						}
742
						
743
						foreach ($submodes as $submode) {
744
							$field->appendFormattedElement($item, $data, $encode, $submode, $eId);
745
						}
746
					}
747
					// output current mode
748
					$item->setAttribute('matched-element', $curMode);
749
					// no field selected
750
					if (is_array($sectionElements) && empty($sectionElements)) {
751
						$item->setAttribute('empty-selection', 'yes');
752
					}
753
				}
754
				// append item when done
755
				$root->appendChild($item);
756
			} // end each entries
757
			
758
			// output mode for this field
759
			$root->setAttribute('data-source-mode', $mode);
760
			$root->setAttribute('field-included-elements', $this->get('elements'));
761
			
762
			// add all our data to the wrapper;
763
			$wrapper->appendChild($root);
764
			
765
			// clean up
766
			$this->recursiveLevel = 1;
767
			$this->recursiveDeepness = null;
768
		}
769
770
		public function getParameterPoolValue(array $data, $entry_id = null)
771
		{
772
			if(!is_array($data) || empty($data)) return;
773
			return static::getEntries($data);
774
		}
775
776
		/* ********* Utils *********** */
777
		
778
		/**
779
		 * Return true if $fieldName is allowed in $sectionElements
780
		 * @param string $fieldName
781
		 * @param string $sectionElements
782
		 * @return bool
783
		 */
784
		public static function isFieldIncluded($fieldName, $sectionElements)
785
		{
786
			return self::getSectionElementName($fieldName, $sectionElements) !== null;
787
		}
788
789
		public static function getSectionElementName($fieldName, $sectionElements)
790
		{
791
			if (is_array($sectionElements)) {
792
				foreach ($sectionElements as $element) {
793
					if ($element == '*') {
794
						return $fieldName;
795
					}
796
					if ($fieldName == $element || preg_match('/^' . $fieldName . '\s*:/sU', $element)) {
797
						return $element;
798
					}
799
				}
800
			}
801
			return null;
802
		}
803
		
804
		public static function parseElements($field)
805
		{
806
			$elements = array();
807
			$exElements = array_map(trim, explode(self::SEPARATOR, $field->get('elements')));
808
			
809
			if (in_array('*', $exElements)) {
810
				$sections = array_map(trim, explode(self::SEPARATOR, $field->get('sections')));
811
				$sections = SectionManager::fetch($sections);
812
				return array_reduce($sections, function ($result, $section) {
813
					$result[$section->get('handle')] = array('*');
814
					return $result;
815
				}, array());
816
			}
817
			
818
			foreach ($exElements as $value) {
819
				if (!$value) {
820
					continue;
821
				}
822
				// sectionName.fieldName or sectionName.*
823
				$parts = array_map(trim, explode('.', $value));
824
				// first time seeing this section
825
				if (!isset($elements[$parts[0]])) {
826
					$elements[$parts[0]] = array();
827
				}
828
				// we have a value after the dot
829
				if (isset($parts[1]) && !!$parts[1]) {
830
					$elements[$parts[0]][] = $parts[1];
831
				}
832
				// sectionName only
833
				else if (!isset($parts[1])) {
834
					$elements[$parts[0]][] = '*';
835
				}
836
			}
837
			
838
			return $elements;
839
		}
840
841
		public static function extractMode($fieldName, $mode)
842
		{
843
			$pattern = '/^' . $fieldName . '\s*:\s*/s';
844
			if (!preg_match($pattern, $mode)) {
845
				return null;
846
			}
847
			$mode = preg_replace($pattern, '', $mode, 1);
848
			if ($mode === '*') {
849
				return null;
850
			}
851
			return $mode;
852
		}
853
854
		/**
855
		 * @param string $prefix
856
		 * @param string $name
857
		 * @param @optional bool $multiple
858
		 */
859
		private function createFieldName($prefix, $name, $multiple = false)
860
		{
861
			$name = "fields[$prefix][$name]";
862
			if ($multiple) {
863
				$name .= '[]';
864
			}
865
			return $name;
866
		}
867
		
868
		/**
869
		 * @param string $name
870
		 */
871
		private function createSettingsFieldName($name, $multiple = false)
872
		{
873
			return $this->createFieldName($this->get('sortorder'), $name, $multiple);
874
		}
875
		
876
		/**
877
		 * @param string $name
878
		 */
879
		private function createPublishFieldName($name, $multiple = false)
880
		{
881
			return $this->createFieldName($this->get('element_name'), $name, $multiple);
882
		}
883
		
884
		private function getSelectedSectionsArray()
885
		{
886
			$selectedSections = $this->get('sections');
887
			if (!is_array($selectedSections)) {
888
				if (is_string($selectedSections) && strlen($selectedSections) > 0) {
889
					$selectedSections = explode(self::SEPARATOR, $selectedSections);
890
				}
891
				else {
892
					$selectedSections = array();
893
				}
894
			}
895
			return $selectedSections;
896
		}
897
		
898
		private function buildSectionSelect($name)
899
		{
900
			$sections = SectionManager::fetch();
901
			$options = array();
902
			$selectedSections = $this->getSelectedSectionsArray();
903
			
904
			foreach ($sections as $section) {
905
				$driver = $section->get('id');
906
				$selected = in_array($driver, $selectedSections);
907
				$options[] = array($driver, $selected, $section->get('name'));
908
			}
909
			
910
			return Widget::Select($name, $options, array('multiple' => 'multiple'));
911
		} 
912
		
913
		private function appendSelectionSelect(&$wrapper)
914
		{
915
			$name = $this->createSettingsFieldName('sections', true);
916
917
			$input = $this->buildSectionSelect($name);
918
			$input->setAttribute('class', 'entry_relationship-sections');
919
920
			$label = Widget::Label();
921
			$label->setAttribute('class', 'column');
922
923
			$label->setValue(__('Available sections %s', array($input->generate())));
924
925
			$wrapper->appendChild($label);
926
		}
927
928
		private function createEntriesList($entries)
929
		{
930
			$wrap = new XMLElement('div');
931
			$wrapperClass = 'frame collapsible orderable';
932
			if (count($entries) > 0) {
933
				$wrapperClass .= ' empty';
934
			}
935
			if (!$this->is('show_header')) {
936
				$wrapperClass .= ' no-header';
937
			}
938
			$wrap->setAttribute('class', $wrapperClass);
939
			
940
			$list = new XMLElement('ul');
941
			$list->setAttribute('class', '');
942
			if ($this->is('allow_collapse')) {
943
				$list->setAttribute('data-collapsible', '');
944
			}
945
			
946
			$wrap->appendChild($list);
947
			
948
			return $wrap;
949
		}
950
		
951
		private function createEntriesHiddenInput($data)
952
		{
953
			$hidden = new XMLElement('input', null, array(
954
				'type' => 'hidden',
955
				'name' => $this->createPublishFieldName('entries'),
956
				'value' => $data['entries']
957
			));
958
			
959
			return $hidden;
960
		}
961
		
962
		private function createPublishMenu($sections)
963
		{
964
			$wrap = new XMLElement('fieldset');
965
			$wrap->setAttribute('class', 'single');
966
			
967
			if ($this->is('allow_new') || $this->is('allow_link')) {
968
				$selectWrap = new XMLElement('div');
969
				$selectWrap->appendChild(new XMLElement('span', __('Related section: ')));
970
				$options = array();
971
				foreach ($sections as $section) {
972
					$options[] = array($section->get('handle'), false, $section->get('name'));
973
				}
974
				$select = Widget::Select('', $options, array('class' => 'sections'));
975
				$selectWrap->appendChild($select);
976
				$wrap->appendChild($selectWrap);
977
			}
978 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...
979
				$wrap->appendChild(new XMLElement('button', __('Create new'), array(
980
					'type' => 'button',
981
					'class' => 'create',
982
					'data-create' => '',
983
				)));
984
			}
985 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...
986
				$wrap->appendChild(new XMLElement('button', __('Link to entry'), array(
987
					'type' => 'button',
988
					'class' => 'link',
989
					'data-link' => '',
990
				)));
991
			}
992
			
993
			return $wrap;
994
		}
995
996
		/* ********* UI *********** */
997
		
998
		/**
999
		 *
1000
		 * Builds the UI for the field's settings when creating/editing a section
1001
		 * @param XMLElement $wrapper
1002
		 * @param array $errors
1003
		 */
1004
		public function displaySettingsPanel(&$wrapper, $errors=NULL)
1005
		{
1006
			/* first line, label and such */
1007
			parent::displaySettingsPanel($wrapper, $errors);
1008
			
1009
			// sections
1010
			$sections = new XMLElement('fieldset');
1011
			
1012
			$this->appendSelectionSelect($sections);
1013
			if (is_array($errors) && isset($errors['sections'])) {
1014
				$sections = Widget::Error($sections, $errors['sections']);
1015
			}
1016
			$wrapper->appendChild($sections);
1017
			
1018
			// elements
1019
			$elements = new XMLElement('div');
1020
			$element = Widget::Label();
1021
			$element->setValue(__('Included elements in Data Sources and Backend Templates'));
1022
			$element->setAttribute('class', 'column');
1023
			$element->appendChild(Widget::Input($this->createSettingsFieldName('elements'), $this->get('elements'), 'text', array(
1024
				'class' => 'entry_relationship-elements'
1025
			)));
1026
			$elements->appendChild($element);
1027
			$elements_choices = new XMLElement('ul', null, array('class' => 'tags singular entry_relationship-field-choices'));
1028
			
1029
			$elements->appendChild($elements_choices);
1030
			$wrapper->appendChild($elements);
1031
			
1032
			// limit entries
1033
			$limits = new XMLElement('fieldset');
1034
			$limits->appendChild(new XMLElement('legend', __('Limits')));
1035
			$limits_cols = new XMLElement('div');
1036
			$limits_cols->setAttribute('class', 'three columns');
1037
			// min
1038
			$limit_min = Widget::Label();
1039
			$limit_min->setValue(__('Minimum count of entries in this field'));
1040
			$limit_min->setAttribute('class', 'column');
1041
			$limit_min->appendChild(Widget::Input($this->createSettingsFieldName('min_entries'), $this->get('min_entries'), 'number', array(
1042
				'min' => 0,
1043
				'max' => 99999
1044
			)));
1045
			$limits_cols->appendChild($limit_min);
1046
			// max
1047
			$limit_max = Widget::Label();
1048
			$limit_max->setValue(__('Maximum count of entries in this field'));
1049
			$limit_max->setAttribute('class', 'column');
1050
			$limit_max->appendChild(Widget::Input($this->createSettingsFieldName('max_entries'), $this->get('max_entries'), 'number', array(
1051
				'min' => 0,
1052
				'max' => 99999
1053
			)));
1054
			$limits_cols->appendChild($limit_max);
1055
			
1056
			// deepness
1057
			$deepness = Widget::Label();
1058
			$deepness->setValue(__('Maximum level of recursion in Data Sources'));
1059
			$deepness->setAttribute('class', 'column');
1060
			$deepness->appendChild(Widget::Input($this->createSettingsFieldName('deepness'), $this->get('deepness'), 'number', array(
1061
				'min' => 0,
1062
				'max' => 99
1063
			)));
1064
			$limits_cols->appendChild($deepness);
1065
			$limits->appendChild($limits_cols);
1066
			$wrapper->appendChild($limits);
1067
			
1068
			// xsl
1069
			$xsl = new XMLElement('fieldset');
1070
			$xsl->appendChild(new XMLElement('legend', __('Backend XSL templates options')));
1071
			$xsl_cols = new XMLElement('div');
1072
			$xsl_cols->setAttribute('class', 'four columns');
1073
			
1074
			// xsl mode
1075
			$xslmode = Widget::Label();
1076
			$xslmode->setValue(__('XSL mode for entries content template'));
1077
			$xslmode->setAttribute('class', 'column');
1078
			$xslmode->appendChild(Widget::Input($this->createSettingsFieldName('mode'), $this->get('mode'), 'text'));
1079
			$xsl_cols->appendChild($xslmode);
1080
			// xsl header mode
1081
			$xslmodetable = Widget::Label();
1082
			$xslmodetable->setValue(__('XSL mode for entries header template'));
1083
			$xslmodetable->setAttribute('class', 'column');
1084
			$xslmodetable->appendChild(Widget::Input($this->createSettingsFieldName('mode_header'), $this->get('mode_header'), 'text'));
1085
			$xsl_cols->appendChild($xslmodetable);
1086
			// xsl table mode
1087
			$xslmodetable = Widget::Label();
1088
			$xslmodetable->setValue(__('XSL mode for publish table value'));
1089
			$xslmodetable->setAttribute('class', 'column');
1090
			$xslmodetable->appendChild(Widget::Input($this->createSettingsFieldName('mode_table'), $this->get('mode_table'), 'text'));
1091
			$xsl_cols->appendChild($xslmodetable);
1092
			
1093
			$xsl->appendChild($xsl_cols);
1094
			$wrapper->appendChild($xsl);
1095
			
1096
			// permissions
1097
			$permissions = new XMLElement('fieldset');
1098
			$permissions->appendChild(new XMLElement('legend', __('Permissions')));
1099
			$permissions_cols = new XMLElement('div');
1100
			$permissions_cols->setAttribute('class', 'four columns');
1101
			$permissions_cols->appendChild($this->createCheckbox('allow_new', 'Show new button'));
1102
			$permissions_cols->appendChild($this->createCheckbox('allow_edit', 'Show edit button'));
1103
			$permissions_cols->appendChild($this->createCheckbox('allow_link', 'Show link button'));
1104
			$permissions_cols->appendChild($this->createCheckbox('allow_delete', 'Show delete button'));
1105
			$permissions->appendChild($permissions_cols);
1106
			$wrapper->appendChild($permissions);
1107
			
1108
			// display options
1109
			$display = new XMLElement('fieldset');
1110
			$display->appendChild(new XMLElement('legend', __('Display options')));
1111
			$display_cols = new XMLElement('div');
1112
			$display_cols->setAttribute('class', 'four columns');
1113
			$display_cols->appendChild($this->createCheckbox('allow_collapse', 'Allow content collapsing'));
1114
			$display_cols->appendChild($this->createCheckbox('show_header', 'Show the header box before entries templates'));
1115
			$display->appendChild($display_cols);
1116
			$wrapper->appendChild($display);
1117
			
1118
			// assoc
1119
			$assoc = new XMLElement('fieldset');
1120
			$assoc->appendChild(new XMLElement('legend', __('Associations')));
1121
			$assoc_cols = new XMLElement('div');
1122
			$assoc_cols->setAttribute('class', 'three columns');
1123
			$this->appendShowAssociationCheckbox($assoc_cols);
1124
			$assoc->appendChild($assoc_cols);
1125
			$wrapper->appendChild($assoc);
1126
			
1127
			// footer
1128
			$this->appendStatusFooter($wrapper);
1129
		}
1130
		
1131
		/**
1132
		 * @param string $fieldName
1133
		 * @param string $text
1134
		 */
1135
		private function createCheckbox($fieldName, $text) {
1136
			$chk = Widget::Label();
1137
			$chk->setAttribute('class', 'column');
1138
			$attrs = null;
1139
			if ($this->get($fieldName) == 'yes') {
1140
				$attrs = array('checked' => 'checked');
1141
			}
1142
			$chk->appendChild(Widget::Input($this->createSettingsFieldName($fieldName), 'yes', 'checkbox', $attrs));
1143
			$chk->setValue(__($text));
1144
			return $chk;
1145
		}
1146
1147
		/**
1148
		 *
1149
		 * Builds the UI for the publish page
1150
		 * @param XMLElement $wrapper
1151
		 * @param mixed $data
1152
		 * @param mixed $flagWithError
1153
		 * @param string $fieldnamePrefix
1154
		 * @param string $fieldnamePostfix
1155
		 */
1156
		public function displayPublishPanel(&$wrapper, $data=NULL, $flagWithError=NULL, $fieldnamePrefix=NULL, $fieldnamePostfix=NULL, $entry_id = null)
1157
		{
1158
			$entriesId = array();
1159
			$sectionsId = $this->getSelectedSectionsArray();
1160
			
1161
			if ($data['entries'] != null) {
1162
				$entriesId = static::getEntries($data);
1163
			}
1164
			
1165
			$sectionsId = array_map(array('General', 'intval'), $sectionsId);
1166
			$sections = SectionManager::fetch($sectionsId);
1167
			
1168
			$label = Widget::Label($this->get('label'));
1169
			$notes = '';
1170
			
1171
			// min note
1172
			if ($this->getInt('min_entries') > 0) {
1173
				$notes .= __('Minimum number of entries: <b>%s</b>. ', array($this->get('min_entries')));
1174
			}
1175
			// max note
1176
			if ($this->getInt('max_entries') > 0) {
1177
				$notes .= __('Maximum number of entries: <b>%s</b>. ', array($this->get('max_entries')));
1178
			}
1179
			// not required note
1180
			if (!$this->isRequired()) {
1181
				$notes .= __('Optional');
1182
			}
1183
			// append notes
1184
			if ($notes) {
1185
				$label->appendChild(new XMLElement('i', $notes));
1186
			}
1187
			
1188
			// label error management
1189
			if ($flagWithError != NULL) {
1190
				$wrapper->appendChild(Widget::Error($label, $flagWithError));
1191
			} else {
1192
				$wrapper->appendChild($label);
1193
			}
1194
			
1195
			$wrapper->appendChild($this->createEntriesList($entriesId));
1196
			$wrapper->appendChild($this->createPublishMenu($sections));
1197
			$wrapper->appendChild($this->createEntriesHiddenInput($data));
1198
			$wrapper->setAttribute('data-value', $data['entries']);
1199
			$wrapper->setAttribute('data-field-id', $this->get('id'));
1200
			$wrapper->setAttribute('data-field-label', $this->get('label'));
1201
			$wrapper->setAttribute('data-min', $this->get('min_entries'));
1202
			$wrapper->setAttribute('data-max', $this->get('max_entries'));
1203
			if (isset($_REQUEST['debug'])) {
1204
				$wrapper->setAttribute('data-debug', true);
1205
			}
1206
		}
1207
1208
		/**
1209
		 * @param integer $count
1210
		 */
1211
		private static function formatCount($count)
1212
		{
1213
			if ($count == 0) {
1214
				return __('No item');
1215
			} else if ($count == 1) {
1216
				return __('1 item');
1217
			}
1218
			return __('%s items', array($count));
1219
		}
1220
1221
		/**
1222
		 *
1223
		 * Return a plain text representation of the field's data
1224
		 * @param array $data
1225
		 * @param int $entry_id
1226
		 */
1227
		public function prepareTextValue($data, $entry_id = null)
1228
		{
1229
			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...
1230
				return '';
1231
			}
1232
			return $data['entries'];
1233
		}
1234
1235
		/**
1236
		 * Format this field value for display as readable text value.
1237
		 *
1238
		 * @param array $data
1239
		 *  an associative array of data for this string. At minimum this requires a
1240
		 *  key of 'value'.
1241
		 * @param integer $entry_id (optional)
1242
		 *  An option entry ID for more intelligent processing. Defaults to null.
1243
		 * @param string $defaultValue (optional)
1244
		 *  The value to use when no plain text representation of the field's data
1245
		 *  can be made. Defaults to null.
1246
		 * @return string
1247
		 *  the readable text summary of the values of this field instance.
1248
		 */
1249
		public function prepareReadableValue($data, $entry_id = null, $truncate = false, $defaultValue = 'None')
1250
		{
1251
			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...
1252
				return __($defaultValue);
1253
			}
1254
			$entries = static::getEntries($data);
1255
			$realEntries = array();
1256
			foreach ($entries as $entryId) {
1257
				$e = EntryManager::fetch($entryId);
1258
				if (is_array($e) && !empty($e)) {
1259
					$realEntries = array_merge($realEntries, $e);
1260
				}
1261
			}
1262
			$count = count($entries);
1263
			$realCount = count($realEntries);
1264
			if ($count === $realCount) {
1265
				return self::formatCount($count);
1266
			}
1267
			return self::formatCount($realCount) . ' (' . self::formatCount($count - $realCount) . ' not found)';
1268
		}
1269
1270
		/**
1271
		 * Format this field value for display in the publish index tables.
1272
		 *
1273
		 * @param array $data
1274
		 *  an associative array of data for this string. At minimum this requires a
1275
		 *  key of 'value'.
1276
		 * @param XMLElement $link (optional)
1277
		 *  an XML link structure to append the content of this to provided it is not
1278
		 *  null. it defaults to null.
1279
		 * @param integer $entry_id (optional)
1280
		 *  An option entry ID for more intelligent processing. defaults to null
1281
		 * @return string
1282
		 *  the formatted string summary of the values of this field instance.
1283
		 */
1284
		public function prepareTableValue($data, XMLElement $link = null, $entry_id = null)
1285
		{
1286
			$value = $this->prepareReadableValue($data, $entry_id, false, __('None'));
1287
1288
			if ($link) {
1289
				$link->setValue($value);
1290
				return $link->generate();
1291
			}
1292
			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...
1293
				$entries = static::getEntries($data);
1294
				$cellcontent = '';
1295
				foreach ($entries as $child_entry_id) {
1296
					$entry = current($this->entryManager->fetch($child_entry_id));
1297
					$section = $this->sectionManager->fetch($entry->get('section_id'));
1298
					$content = ERFXSLTUTilities::entryToXml($this, $entry, $section->get('handle'), $section->fetchFields(), 'mode_table', isset($_REQUEST['debug']));
1299
					if ($content) {
1300
						$cellcontent .= $content;
1301
					}
1302
				}
1303
				
1304
				if (General::strlen(trim($cellcontent))) {
1305
					return $cellcontent;
1306
				}
1307
			}
1308
1309
			return $value;
1310
		}
1311
1312
		/* ********* SQL Data Definition ************* */
1313
1314
		/**
1315
		 *
1316
		 * Creates table needed for entries of individual fields
1317
		 */
1318
		public function createTable()
1319
		{
1320
			$id = $this->get('id');
1321
1322
			return Symphony::Database()->query("
1323
				CREATE TABLE `tbl_entries_data_$id` (
1324
					`id` int(11) 		unsigned NOT NULL AUTO_INCREMENT,
1325
					`entry_id` 			int(11) unsigned NOT NULL,
1326
					`entries` 			text COLLATE utf8_unicode_ci NULL,
1327
					PRIMARY KEY  (`id`),
1328
					UNIQUE KEY `entry_id` (`entry_id`)
1329
				) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
1330
			");
1331
		}
1332
1333
		/**
1334
		 * Creates the table needed for the settings of the field
1335
		 */
1336
		public static function createFieldTable()
1337
		{
1338
			$tbl = self::FIELD_TBL_NAME;
1339
1340
			return Symphony::Database()->query("
1341
				CREATE TABLE IF NOT EXISTS `$tbl` (
1342
					`id` 				int(11) unsigned NOT NULL AUTO_INCREMENT,
1343
					`field_id` 			int(11) unsigned NOT NULL,
1344
					`sections`			varchar(255) NULL COLLATE utf8_unicode_ci,
1345
					`show_association` 	enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1346
					`deepness` 			int(2) unsigned NULL,
1347
					`elements` 			varchar(1024) NULL COLLATE utf8_unicode_ci,
1348
					`mode`				varchar(50) NULL COLLATE utf8_unicode_ci,
1349
					`mode_table`		varchar(50) NULL COLLATE utf8_unicode_ci DEFAULT NULL,
1350
					`mode_header`		varchar(50) NULL COLLATE utf8_unicode_ci DEFAULT NULL,
1351
					`min_entries`		int(5) unsigned NULL,
1352
					`max_entries`		int(5) unsigned NULL,
1353
					`allow_edit` 		enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1354
					`allow_new` 		enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1355
					`allow_link` 		enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1356
					`allow_delete` 		enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'no',
1357
					`allow_collapse` 	enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1358
					`show_header` 		enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1359
					PRIMARY KEY (`id`),
1360
					UNIQUE KEY `field_id` (`field_id`)
1361
				) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
1362
			");
1363
		}
1364
		
1365
		public static function update_102()
1366
		{
1367
			$tbl = self::FIELD_TBL_NAME;
1368
			$sql = "
1369
				ALTER TABLE `$tbl`
1370
					ADD COLUMN `allow_edit` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1371
					ADD COLUMN `allow_new` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes',
1372
					ADD COLUMN `allow_link` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes'
1373
					AFTER `max_entries`
1374
			";
1375
			$addColumns = Symphony::Database()->query($sql);
1376
			if (!$addColumns) {
1377
				return false;
1378
			}
1379
1380
			$fields = FieldManager::fetch(null, null, null, 'id', 'entry_relationship');
1381
			if (!empty($fields) && is_array($fields)) {
1382
				foreach ($fields as $fieldId => $field) {
1383
					$sql = "ALTER TABLE `tbl_entries_data_$fieldId` MODIFY `entries` TEXT";
1384
					if (!Symphony::Database()->query($sql)) {
1385
						throw new Exception(__('Could not update table `tbl_entries_data_%s`.', array($fieldId)));
1386
					}
1387
				}
1388
			}
1389
			return true;
1390
		}
1391
		
1392
		public static function update_103()
1393
		{
1394
			$tbl = self::FIELD_TBL_NAME;
1395
			$sql = "
1396
				ALTER TABLE `$tbl`
1397
					ADD COLUMN `allow_delete` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'no'
1398
						AFTER `allow_link`
1399
			";
1400
			return Symphony::Database()->query($sql);
1401
		}
1402
		
1403
		public static function update_200()
1404
		{
1405
			$tbl = self::FIELD_TBL_NAME;
1406
			$sql = "
1407
				ALTER TABLE `$tbl`
1408
					ADD COLUMN `allow_collapse` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes'
1409
						AFTER `allow_delete`,
1410
					ADD COLUMN `mode_table` varchar(50) NULL COLLATE utf8_unicode_ci DEFAULT NULL
1411
						AFTER `mode`,
1412
					ADD COLUMN `mode_header` varchar(50) NULL COLLATE utf8_unicode_ci DEFAULT NULL
1413
						AFTER `mode_table`,
1414
					ADD COLUMN `show_header` enum('yes','no') NOT NULL COLLATE utf8_unicode_ci DEFAULT 'yes'
1415
						AFTER `allow_collapse`
1416
			";
1417
			return Symphony::Database()->query($sql);
1418
		}
1419
		
1420
		/**
1421
		 *
1422
		 * Drops the table needed for the settings of the field
1423
		 */
1424
		public static function deleteFieldTable()
1425
		{
1426
			$tbl = self::FIELD_TBL_NAME;
1427
			
1428
			return Symphony::Database()->query("
1429
				DROP TABLE IF EXISTS `$tbl`
1430
			");
1431
		}
1432
		
1433
		private static function removeSectionAssociation($child_field_id)
1434
		{
1435
			return Symphony::Database()->delete('tbl_sections_association', "`child_section_field_id` = {$child_field_id}");
1436
		}
1437
	}