From 9c07d69c4587c551fe988475b7ee3fd6d78c4d3a Mon Sep 17 00:00:00 2001 From: nazwa Date: Tue, 24 Nov 2015 23:02:42 +0000 Subject: [PATCH 1/3] Proper handling of list fields Moved field handling to a separate function and added logic to correctly process nested lists. --- system/src/Grav/Common/Data/Blueprint.php | 178 ++++++++++++---------- 1 file changed, 101 insertions(+), 77 deletions(-) diff --git a/system/src/Grav/Common/Data/Blueprint.php b/system/src/Grav/Common/Data/Blueprint.php index 6f0c71e50..aefd1b75c 100644 --- a/system/src/Grav/Common/Data/Blueprint.php +++ b/system/src/Grav/Common/Data/Blueprint.php @@ -314,91 +314,115 @@ class Blueprint implements \ArrayAccess, ExportInterface } /** - * Gets all field definitions from the blueprints. - * - * @param array $fields - * @param array $params - * @param string $prefix - * @param array $current - * @internal - */ - protected function parseFormFields(array &$fields, $params, $prefix, array &$current) - { - // Go though all the fields in current level. - foreach ($fields as $key => &$field) { - $current[$key] = &$field; - // Set name from the array key. - $field['name'] = $prefix . $key; - $field += $params; + * Gets all field definitions from the blueprints. + * + * @param array $fields + * @param array $params + * @param string $prefix + * @param array $current + * @internal + */ + protected function parseFormFields(array &$fields, $params, $prefix, array &$current) + { + // Go though all the fields in current level. + foreach ($fields as $key => &$field) { + $current[$key] = &$field; + // Set name from the array key. + $field['name'] = $prefix . $key; + $field += $params; - if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) { - // Recursively get all the nested fields. - $newParams = array_intersect_key($this->filter, $field); - $this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']); - } else if ($field['type'] !== 'ignore') { - // Add rule. + if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) { + // Recursively get all the nested fields. + $newParams = array_intersect_key($this->filter, $field); + $this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']); + } else if( $field['type'] === 'list') { + // Lists have different structure for fields (one level deeper) + // This means we need to loop through the list to get to the actual field + // The property and rule setting need to be set on the list field + // and NOT on the children, which is why we need to duplicate some of + // the code below :( + + $this->rules[$prefix . $key] = &$field; + $this->addProperty($prefix . $key); + + foreach($field['fields'] as $subName => &$subField) { + $this->parseFormField($subField, $prefix, $key, false); + } + + if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') { + $field['validate'] += $this->getRule($field['validate']['rule']); + } + } else if ($field['type'] !== 'ignore') { $this->rules[$prefix . $key] = &$field; - $this->addProperty($prefix . $key); + $this->addProperty($prefix . $key); - foreach ($field as $name => $value) { - // Support nested blueprints. - if ($this->context && $name == '@import') { - $values = (array) $value; - if (!isset($field['fields'])) { - $field['fields'] = array(); - } - foreach ($values as $bname) { - $b = $this->context->get($bname); - $field['fields'] = array_merge($field['fields'], $b->fields()); - } - } + $this->parseFormField($field, $prefix, $key, true); - // Support for callable data values. - elseif (substr($name, 0, 6) == '@data-') { - $property = substr($name, 6); - if (is_array($value)) { - $func = array_shift($value); - } else { - $func = $value; - $value = array(); - } - list($o, $f) = preg_split('/::/', $func); - if (!$f && function_exists($o)) { - $data = call_user_func_array($o, $value); - } elseif ($f && method_exists($o, $f)) { - $data = call_user_func_array(array($o, $f), $value); - } + if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') { + $field['validate'] += $this->getRule($field['validate']['rule']); + } + } + } + } + /** + * Parses individual field definition + * + * @param array $field + * @internal + */ + protected function parseFormField(&$field) { + foreach ($field as $name => $value) { + // Support nested blueprints. + if ($this->context && $name == '@import') { + $values = (array) $value; + if (!isset($field['fields'])) { + $field['fields'] = array(); + } + foreach ($values as $bname) { + $b = $this->context->get($bname); + $field['fields'] = array_merge($field['fields'], $b->fields()); + } + } - // If function returns a value, - if (isset($data)) { - if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) { - // Combine field and @data-field together. - $field[$property] += $data; - } else { - // Or create/replace field with @data-field. - $field[$property] = $data; - } - } - } + // Support for callable data values. + elseif (substr($name, 0, 6) == '@data-') { + $property = substr($name, 6); + if (is_array($value)) { + $func = array_shift($value); + } else { + $func = $value; + $value = array(); + } + list($o, $f) = preg_split('/::/', $func); + if (!$f && function_exists($o)) { + $data = call_user_func_array($o, $value); + } elseif ($f && method_exists($o, $f)) { + $data = call_user_func_array(array($o, $f), $value); + } - elseif (substr($name, 0, 8) == '@config-') { - $property = substr($name, 8); - $default = isset($field[$property]) ? $field[$property] : null; - $config = self::getGrav()['config']->get($value, $default); + // If function returns a value, + if (isset($data)) { + if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) { + // Combine field and @data-field together. + $field[$property] += $data; + } else { + // Or create/replace field with @data-field. + $field[$property] = $data; + } + } + } - if (!is_null($config)) { - $field[$property] = $config; - } - } - } + elseif (substr($name, 0, 8) == '@config-') { + $property = substr($name, 8); + $default = isset($field[$property]) ? $field[$property] : null; + $config = self::getGrav()['config']->get($value, $default); - // Initialize predefined validation rule. - if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') { - $field['validate'] += $this->getRule($field['validate']['rule']); - } - } - } - } + if (!is_null($config)) { + $field[$property] = $config; + } + } + } + } /** * Add property to the definition. From fb3e68e16e124dda0cf211d3aa78146af377d92b Mon Sep 17 00:00:00 2001 From: Maciej Ka Date: Tue, 24 Nov 2015 23:34:47 +0000 Subject: [PATCH 2/3] removed old parameters --- system/src/Grav/Common/Data/Blueprint.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/src/Grav/Common/Data/Blueprint.php b/system/src/Grav/Common/Data/Blueprint.php index aefd1b75c..04bf51040 100644 --- a/system/src/Grav/Common/Data/Blueprint.php +++ b/system/src/Grav/Common/Data/Blueprint.php @@ -346,7 +346,7 @@ class Blueprint implements \ArrayAccess, ExportInterface $this->addProperty($prefix . $key); foreach($field['fields'] as $subName => &$subField) { - $this->parseFormField($subField, $prefix, $key, false); + $this->parseFormField($subField); } if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') { @@ -356,7 +356,7 @@ class Blueprint implements \ArrayAccess, ExportInterface $this->rules[$prefix . $key] = &$field; $this->addProperty($prefix . $key); - $this->parseFormField($field, $prefix, $key, true); + $this->parseFormField($field); if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') { $field['validate'] += $this->getRule($field['validate']['rule']); From edfd7db88b7db461d32850d40780046ba1abf91e Mon Sep 17 00:00:00 2001 From: Maciej Ka Date: Tue, 24 Nov 2015 23:48:22 +0000 Subject: [PATCH 3/3] pretty & clean --- system/src/Grav/Common/Data/Blueprint.php | 40 +++++++++-------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/system/src/Grav/Common/Data/Blueprint.php b/system/src/Grav/Common/Data/Blueprint.php index 04bf51040..8598d8436 100644 --- a/system/src/Grav/Common/Data/Blueprint.php +++ b/system/src/Grav/Common/Data/Blueprint.php @@ -335,33 +335,23 @@ class Blueprint implements \ArrayAccess, ExportInterface // Recursively get all the nested fields. $newParams = array_intersect_key($this->filter, $field); $this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']); - } else if( $field['type'] === 'list') { - // Lists have different structure for fields (one level deeper) - // This means we need to loop through the list to get to the actual field - // The property and rule setting need to be set on the list field - // and NOT on the children, which is why we need to duplicate some of - // the code below :( - - $this->rules[$prefix . $key] = &$field; - $this->addProperty($prefix . $key); - - foreach($field['fields'] as $subName => &$subField) { - $this->parseFormField($subField); - } - - if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') { - $field['validate'] += $this->getRule($field['validate']['rule']); - } } else if ($field['type'] !== 'ignore') { $this->rules[$prefix . $key] = &$field; - $this->addProperty($prefix . $key); - - $this->parseFormField($field); - - if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') { - $field['validate'] += $this->getRule($field['validate']['rule']); - } - } + $this->addProperty($prefix . $key); + + if ($field['type'] === 'list') { + // we loop through list to get the actual field + foreach($field['fields'] as $subName => &$subField) { + $this->parseFormField($subField); + } + } else { + $this->parseFormField($field); + } + + if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') { + $field['validate'] += $this->getRule($field['validate']['rule']); + } + } } } /**