Completed
Push — dev ( 6f87eb...29b8e3 )
by Nicolas
01:54
created

FieldEntry_Relationship::checkPostFieldData()   C

Complexity

Conditions 12
Paths 9

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 29
rs 5.1612
c 0
b 0
f 0
cc 12
eloc 17
nc 9
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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