Completed
Push — dev ( 84170d...542d9d )
by Nicolas
01:51
created

FieldEntry_relationship   D

Complexity

Total Complexity 181

Size/Duplication

Total Lines 1240
Duplicated Lines 1.53 %

Coupling/Cohesion

Components 2
Dependencies 1
Metric Value
wmc 181
lcom 2
cbo 1
dl 19
loc 1240
rs 4.4102

54 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 35 1
A isSortable() 0 4 1
A canFilter() 0 4 1
A canPublishFilter() 0 4 1
A canImport() 0 4 1
A canPrePopulate() 0 4 1
A mustBeUnique() 0 4 1
A allowDatasourceOutputGrouping() 0 4 1
A requiresSQLGrouping() 0 4 1
A allowDatasourceParamOutput() 0 4 1
A getInt() 0 4 1
A is() 0 4 1
A isRequired() 0 4 1
A getEntries() 0 4 1
C checkPostFieldData() 0 29 12
B processRawFieldData() 0 23 5
F setFromPOST() 0 26 11
A checkFields() 0 15 4
B commit() 0 56 6
A tearDown() 0 5 1
A generateWhereFilter() 0 11 3
A fetchAssociatedEntryCount() 0 12 2
A fetchAssociatedEntrySearchValue() 0 4 1
A findRelatedEntries() 0 14 2
A prepareAssociationsDrawerXMLElement() 0 17 1
B buildDSRetrievalSQL() 0 28 4
C parseElements() 0 35 8
A fetchEntry() 0 8 3
A fetchIncludableElements() 0 13 3
F appendFormattedElement() 5 213 35
A getParameterPoolValue() 0 5 3
A isFieldIncluded() 0 7 2
B getSectionElementName() 0 11 5
A extractMode() 0 8 2
A createFieldName() 0 8 2
A createSettingsFieldName() 0 4 1
A createPublishFieldName() 0 4 1
A getSelectedSectionsArray() 0 13 4
A buildSectionSelect() 0 14 2
A appendSelectionSelect() 0 14 1
A createEntriesList() 0 12 2
A createEntriesHiddenInput() 0 10 1
B createPublishMenu() 14 33 6
B displaySettingsPanel() 0 90 3
A createCheckbox() 0 11 2
C displayPublishPanel() 0 51 8
A formatCount() 0 9 3
B prepareTextValue() 0 20 7
A createTable() 0 14 1
B createFieldTable() 0 24 1
B update_102() 0 26 6
A update_103() 0 10 1
A deleteFieldTable() 0 8 1
A removeSectionAssociation() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like FieldEntry_relationship often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FieldEntry_relationship, and based on these observations, apply Extract Interface, too.

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