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 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 |
||
| 20 | class FieldEntry_Relationship extends FieldRelationship |
||
| 21 | { |
||
| 22 | /** |
||
| 23 | * |
||
| 24 | * Name of the field table |
||
| 25 | * @var string |
||
| 26 | */ |
||
| 27 | const FIELD_TBL_NAME = 'tbl_fields_entry_relationship'; |
||
| 28 | |||
| 29 | /** |
||
| 30 | * |
||
| 31 | * Current recursive level of output |
||
| 32 | * @var int |
||
| 33 | */ |
||
| 34 | protected $recursiveLevel = 1; |
||
| 35 | public function getRecursiveLevel() |
||
| 43 | |||
| 44 | /** |
||
| 45 | * |
||
| 46 | * Parent's maximum recursive level of output |
||
| 47 | * @var int |
||
| 48 | */ |
||
| 49 | protected $recursiveDeepness = null; |
||
| 50 | public function getRecursiveDeepness() |
||
| 58 | |||
| 59 | // cache managers |
||
| 60 | private $sectionManager; |
||
| 61 | private $entryManager; |
||
| 62 | private $sectionInfos; |
||
| 63 | |||
| 64 | public $expandIncludableElements = true; |
||
| 65 | |||
| 66 | /** |
||
| 67 | * |
||
| 68 | * Constructor for the Entry_Relationship Field object |
||
| 69 | */ |
||
| 70 | public function __construct() |
||
| 71 | { |
||
| 72 | // call the parent constructor |
||
| 73 | parent::__construct(); |
||
| 74 | // EQFA |
||
| 75 | $this->entryQueryFieldAdapter = new EntryQueryEntryrelationshipAdapter($this); |
||
| 76 | // set the name of the field |
||
| 77 | $this->_name = __('Entry Relationship'); |
||
| 78 | // permits to make it required |
||
| 79 | $this->_required = true; |
||
| 80 | // permits the make it show in the table columns |
||
| 81 | $this->_showcolumn = true; |
||
| 82 | // permits association |
||
| 83 | $this->_showassociation = true; |
||
| 84 | // current recursive level |
||
| 85 | $this->recursiveLevel = 1; |
||
| 86 | // parent's maximum recursive level of output |
||
| 87 | $this->recursiveDeepness = null; |
||
| 88 | // set as orderable |
||
| 89 | $this->orderable = true; |
||
| 90 | // set as not required by default |
||
| 91 | $this->set('required', 'no'); |
||
| 92 | // show association by default |
||
| 93 | $this->set('show_association', 'yes'); |
||
| 94 | // no sections |
||
| 95 | $this->set('sections', null); |
||
| 96 | // no max deepness |
||
| 97 | $this->set('deepness', null); |
||
| 98 | // no included elements |
||
| 99 | $this->set('elements', null); |
||
| 100 | // no modes |
||
| 101 | $this->set('mode', null); |
||
| 102 | $this->set('mode_table', null); |
||
| 103 | $this->set('mode_header', null); |
||
| 104 | $this->set('mode_footer', null); |
||
| 105 | // no limit |
||
| 106 | $this->set('min_entries', null); |
||
| 107 | $this->set('max_entries', null); |
||
| 108 | // all permissions |
||
| 109 | $this->set('allow_new', 'yes'); |
||
| 110 | $this->set('allow_edit', 'yes'); |
||
| 111 | $this->set('allow_link', 'yes'); |
||
| 112 | $this->set('allow_delete', 'no'); |
||
| 113 | // display options |
||
| 114 | $this->set('allow_collapse', 'yes'); |
||
| 115 | $this->set('allow_search', 'no'); |
||
| 116 | $this->set('show_header', 'yes'); |
||
| 117 | // cache managers |
||
| 118 | $this->sectionManager = new SectionManager; |
||
| 119 | $this->entryManager = new EntryManager; |
||
| 120 | $this->fieldManager = new FieldManager; |
||
| 121 | $this->sectionInfos = new SectionsInfos; |
||
| 122 | } |
||
| 123 | |||
| 124 | public function isSortable() |
||
| 125 | { |
||
| 126 | return false; |
||
| 127 | } |
||
| 128 | |||
| 129 | public function canFilter() |
||
| 130 | { |
||
| 131 | return true; |
||
| 132 | } |
||
| 133 | |||
| 134 | public function canPublishFilter() |
||
| 135 | { |
||
| 136 | return true; |
||
| 137 | } |
||
| 138 | |||
| 139 | public function canImport() |
||
| 140 | { |
||
| 141 | return false; |
||
| 142 | } |
||
| 143 | |||
| 144 | public function canPrePopulate() |
||
| 145 | { |
||
| 146 | return true; |
||
| 147 | } |
||
| 148 | |||
| 149 | public function mustBeUnique() |
||
| 150 | { |
||
| 151 | return false; |
||
| 152 | } |
||
| 153 | |||
| 154 | public function allowDatasourceOutputGrouping() |
||
| 155 | { |
||
| 156 | return false; |
||
| 157 | } |
||
| 158 | |||
| 159 | public function requiresSQLGrouping() |
||
| 160 | { |
||
| 161 | return false; |
||
| 162 | } |
||
| 163 | |||
| 164 | public function allowDatasourceParamOutput() |
||
| 165 | { |
||
| 166 | return true; |
||
| 167 | } |
||
| 168 | |||
| 169 | /* ********** INPUT AND FIELD *********** */ |
||
| 170 | |||
| 171 | |||
| 172 | /** |
||
| 173 | * |
||
| 174 | * Validates input |
||
| 175 | * Called before <code>processRawFieldData</code> |
||
| 176 | * @param $data |
||
| 177 | * @param $message |
||
| 178 | * @param $entry_id |
||
| 179 | */ |
||
| 180 | public function checkPostFieldData($data, &$message, $entry_id = null) |
||
| 181 | { |
||
| 182 | $message = null; |
||
| 183 | $required = $this->isRequired(); |
||
| 184 | |||
| 185 | if ($required && (!is_array($data) || count($data) == 0 || strlen($data['entries']) < 1)) { |
||
| 186 | $message = __("'%s' is a required field.", array($this->get('label'))); |
||
| 187 | return self::__MISSING_FIELDS__; |
||
| 188 | } |
||
| 189 | |||
| 190 | $entries = $data['entries']; |
||
| 191 | |||
| 192 | if (!is_array($entries)) { |
||
| 193 | $entries = static::getEntries($data); |
||
| 194 | } |
||
| 195 | |||
| 196 | // enforce limits only if required or it contains data |
||
| 197 | if ($required || count($entries) > 0) { |
||
| 198 | if ($this->getInt('min_entries') > 0 && $this->getInt('min_entries') > count($entries)) { |
||
| 199 | $message = __("'%s' requires a minimum of %s entries.", array($this->get('label'), $this->getInt('min_entries'))); |
||
| 200 | return self::__INVALID_FIELDS__; |
||
| 201 | } else if ($this->getInt('max_entries') > 0 && $this->getInt('max_entries') < count($entries)) { |
||
| 202 | $message = __("'%s' can not contains more than %s entries.", array($this->get('label'), $this->getInt('max_entries'))); |
||
| 203 | return self::__INVALID_FIELDS__; |
||
| 204 | } |
||
| 205 | } |
||
| 206 | |||
| 207 | return self::__OK__; |
||
| 208 | } |
||
| 209 | |||
| 210 | |||
| 211 | /** |
||
| 212 | * |
||
| 213 | * Process data before saving into database. |
||
| 214 | * |
||
| 215 | * @param array $data |
||
| 216 | * @param int $status |
||
| 217 | * @param boolean $simulate |
||
| 218 | * @param int $entry_id |
||
| 219 | * |
||
| 220 | * @return Array - data to be inserted into DB |
||
| 221 | */ |
||
| 222 | public function processRawFieldData($data, &$status, &$message = null, $simulate = false, $entry_id = null) |
||
| 223 | { |
||
| 224 | $status = self::__OK__; |
||
| 225 | $entries = null; |
||
| 226 | |||
| 227 | if (!is_array($data) && !is_string($data)) { |
||
| 228 | return null; |
||
| 229 | } |
||
| 230 | |||
| 231 | if (isset($data['entries'])) { |
||
| 232 | $entries = $data['entries']; |
||
| 233 | } |
||
| 234 | else if (is_string($data)) { |
||
| 235 | $entries = $data; |
||
| 236 | } |
||
| 237 | |||
| 238 | $row = array( |
||
| 239 | 'entries' => empty($entries) ? null : $entries |
||
| 240 | ); |
||
| 241 | |||
| 242 | // return row |
||
| 243 | return $row; |
||
| 244 | } |
||
| 245 | |||
| 246 | /** |
||
| 247 | * This function permits parsing different field settings values |
||
| 248 | * |
||
| 249 | * @param array $settings |
||
| 250 | * the data array to initialize if necessary. |
||
| 251 | */ |
||
| 252 | public function setFromPOST(Array $settings = array()) |
||
| 253 | { |
||
| 254 | // call the default behavior |
||
| 255 | parent::setFromPOST($settings); |
||
| 256 | |||
| 257 | // declare a new setting array |
||
| 258 | $new_settings = array(); |
||
| 259 | |||
| 260 | // set new settings |
||
| 261 | $new_settings['sections'] = is_array($settings['sections']) ? |
||
| 262 | implode(self::SEPARATOR, $settings['sections']) : |
||
| 263 | (is_string($settings['sections']) ? $settings['sections'] : null); |
||
| 264 | |||
| 265 | $new_settings['show_association'] = $settings['show_association'] == 'yes' ? 'yes' : 'no'; |
||
| 266 | $new_settings['deepness'] = General::intval($settings['deepness']); |
||
| 267 | $new_settings['deepness'] = $new_settings['deepness'] < 1 ? null : $new_settings['deepness']; |
||
| 268 | $new_settings['elements'] = empty($settings['elements']) ? null : $settings['elements']; |
||
| 269 | $new_settings['mode'] = empty($settings['mode']) ? null : $settings['mode']; |
||
| 270 | $new_settings['mode_table'] = empty($settings['mode_table']) ? null : $settings['mode_table']; |
||
| 271 | $new_settings['mode_header'] = empty($settings['mode_header']) ? null : $settings['mode_header']; |
||
| 272 | $new_settings['mode_footer'] = empty($settings['mode_footer']) ? null : $settings['mode_footer']; |
||
| 273 | $new_settings['allow_new'] = $settings['allow_new'] == 'yes' ? 'yes' : 'no'; |
||
| 274 | $new_settings['allow_edit'] = $settings['allow_edit'] == 'yes' ? 'yes' : 'no'; |
||
| 275 | $new_settings['allow_link'] = $settings['allow_link'] == 'yes' ? 'yes' : 'no'; |
||
| 276 | $new_settings['allow_delete'] = $settings['allow_delete'] == 'yes' ? 'yes' : 'no'; |
||
| 277 | $new_settings['allow_collapse'] = $settings['allow_collapse'] == 'yes' ? 'yes' : 'no'; |
||
| 278 | $new_settings['allow_search'] = $settings['allow_search'] == 'yes' ? 'yes' : 'no'; |
||
| 279 | $new_settings['show_header'] = $settings['show_header'] == 'yes' ? 'yes' : 'no'; |
||
| 280 | |||
| 281 | // save it into the array |
||
| 282 | $this->setArray($new_settings); |
||
| 283 | } |
||
| 284 | |||
| 285 | |||
| 286 | /** |
||
| 287 | * |
||
| 288 | * Validates the field settings before saving it into the field's table |
||
| 289 | */ |
||
| 290 | public function checkFields(Array &$errors, $checkForDuplicates = true) |
||
| 291 | { |
||
| 292 | $parent = parent::checkFields($errors, $checkForDuplicates); |
||
| 293 | if ($parent != self::__OK__) { |
||
| 294 | return $parent; |
||
| 295 | } |
||
| 296 | |||
| 297 | $sections = $this->get('sections'); |
||
| 298 | |||
| 299 | if (empty($sections)) { |
||
| 300 | $errors['sections'] = __('At least one section must be chosen'); |
||
| 301 | } |
||
| 302 | |||
| 303 | return (!empty($errors) ? self::__ERROR__ : self::__OK__); |
||
| 304 | } |
||
| 305 | |||
| 306 | /** |
||
| 307 | * |
||
| 308 | * Save field settings into the field's table |
||
| 309 | */ |
||
| 310 | public function commit() |
||
| 311 | { |
||
| 312 | // if the default implementation works... |
||
| 313 | if(!parent::commit()) return false; |
||
| 314 | |||
| 315 | $id = $this->get('id'); |
||
| 316 | |||
| 317 | // exit if there is no id |
||
| 318 | if($id == false) return false; |
||
| 319 | |||
| 320 | // we are the child, with multiple parents |
||
| 321 | $child_field_id = $id; |
||
| 322 | |||
| 323 | // delete associations, only where we are the child |
||
| 324 | self::removeSectionAssociation($child_field_id); |
||
| 325 | |||
| 326 | $sections = $this->getSelectedSectionsArray(); |
||
| 327 | |||
| 328 | foreach ($sections as $key => $sectionId) { |
||
| 329 | if (empty($sectionId)) { |
||
| 330 | continue; |
||
| 331 | } |
||
| 332 | $parent_section_id = General::intval($sectionId); |
||
| 333 | if ($parent_section_id < 1) { |
||
| 334 | // section not found, bail out |
||
| 335 | continue; |
||
| 336 | } |
||
| 337 | $parent_section = $this->sectionManager |
||
| 338 | ->select() |
||
| 339 | ->section($parent_section_id) |
||
| 340 | ->execute() |
||
| 341 | ->next(); |
||
| 342 | if (!$parent_section) { |
||
| 343 | // section not found, bail out |
||
| 344 | continue; |
||
| 345 | } |
||
| 346 | $fields = $parent_section->fetchVisibleColumns(); |
||
| 347 | if (empty($fields)) { |
||
| 348 | // no visible field, revert to all |
||
| 349 | $fields = $parent_section->fetchFields(); |
||
| 350 | } |
||
| 351 | if (empty($fields)) { |
||
| 352 | // no fields found, bail out |
||
| 353 | continue; |
||
| 354 | } |
||
| 355 | $parent_field_id = current($fields)->get('id'); |
||
| 356 | // create association |
||
| 357 | SectionManager::createSectionAssociation( |
||
| 358 | $parent_section_id, |
||
| 359 | $child_field_id, |
||
| 360 | $parent_field_id, |
||
| 361 | $this->get('show_association') == 'yes' |
||
| 362 | ); |
||
| 363 | } |
||
| 364 | |||
| 365 | // declare an array contains the field's settings |
||
| 366 | $settings = array( |
||
| 367 | 'sections' => $this->get('sections'), |
||
| 368 | 'show_association' => $this->get('show_association'), |
||
| 369 | 'deepness' => $this->get('deepness'), |
||
| 370 | 'elements' => $this->get('elements'), |
||
| 371 | 'mode' => $this->get('mode'), |
||
| 372 | 'mode_table' => $this->get('mode_table'), |
||
| 373 | 'mode_header' => $this->get('mode_header'), |
||
| 374 | 'mode_footer' => $this->get('mode_footer'), |
||
| 375 | 'min_entries' => $this->get('min_entries'), |
||
| 376 | 'max_entries' => $this->get('max_entries'), |
||
| 377 | 'allow_new' => $this->get('allow_new'), |
||
| 378 | 'allow_edit' => $this->get('allow_edit'), |
||
| 379 | 'allow_link' => $this->get('allow_link'), |
||
| 380 | 'allow_delete' => $this->get('allow_delete'), |
||
| 381 | 'allow_collapse' => $this->get('allow_collapse'), |
||
| 382 | 'allow_search' => $this->get('allow_search'), |
||
| 383 | 'show_header' => $this->get('show_header'), |
||
| 384 | ); |
||
| 385 | |||
| 386 | return FieldManager::saveSettings($id, $settings); |
||
| 387 | } |
||
| 388 | |||
| 389 | /** |
||
| 390 | * |
||
| 391 | * This function allows Fields to cleanup any additional things before it is removed |
||
| 392 | * from the section. |
||
| 393 | * @return boolean |
||
| 394 | */ |
||
| 395 | public function tearDown() |
||
| 396 | { |
||
| 397 | self::removeSectionAssociation($this->get('id')); |
||
| 398 | return parent::tearDown(); |
||
| 399 | } |
||
| 400 | |||
| 401 | /** |
||
| 402 | * Generates the where filter for searching by entry id |
||
| 403 | * |
||
| 404 | * @param string $value |
||
| 405 | * @param @optional string $col |
||
| 406 | */ |
||
| 407 | public function generateWhereFilter($value, $col = 'd') |
||
| 408 | { |
||
| 409 | $junction = $andOperation ? 'and' : 'or'; |
||
|
|
|||
| 410 | |||
| 411 | if (!$value) { |
||
| 412 | return [ |
||
| 413 | $junction => [ |
||
| 414 | [$col . '.entries' => null], |
||
| 415 | ], |
||
| 416 | ]; |
||
| 417 | } |
||
| 418 | |||
| 419 | return [ |
||
| 420 | 'or' => [ |
||
| 421 | [$col . '.entries' => $value], |
||
| 422 | [$col . '.entries' => ['like' => $value . ',%']], |
||
| 423 | [$col . '.entries' => ['like' => '%,' . $value]], |
||
| 424 | [$col . '.entries' => ['like' => '%,' . $value . ',%']], |
||
| 425 | ] |
||
| 426 | ]; |
||
| 427 | } |
||
| 428 | |||
| 429 | /** |
||
| 430 | * Fetch the number of associated entries for a particular entry id |
||
| 431 | * |
||
| 432 | * @param string $value |
||
| 433 | */ |
||
| 434 | public function fetchAssociatedEntryCount($value) |
||
| 435 | { |
||
| 436 | if (!$value) { |
||
| 437 | return 0; |
||
| 438 | } |
||
| 439 | |||
| 440 | $where = $this->generateWhereFilter($value); |
||
| 441 | |||
| 442 | $entries = Symphony::Database() |
||
| 443 | ->select(['e.id']) |
||
| 444 | ->from('tbl_entries', 'e') |
||
| 445 | ->innerJoin('tbl_entries_data_' . $this->get('id'), 'd') |
||
| 446 | ->on(['e.id' => '$d.entry_id']) |
||
| 447 | ->where(['e.section_id' => $this->get('parent_section')]) |
||
| 448 | ->where($where) |
||
| 449 | ->execute() |
||
| 450 | ->rows(); |
||
| 451 | |||
| 452 | return count($entries); |
||
| 453 | } |
||
| 454 | |||
| 455 | public function fetchAssociatedEntrySearchValue($data, $field_id = null, $parent_entry_id = null) |
||
| 456 | { |
||
| 457 | return $parent_entry_id; |
||
| 458 | } |
||
| 459 | |||
| 460 | public function findRelatedEntries($entry_id, $parent_field_id) |
||
| 461 | { |
||
| 462 | $entries = $this->entryManager |
||
| 463 | ->select() |
||
| 464 | ->section($this->get('parent_section')) |
||
| 465 | ->filter($this->get('id'), [(string)$entry_id]) |
||
| 466 | ->schema(['id']) |
||
| 467 | ->execute() |
||
| 468 | ->rows(); |
||
| 469 | |||
| 470 | return array_map(function ($e) { |
||
| 471 | return $e['id']; |
||
| 472 | }, $entries); |
||
| 473 | } |
||
| 474 | |||
| 475 | public function findParentRelatedEntries($parent_field_id, $entry_id) |
||
| 476 | { |
||
| 477 | $entry = $this->entryManager |
||
| 478 | ->select() |
||
| 479 | ->entry($entry_id) |
||
| 480 | ->section($this->entryManager->fetchEntrySectionID($entry_id)) |
||
| 481 | ->includeAllFields() |
||
| 482 | ->schema(array($this->get('label'))) |
||
| 483 | ->execute() |
||
| 484 | ->next(); |
||
| 485 | |||
| 486 | if (!$entry) { |
||
| 487 | return array(); |
||
| 488 | } |
||
| 489 | |||
| 490 | return self::getEntries($entry->getData($this->get('id'))); |
||
| 491 | } |
||
| 492 | |||
| 493 | public function fetchFilterableOperators() |
||
| 494 | { |
||
| 495 | return array( |
||
| 496 | array( |
||
| 497 | 'title' => 'links to', |
||
| 498 | 'filter' => ' ', |
||
| 499 | 'help' => __('Find entries that links to the specified filter') |
||
| 500 | ), |
||
| 501 | array( |
||
| 502 | 'filter' => 'sql: NOT NULL', |
||
| 503 | 'title' => 'is not empty', |
||
| 504 | 'help' => __('Find entries with a non-empty value.') |
||
| 505 | ), |
||
| 506 | array( |
||
| 507 | 'filter' => 'sql: NULL', |
||
| 508 | 'title' => 'is empty', |
||
| 509 | 'help' => __('Find entries with an empty value.') |
||
| 510 | ), |
||
| 511 | array( |
||
| 512 | 'title' => 'contains', |
||
| 513 | 'filter' => 'regexp: ', |
||
| 514 | 'help' => __('Find values that match the given <a href="%s">MySQL regular expressions</a>.', array( |
||
| 515 | 'https://dev.mysql.com/doc/mysql/en/regexp.html' |
||
| 516 | )) |
||
| 517 | ), |
||
| 518 | array( |
||
| 519 | 'title' => 'does not contain', |
||
| 520 | 'filter' => 'not-regexp: ', |
||
| 521 | 'help' => __('Find values that do not match the given <a href="%s">MySQL regular expressions</a>.', array( |
||
| 522 | 'https://dev.mysql.com/doc/mysql/en/regexp.html' |
||
| 523 | )) |
||
| 524 | ), |
||
| 525 | ); |
||
| 526 | } |
||
| 527 | |||
| 528 | public function fetchSuggestionTypes() |
||
| 529 | { |
||
| 530 | return array('association'); |
||
| 531 | } |
||
| 532 | |||
| 533 | public function fetchIDsfromValue($value) |
||
| 534 | { |
||
| 535 | $ids = array(); |
||
| 536 | $sections = $this->getArray('sections'); |
||
| 537 | |||
| 538 | foreach ($sections as $sectionId) { |
||
| 539 | $section = $this->sectionManager |
||
| 540 | ->select() |
||
| 541 | ->section($sectionId) |
||
| 542 | ->execute() |
||
| 543 | ->next(); |
||
| 544 | |||
| 545 | if (!$section) { |
||
| 546 | continue; |
||
| 547 | } |
||
| 548 | $filterableFields = $section->fetchFilterableFields(); |
||
| 549 | if (empty($filterableFields)) { |
||
| 550 | continue; |
||
| 551 | } |
||
| 552 | foreach ($filterableFields as $fId => $field) { |
||
| 553 | if ($field instanceof FieldRelationship) { |
||
| 554 | continue; |
||
| 555 | } |
||
| 556 | $fEntries = (new EntryManager) |
||
| 557 | ->select(['e.id']) |
||
| 558 | ->section($sectionId) |
||
| 559 | ->filter($fId, [$value]) |
||
| 560 | ->execute() |
||
| 561 | ->rows(); |
||
| 562 | |||
| 563 | if (!empty($fEntries)) { |
||
| 564 | $ids = array_merge($ids, $fEntries); |
||
| 565 | break; |
||
| 566 | } |
||
| 567 | } |
||
| 568 | } |
||
| 569 | |||
| 570 | return array_map(function ($e) { |
||
| 571 | return $e['id']; |
||
| 572 | }, $ids); |
||
| 573 | } |
||
| 574 | |||
| 575 | public function prepareAssociationsDrawerXMLElement(Entry $e, array $parent_association, $prepolutate = '') |
||
| 576 | { |
||
| 577 | $currentSection = $this->sectionManager |
||
| 578 | ->select() |
||
| 579 | ->section($parent_association['child_section_id']) |
||
| 580 | ->execute() |
||
| 581 | ->next(); |
||
| 582 | $visibleCols = $currentSection->fetchVisibleColumns(); |
||
| 583 | $outputFieldId = current($visibleCols)->get('id'); |
||
| 584 | $outputField = $this->fieldManager |
||
| 585 | ->select() |
||
| 586 | ->field($outputFieldId) |
||
| 587 | ->execute() |
||
| 588 | ->next(); |
||
| 589 | |||
| 590 | $value = $outputField->prepareReadableValue($e->getData($outputFieldId), $e->get('id'), true, __('None')); |
||
| 591 | |||
| 592 | $li = new XMLElement('li'); |
||
| 593 | $li->setAttribute('class', 'field-' . $this->get('type')); |
||
| 594 | $a = new XMLElement('a', strip_tags($value)); |
||
| 595 | $a->setAttribute('href', SYMPHONY_URL . '/publish/' . $parent_association['handle'] . '/edit/' . $e->get('id') . '/'); |
||
| 596 | $li->appendChild($a); |
||
| 597 | |||
| 598 | return $li; |
||
| 599 | } |
||
| 600 | |||
| 601 | /* ******* EVENTS ******* */ |
||
| 602 | |||
| 603 | public function getExampleFormMarkup() |
||
| 604 | { |
||
| 605 | $label = Widget::Label($this->get('label')); |
||
| 606 | $label->appendChild(Widget::Input('fields['.$this->get('element_name').'][entries]', null, 'hidden')); |
||
| 607 | |||
| 608 | return $label; |
||
| 609 | } |
||
| 610 | |||
| 611 | |||
| 612 | /* ******* DATA SOURCE ******* */ |
||
| 613 | |||
| 614 | private function fetchEntryWithData($eId, $sectionId, $elements = array()) |
||
| 615 | { |
||
| 616 | $q = $this->entryManager |
||
| 617 | ->select() |
||
| 618 | ->entry($eId) |
||
| 619 | ->section($sectionId); |
||
| 620 | if ($elements === null) { |
||
| 621 | $q->includeAllFields(); |
||
| 622 | } else { |
||
| 623 | $q->schema($elements); |
||
| 624 | } |
||
| 625 | return $q->execute() |
||
| 626 | ->next(); |
||
| 627 | } |
||
| 628 | |||
| 629 | private function fetchEntryOnly($eId) |
||
| 630 | { |
||
| 631 | return $this->entryManager |
||
| 632 | ->select() |
||
| 633 | ->entry($eId) |
||
| 634 | ->execute() |
||
| 635 | ->next(); |
||
| 636 | } |
||
| 637 | |||
| 638 | protected function fetchAllIncludableElements() |
||
| 639 | { |
||
| 640 | $sections = $this->getArray('sections'); |
||
| 641 | return $allElements = array_reduce($this->sectionInfos->fetch($sections), function ($memo, $item) { |
||
| 642 | return array_merge($memo, array_map(function ($field) use ($item) { |
||
| 643 | return $item['handle'] . '.' . $field['handle']; |
||
| 644 | }, $item['fields'])); |
||
| 645 | }, array()); |
||
| 646 | } |
||
| 647 | |||
| 648 | public function fetchIncludableElements() |
||
| 649 | { |
||
| 650 | $label = $this->get('element_name'); |
||
| 651 | $elements = $this->getArray('elements'); |
||
| 652 | if (empty($elements)) { |
||
| 653 | $elements = array('*'); |
||
| 654 | } |
||
| 655 | $includedElements = array(); |
||
| 656 | // Include everything |
||
| 657 | if ($this->expandIncludableElements) { |
||
| 658 | $includedElements[] = $label . ': *'; |
||
| 659 | } |
||
| 660 | // Include individual elements |
||
| 661 | foreach ($elements as $elem) { |
||
| 662 | $elem = trim($elem); |
||
| 663 | if ($elem !== '*') { |
||
| 664 | $includedElements[] = $label . ': ' . $elem; |
||
| 665 | } else if ($this->expandIncludableElements) { |
||
| 666 | $includedElements = array_unique(array_merge($includedElements, array_map(function ($item) use ($label) { |
||
| 667 | return $label . ': ' . $item; |
||
| 668 | }, $this->fetchAllIncludableElements()))); |
||
| 669 | } else { |
||
| 670 | $includedElements = array('*'); |
||
| 671 | } |
||
| 672 | } |
||
| 673 | return $includedElements; |
||
| 674 | } |
||
| 675 | |||
| 676 | /** |
||
| 677 | * Appends data into the XML tree of a Data Source |
||
| 678 | * @param $wrapper |
||
| 679 | * @param $data |
||
| 680 | */ |
||
| 681 | public function appendFormattedElement(XMLElement &$wrapper, $data, $encode = false, $mode = null, $entry_id = null) |
||
| 682 | { |
||
| 683 | if (!is_array($data) || empty($data)) { |
||
| 684 | return; |
||
| 685 | } |
||
| 686 | |||
| 687 | // try to find an existing root |
||
| 688 | $root = null; |
||
| 689 | $newRoot = false; |
||
| 690 | foreach (array_reverse($wrapper->getChildren()) as $xmlField) { |
||
| 691 | if ($xmlField->getName() === $this->get('element_name')) { |
||
| 692 | $root = $xmlField; |
||
| 693 | break; |
||
| 694 | } |
||
| 695 | } |
||
| 696 | |||
| 697 | // root was not found, create one |
||
| 698 | if (!$root) { |
||
| 699 | $root = new XMLElement($this->get('element_name')); |
||
| 700 | $newRoot = true; |
||
| 701 | } |
||
| 702 | |||
| 703 | // devkit will load |
||
| 704 | $devkit = isset($_GET['debug']) && (empty($_GET['debug']) || $_GET['debug'] == 'xml'); |
||
| 705 | |||
| 706 | // selected items |
||
| 707 | $entries = static::getEntries($data); |
||
| 708 | |||
| 709 | // current linked entries |
||
| 710 | $root->setAttribute('entries', $data['entries']); |
||
| 711 | |||
| 712 | // available sections |
||
| 713 | $root->setAttribute('sections', $this->get('sections')); |
||
| 714 | |||
| 715 | // included elements |
||
| 716 | $elements = static::parseElements($this); |
||
| 717 | |||
| 718 | // DS mode |
||
| 719 | if (!$mode) { |
||
| 720 | $mode = '*'; |
||
| 721 | } |
||
| 722 | |||
| 723 | $parentDeepness = General::intval($this->recursiveDeepness); |
||
| 724 | $deepness = General::intval($this->get('deepness')); |
||
| 725 | |||
| 726 | // both deepnesses are defined and parent restricts more |
||
| 727 | if ($parentDeepness > 0 && $deepness > 0 && $parentDeepness < $deepness) { |
||
| 728 | $deepness = $parentDeepness; |
||
| 729 | } |
||
| 730 | // parent is defined, current is not |
||
| 731 | else if ($parentDeepness > 0 && $deepness < 1) { |
||
| 732 | $deepness = $parentDeepness; |
||
| 733 | } |
||
| 734 | |||
| 735 | // cache recursive level because recursion might |
||
| 736 | // change its value later on. |
||
| 737 | $recursiveLevel = $this->recursiveLevel; |
||
| 738 | |||
| 739 | // build entries |
||
| 740 | foreach ($entries as $eId) { |
||
| 741 | // try to find and existing item |
||
| 742 | // TODO: keep last index found since it should be the next |
||
| 743 | $item = null; |
||
| 744 | $newItem = false; |
||
| 745 | foreach ($root->getChildren() as $xmlItem) { |
||
| 746 | if (General::intval($xmlItem->getAttribute('id')) === General::intval($eId)) { |
||
| 747 | $item = $xmlItem; |
||
| 748 | break; |
||
| 749 | } |
||
| 750 | } |
||
| 751 | |||
| 752 | // item was not found, create one |
||
| 753 | if (!$item) { |
||
| 754 | $item = new XMLElement('item'); |
||
| 755 | $item->setAllowEmptyAttributes(false); |
||
| 756 | // output id |
||
| 757 | $item->setAttribute('id', $eId); |
||
| 758 | // output recursive level |
||
| 759 | $item->setAttribute('level', $recursiveLevel); |
||
| 760 | $item->setAttribute('max-level', $deepness); |
||
| 761 | $newItem = true; |
||
| 762 | // item was found, but it is an error, so we can skip it |
||
| 763 | } else if ($item->getName() === 'error') { |
||
| 764 | continue; |
||
| 765 | } |
||
| 766 | |||
| 767 | // max recursion check |
||
| 768 | if ($deepness < 1 || $recursiveLevel < $deepness) { |
||
| 769 | // current entry, without data |
||
| 770 | $entry = $this->fetchEntryOnly($eId); |
||
| 771 | |||
| 772 | // entry not found... |
||
| 773 | if (!$entry || empty($entry)) { |
||
| 774 | $error = new XMLElement('error'); |
||
| 775 | $error->setAttribute('id', $eId); |
||
| 776 | $error->setValue(__('Error: entry `%s` not found', array($eId))); |
||
| 777 | $root->prependChild($error); |
||
| 778 | continue; |
||
| 779 | } |
||
| 780 | |||
| 781 | // fetch section infos |
||
| 782 | $sectionId = $entry->get('section_id'); |
||
| 783 | $section = $this->sectionManager |
||
| 784 | ->select() |
||
| 785 | ->section($sectionId) |
||
| 786 | ->execute() |
||
| 787 | ->next(); |
||
| 788 | $sectionName = $section->get('handle'); |
||
| 789 | |||
| 790 | // set section related attributes |
||
| 791 | $item->setAttribute('section-id', $sectionId); |
||
| 792 | $item->setAttribute('section', $sectionName); |
||
| 793 | |||
| 794 | // Get the valid elements for this section only |
||
| 795 | $validElements = $elements[$sectionName]; |
||
| 796 | |||
| 797 | // adjust the mode for the current section |
||
| 798 | $curMode = $mode; |
||
| 799 | |||
| 800 | // remove section name from current mode so "sectionName.field" becomes simply "field" |
||
| 801 | if (preg_match('/^(' . $sectionName . '\.)(.*)$/sU', $curMode)) { |
||
| 802 | $curMode = preg_replace('/^' . $sectionName . '\./sU', '', $curMode); |
||
| 803 | } |
||
| 804 | // remove section name from current mode "sectionName" and |
||
| 805 | // treat it like if it is "sectionName: *" |
||
| 806 | else if (preg_match('/^(' . $sectionName . ')$/sU', $curMode)) { |
||
| 807 | $curMode = '*'; |
||
| 808 | } |
||
| 809 | // section name was not found in mode, check if the mode is "*" |
||
| 810 | else if ($curMode != '*') { |
||
| 811 | // mode forbids this section |
||
| 812 | $validElements = null; |
||
| 813 | } |
||
| 814 | |||
| 815 | // this section is not selected, bail out |
||
| 816 | View Code Duplication | if (!is_array($validElements)) { |
|
| 817 | if ($newItem) { |
||
| 818 | if ($devkit) { |
||
| 819 | $item->setAttribute('x-forbidden-by-ds', $curMode); |
||
| 820 | } |
||
| 821 | $root->appendChild($item); |
||
| 822 | } |
||
| 823 | continue; |
||
| 824 | } else { |
||
| 825 | if ($devkit) { |
||
| 826 | $item->setAttribute('x-forbidden-by-ds', null); |
||
| 827 | } |
||
| 828 | } |
||
| 829 | |||
| 830 | // selected fields for fetching |
||
| 831 | $sectionElements = array(); |
||
| 832 | |||
| 833 | // everything is allowed |
||
| 834 | if (in_array('*', $validElements)) { |
||
| 835 | if ($curMode !== '*') { |
||
| 836 | // get only the mode |
||
| 837 | $sectionElements = array($curMode); |
||
| 838 | } |
||
| 839 | else { |
||
| 840 | // setting null = get all |
||
| 841 | $sectionElements = null; |
||
| 842 | } |
||
| 843 | } |
||
| 844 | // only use valid elements |
||
| 845 | else { |
||
| 846 | if ($curMode !== '*') { |
||
| 847 | // is this field allowed ? |
||
| 848 | if (self::isFieldIncluded($curMode, $validElements)) { |
||
| 849 | // get only the mode |
||
| 850 | $sectionElements = array($curMode); |
||
| 851 | } |
||
| 852 | else { |
||
| 853 | // $curMode selects something outside of |
||
| 854 | // the valid elements: select nothing |
||
| 855 | $sectionElements = array(); |
||
| 856 | } |
||
| 857 | } |
||
| 858 | else { |
||
| 859 | // use field's valid elements |
||
| 860 | $sectionElements = $validElements; |
||
| 861 | } |
||
| 862 | } |
||
| 863 | |||
| 864 | // Filtering is enabled, but nothing is selected |
||
| 865 | View Code Duplication | if (is_array($sectionElements) && empty($sectionElements)) { |
|
| 866 | if ($newItem) { |
||
| 867 | $root->appendChild($item); |
||
| 868 | if ($devkit) { |
||
| 869 | $item->setAttribute('x-forbidden-by-selection', $curMode); |
||
| 870 | } |
||
| 871 | } |
||
| 872 | continue; |
||
| 873 | } else { |
||
| 874 | if ($devkit) { |
||
| 875 | $item->setAttribute('x-forbidden-by-selection', null); |
||
| 876 | } |
||
| 877 | } |
||
| 878 | |||
| 879 | // fetch current entry again, but with data for the allowed schema |
||
| 880 | $entry = $this->fetchEntryWithData($eId, $sectionId, $sectionElements); |
||
| 881 | |||
| 882 | // cache the entry data |
||
| 883 | $entryData = $entry->getData(); |
||
| 884 | |||
| 885 | // for each field returned for this entry... |
||
| 886 | foreach ($entryData as $fieldId => $data) { |
||
| 887 | $filteredData = array_filter($data, function ($value) { |
||
| 888 | return $value != null; |
||
| 889 | }); |
||
| 890 | |||
| 891 | if (empty($filteredData)) { |
||
| 892 | continue; |
||
| 893 | } |
||
| 894 | |||
| 895 | $field = $this->fieldManager |
||
| 896 | ->select() |
||
| 897 | ->field($fieldId) |
||
| 898 | ->execute() |
||
| 899 | ->next(); |
||
| 900 | $fieldName = $field->get('element_name'); |
||
| 901 | $fieldCurMode = self::extractMode($fieldName, $curMode); |
||
| 902 | |||
| 903 | $parentIncludableElement = self::getSectionElementName($fieldName, $validElements); |
||
| 904 | $parentIncludableElementMode = self::extractMode($fieldName, $parentIncludableElement); |
||
| 905 | |||
| 906 | // Special treatments for ERF |
||
| 907 | if ($field instanceof FieldEntry_relationship) { |
||
| 908 | // Increment recursive level |
||
| 909 | $field->recursiveLevel = $recursiveLevel + 1; |
||
| 910 | $field->recursiveDeepness = $deepness; |
||
| 911 | } |
||
| 912 | |||
| 913 | $submodes = null; |
||
| 914 | // Parent mode is not defined (we are selecting the whole section) |
||
| 915 | if ($parentIncludableElementMode === null) { |
||
| 916 | if ($fieldCurMode == null) { |
||
| 917 | // Field does not defined a mode either: use the field's default |
||
| 918 | $submodes = null; |
||
| 919 | } else { |
||
| 920 | // Use the current field's mode |
||
| 921 | $submodes = array($fieldCurMode); |
||
| 922 | } |
||
| 923 | if ($devkit) { |
||
| 924 | $item->setAttribute('x-selection-mode-empty', null); |
||
| 925 | } |
||
| 926 | } else { |
||
| 927 | // Field mode is not defined or it is the same as the parent |
||
| 928 | if ($fieldCurMode === null || $fieldCurMode == $parentIncludableElementMode) { |
||
| 929 | if ($devkit) { |
||
| 930 | $item->setAttribute('x-selection-mode-empty', null); |
||
| 931 | } |
||
| 932 | // Use parent mode |
||
| 933 | $submodes = array($parentIncludableElementMode); |
||
| 934 | } else { |
||
| 935 | if ($devkit) { |
||
| 936 | $item->setAttribute('x-selection-mode-empty', 'yes'); |
||
| 937 | } |
||
| 938 | // Empty selection |
||
| 939 | $submodes = array(); |
||
| 940 | } |
||
| 941 | } |
||
| 942 | |||
| 943 | // current selection does not specify a mode |
||
| 944 | if ($submodes === null) { |
||
| 945 | if ($field instanceof FieldEntry_Relationship) { |
||
| 946 | $field->expandIncludableElements = false; |
||
| 947 | } |
||
| 948 | $submodes = array_map(function ($fieldIncludableElement) use ($fieldName) { |
||
| 949 | return FieldEntry_relationship::extractMode($fieldName, $fieldIncludableElement); |
||
| 950 | }, $field->fetchIncludableElements()); |
||
| 951 | if ($field instanceof FieldEntry_Relationship) { |
||
| 952 | $field->expandIncludableElements = true; |
||
| 953 | } |
||
| 954 | } |
||
| 955 | |||
| 956 | // Append the formatted element for each requested mode |
||
| 957 | foreach ($submodes as $submode) { |
||
| 958 | $field->appendFormattedElement($item, $data, $encode, $submode, $eId); |
||
| 959 | } |
||
| 960 | } |
||
| 961 | // output current mode |
||
| 962 | $item->setAttribute('matched-element', $curMode); |
||
| 963 | // no field selected |
||
| 964 | if (is_array($sectionElements) && empty($sectionElements)) { |
||
| 965 | $item->setAttribute('empty-selection', 'yes'); |
||
| 966 | } |
||
| 967 | } // end max recursion check |
||
| 968 | |||
| 969 | if ($newItem) { |
||
| 970 | // append item when done |
||
| 971 | $root->appendChild($item); |
||
| 972 | } |
||
| 973 | } // end each entries |
||
| 974 | |||
| 975 | if ($newRoot) { |
||
| 976 | // output mode for this field |
||
| 977 | if ($devkit) { |
||
| 978 | $root->setAttribute('x-data-source-mode', $mode); |
||
| 979 | $root->setAttribute('x-field-included-elements', $this->get('elements')); |
||
| 980 | } |
||
| 981 | |||
| 982 | // add all our data to the wrapper; |
||
| 983 | $wrapper->appendChild($root); |
||
| 984 | } else { |
||
| 985 | if ($devkit) { |
||
| 986 | $root->setAttribute('x-data-source-mode', $root->getAttribute('x-data-source-mode') . ', ' . $mode); |
||
| 987 | } |
||
| 988 | } |
||
| 989 | |||
| 990 | // clean up |
||
| 991 | $this->recursiveLevel = 1; |
||
| 992 | $this->recursiveDeepness = null; |
||
| 993 | } |
||
| 994 | |||
| 995 | public function getParameterPoolValue(array $data, $entry_id = null) |
||
| 1000 | |||
| 1001 | /* ********* Utils *********** */ |
||
| 1002 | |||
| 1003 | /** |
||
| 1004 | * Return true if $fieldName is allowed in $sectionElements |
||
| 1005 | * @param string $fieldName |
||
| 1006 | * @param string $sectionElements |
||
| 1007 | * @return bool |
||
| 1008 | */ |
||
| 1009 | public static function isFieldIncluded($fieldName, $sectionElements) |
||
| 1013 | |||
| 1014 | public static function getSectionElementName($fieldName, $sectionElements) |
||
| 1034 | |||
| 1035 | public static function parseElements($field) |
||
| 1036 | { |
||
| 1037 | $elements = array(); |
||
| 1038 | $exElements = $field->getArray('elements'); |
||
| 1039 | |||
| 1040 | |||
| 1041 | if (in_array('*', $exElements)) { |
||
| 1042 | $sections = $field->getArray('sections'); |
||
| 1043 | $sm = new SectionManager; |
||
| 1044 | $sections = $sm |
||
| 1045 | ->select() |
||
| 1046 | ->sections($sections) |
||
| 1047 | ->execute() |
||
| 1048 | ->rows(); |
||
| 1049 | return array_reduce($sections, function ($result, $section) { |
||
| 1050 | $result[$section->get('handle')] = array('*'); |
||
| 1051 | return $result; |
||
| 1052 | }, array()); |
||
| 1053 | } |
||
| 1054 | |||
| 1055 | foreach ($exElements as $value) { |
||
| 1056 | if (!$value) { |
||
| 1057 | continue; |
||
| 1058 | } |
||
| 1059 | // sectionName.fieldName or sectionName.* |
||
| 1060 | $parts = array_map('trim', explode('.', $value, 2)); |
||
| 1061 | // first time seeing this section |
||
| 1062 | if (!isset($elements[$parts[0]])) { |
||
| 1063 | $elements[$parts[0]] = array(); |
||
| 1064 | } |
||
| 1065 | // we have a value after the dot |
||
| 1077 | |||
| 1078 | public static function extractMode($fieldName, $mode) |
||
| 1090 | |||
| 1091 | private function buildSectionSelect($name) |
||
| 1109 | |||
| 1110 | View Code Duplication | private function appendSelectionSelect(&$wrapper) |
|
| 1124 | |||
| 1125 | private function createEntriesHiddenInput($data) |
||
| 1135 | |||
| 1136 | private function createActionBarMenu($sections) |
||
| 1204 | |||
| 1205 | /* ********* UI *********** */ |
||
| 1206 | |||
| 1207 | /** |
||
| 1208 | * |
||
| 1209 | * Builds the UI for the field's settings when creating/editing a section |
||
| 1210 | * @param XMLElement $wrapper |
||
| 1211 | * @param array $errors |
||
| 1212 | */ |
||
| 1213 | public function displaySettingsPanel(XMLElement &$wrapper, $errors = null) |
||
| 1345 | |||
| 1346 | /** |
||
| 1347 | * |
||
| 1348 | * Builds the UI for the publish page |
||
| 1349 | * @param XMLElement $wrapper |
||
| 1350 | * @param mixed $data |
||
| 1351 | * @param mixed $flagWithError |
||
| 1352 | * @param string $fieldnamePrefix |
||
| 1353 | * @param string $fieldnamePostfix |
||
| 1354 | */ |
||
| 1355 | public function displayPublishPanel(XMLElement &$wrapper, $data = null, $flagWithError = null, $fieldnamePrefix = null, $fieldnamePostfix = null, $entry_id = null) |
||
| 1417 | |||
| 1418 | /** |
||
| 1419 | * |
||
| 1420 | * Return a plain text representation of the field's data |
||
| 1421 | * @param array $data |
||
| 1422 | * @param int $entry_id |
||
| 1423 | */ |
||
| 1424 | public function prepareTextValue($data, $entry_id = null) |
||
| 1431 | |||
| 1432 | /** |
||
| 1433 | * Format this field value for display as readable text value. |
||
| 1434 | * |
||
| 1435 | * @param array $data |
||
| 1436 | * an associative array of data for this string. At minimum this requires a |
||
| 1437 | * key of 'value'. |
||
| 1438 | * @param integer $entry_id (optional) |
||
| 1439 | * An option entry ID for more intelligent processing. Defaults to null. |
||
| 1440 | * @param string $defaultValue (optional) |
||
| 1441 | * The value to use when no plain text representation of the field's data |
||
| 1442 | * can be made. Defaults to null. |
||
| 1443 | * @return string |
||
| 1444 | * the readable text summary of the values of this field instance. |
||
| 1445 | */ |
||
| 1446 | public function prepareReadableValue($data, $entry_id = null, $truncate = false, $defaultValue = 'None') |
||
| 1470 | |||
| 1471 | /** |
||
| 1472 | * Format this field value for display in the publish index tables. |
||
| 1473 | * |
||
| 1474 | * @param array $data |
||
| 1475 | * an associative array of data for this string. At minimum this requires a |
||
| 1476 | * key of 'value'. |
||
| 1477 | * @param XMLElement $link (optional) |
||
| 1478 | * an XML link structure to append the content of this to provided it is not |
||
| 1479 | * null. it defaults to null. |
||
| 1480 | * @param integer $entry_id (optional) |
||
| 1481 | * An option entry ID for more intelligent processing. defaults to null |
||
| 1482 | * @return string |
||
| 1483 | * the formatted string summary of the values of this field instance. |
||
| 1484 | */ |
||
| 1485 | public function prepareTableValue($data, XMLElement $link = null, $entry_id = null) |
||
| 1528 | |||
| 1529 | /* ********* SQL Data Definition ************* */ |
||
| 1530 | |||
| 1531 | /** |
||
| 1532 | * |
||
| 1533 | * Creates table needed for entries of individual fields |
||
| 1534 | */ |
||
| 1535 | public function createTable() |
||
| 1558 | |||
| 1559 | /** |
||
| 1560 | * Creates the table needed for the settings of the field |
||
| 1561 | */ |
||
| 1562 | public static function createFieldTable() |
||
| 1657 | |||
| 1658 | public static function update_102() |
||
| 1713 | |||
| 1714 | View Code Duplication | public static function update_103() |
|
| 1729 | |||
| 1730 | public static function update_200() |
||
| 1778 | |||
| 1779 | View Code Duplication | public static function update_2008() |
|
| 1794 | |||
| 1795 | /** |
||
| 1796 | * |
||
| 1797 | * Drops the table needed for the settings of the field |
||
| 1798 | */ |
||
| 1799 | public static function deleteFieldTable() |
||
| 1807 | |||
| 1808 | private static function removeSectionAssociation($child_field_id) |
||
| 1816 | } |
||
| 1817 |
This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.