Issue #1397246 by webchick, heyrocker, sun: Add drupal_array_unset_nested_value().
parent
1878eb1534
commit
7cd1f96db9
|
@ -6447,6 +6447,78 @@ function element_set_attributes(array &$element, array $map) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from a nested array with variable depth.
|
||||
*
|
||||
* This helper function should be used when the depth of the array element being
|
||||
* retrieved may vary (that is, the number of parent keys is variable). It is
|
||||
* primarily used for form structures and renderable arrays.
|
||||
*
|
||||
* Without this helper function the only way to get a nested array value with
|
||||
* variable depth in one line would be using eval(), which should be avoided:
|
||||
* @code
|
||||
* // Do not do this! Avoid eval().
|
||||
* // May also throw a PHP notice, if the variable array keys do not exist.
|
||||
* eval('$value = $array[\'' . implode("']['", $parents) . "'];");
|
||||
* @endcode
|
||||
*
|
||||
* Instead, use this helper function:
|
||||
* @code
|
||||
* $value = drupal_array_get_nested_value($form, $parents);
|
||||
* @endcode
|
||||
*
|
||||
* The return value will be NULL, regardless of whether the actual value is NULL
|
||||
* or whether the requested key does not exist. If it is required to know
|
||||
* whether the nested array key actually exists, pass a third argument that is
|
||||
* altered by reference:
|
||||
* @code
|
||||
* $key_exists = NULL;
|
||||
* $value = drupal_array_get_nested_value($form, $parents, $key_exists);
|
||||
* if ($key_exists) {
|
||||
* // ... do something with $value ...
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* However if the number of array parent keys is static, the value should always
|
||||
* be retrieved directly rather than calling this function. For instance:
|
||||
* @code
|
||||
* $value = $form['signature_settings']['signature'];
|
||||
* @endcode
|
||||
*
|
||||
* @param $array
|
||||
* The array from which to get the value.
|
||||
* @param $parents
|
||||
* An array of parent keys of the value, starting with the outermost key.
|
||||
* @param $key_exists
|
||||
* (optional) If given, an already defined variable that is altered by
|
||||
* reference.
|
||||
*
|
||||
* @return
|
||||
* The requested nested value. Possibly NULL if the value is NULL or not all
|
||||
* nested parent keys exist. $key_exists is altered by reference and is a
|
||||
* Boolean that indicates whether all nested parent keys exist (TRUE) or not
|
||||
* (FALSE). This allows to distinguish between the two possibilities when NULL
|
||||
* is returned.
|
||||
*
|
||||
* @see drupal_array_set_nested_value()
|
||||
* @see drupal_array_unset_nested_value()
|
||||
*/
|
||||
function &drupal_array_get_nested_value(array &$array, array $parents, &$key_exists = NULL) {
|
||||
$ref = &$array;
|
||||
foreach ($parents as $parent) {
|
||||
if (is_array($ref) && array_key_exists($parent, $ref)) {
|
||||
$ref = &$ref[$parent];
|
||||
}
|
||||
else {
|
||||
$key_exists = FALSE;
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
}
|
||||
$key_exists = TRUE;
|
||||
return $ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value in a nested array with variable depth.
|
||||
*
|
||||
|
@ -6505,6 +6577,7 @@ function element_set_attributes(array &$element, array $map) {
|
|||
* FALSE, PHP throws an error if trying to add into a value that is not an
|
||||
* array. Defaults to FALSE.
|
||||
*
|
||||
* @see drupal_array_unset_nested_value()
|
||||
* @see drupal_array_get_nested_value()
|
||||
*/
|
||||
function drupal_array_set_nested_value(array &$array, array $parents, $value, $force = FALSE) {
|
||||
|
@ -6521,74 +6594,73 @@ function drupal_array_set_nested_value(array &$array, array $parents, $value, $f
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from a nested array with variable depth.
|
||||
* Unsets a value in a nested array with variable depth.
|
||||
*
|
||||
* This helper function should be used when the depth of the array element being
|
||||
* retrieved may vary (that is, the number of parent keys is variable). It is
|
||||
* primarily used for form structures and renderable arrays.
|
||||
* This helper function should be used when the depth of the array element you
|
||||
* are changing may vary (that is, the number of parent keys is variable). It
|
||||
* is primarily used for form structures and renderable arrays.
|
||||
*
|
||||
* Without this helper function the only way to get a nested array value with
|
||||
* variable depth in one line would be using eval(), which should be avoided:
|
||||
* Example:
|
||||
* @code
|
||||
* // Assume you have a 'signature' element somewhere in a form. It might be:
|
||||
* $form['signature_settings']['signature'] = array(
|
||||
* '#type' => 'text_format',
|
||||
* '#title' => t('Signature'),
|
||||
* );
|
||||
* // Or, it might be further nested:
|
||||
* $form['signature_settings']['user']['signature'] = array(
|
||||
* '#type' => 'text_format',
|
||||
* '#title' => t('Signature'),
|
||||
* );
|
||||
* @endcode
|
||||
*
|
||||
* To deal with the situation, the code needs to figure out the route to the
|
||||
* element, given an array of parents that is either
|
||||
* @code array('signature_settings', 'signature') @endcode in the first case or
|
||||
* @code array('signature_settings', 'user', 'signature') @endcode in the second
|
||||
* case.
|
||||
*
|
||||
* Without this helper function the only way to unset the signature element in
|
||||
* one line would be using eval(), which should be avoided:
|
||||
* @code
|
||||
* // Do not do this! Avoid eval().
|
||||
* // May also throw a PHP notice, if the variable array keys do not exist.
|
||||
* eval('$value = $array[\'' . implode("']['", $parents) . "'];");
|
||||
* eval('unset($form[\'' . implode("']['", $parents) . '\']);');
|
||||
* @endcode
|
||||
*
|
||||
* Instead, use this helper function:
|
||||
* @code
|
||||
* $value = drupal_array_get_nested_value($form, $parents);
|
||||
* @endcode
|
||||
*
|
||||
* The return value will be NULL, regardless of whether the actual value is NULL
|
||||
* or whether the requested key does not exist. If it is required to know
|
||||
* whether the nested array key actually exists, pass a third argument that is
|
||||
* altered by reference:
|
||||
* @code
|
||||
* $key_exists = NULL;
|
||||
* $value = drupal_array_get_nested_value($form, $parents, $key_exists);
|
||||
* if ($key_exists) {
|
||||
* // ... do something with $value ...
|
||||
* }
|
||||
* drupal_array_unset_nested_value($form, $parents, $element);
|
||||
* @endcode
|
||||
*
|
||||
* However if the number of array parent keys is static, the value should always
|
||||
* be retrieved directly rather than calling this function. For instance:
|
||||
* be set directly rather than calling this function. For instance, for the
|
||||
* first example we could just do:
|
||||
* @code
|
||||
* $value = $form['signature_settings']['signature'];
|
||||
* unset($form['signature_settings']['signature']);
|
||||
* @endcode
|
||||
*
|
||||
* @param $array
|
||||
* The array from which to get the value.
|
||||
* A reference to the array to modify.
|
||||
* @param $parents
|
||||
* An array of parent keys of the value, starting with the outermost key.
|
||||
* @param $key_exists
|
||||
* An array of parent keys, starting with the outermost key and including the
|
||||
* key to be unset.
|
||||
* @param $key_existed
|
||||
* (optional) If given, an already defined variable that is altered by
|
||||
* reference.
|
||||
*
|
||||
* @return
|
||||
* The requested nested value. Possibly NULL if the value is NULL or not all
|
||||
* nested parent keys exist. $key_exists is altered by reference and is a
|
||||
* Boolean that indicates whether all nested parent keys exist (TRUE) or not
|
||||
* (FALSE). This allows to distinguish between the two possibilities when NULL
|
||||
* is returned.
|
||||
*
|
||||
* @see drupal_array_set_nested_value()
|
||||
* @see drupal_array_get_nested_value()
|
||||
*/
|
||||
function &drupal_array_get_nested_value(array &$array, array $parents, &$key_exists = NULL) {
|
||||
$ref = &$array;
|
||||
foreach ($parents as $parent) {
|
||||
if (is_array($ref) && array_key_exists($parent, $ref)) {
|
||||
$ref = &$ref[$parent];
|
||||
}
|
||||
else {
|
||||
$key_exists = FALSE;
|
||||
$null = NULL;
|
||||
return $null;
|
||||
}
|
||||
function drupal_array_unset_nested_value(array &$array, array $parents, &$key_existed = NULL) {
|
||||
$unset_key = array_pop($parents);
|
||||
$ref = &drupal_array_get_nested_value($array, $parents, $key_existed);
|
||||
if ($key_existed && is_array($ref) && array_key_exists($unset_key, $ref)) {
|
||||
$key_existed = TRUE;
|
||||
unset($ref[$unset_key]);
|
||||
}
|
||||
else {
|
||||
$key_existed = FALSE;
|
||||
}
|
||||
$key_exists = TRUE;
|
||||
return $ref;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2411,6 +2411,118 @@ class DrupalAttributesUnitTest extends DrupalUnitTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the various drupal_array_* helper functions.
|
||||
*/
|
||||
class CommonDrupalArrayUnitTest extends DrupalUnitTestCase {
|
||||
|
||||
/**
|
||||
* Form array to check.
|
||||
*/
|
||||
protected $form;
|
||||
|
||||
/**
|
||||
* Array of parents for the nested element.
|
||||
*/
|
||||
protected $parents;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'drupal_array_*() tests',
|
||||
'description' => 'Tests the various drupal_array_* helper functions.',
|
||||
'group' => 'System',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create a form structure with a nested element.
|
||||
$this->form['fieldset']['element'] = array(
|
||||
'#value' => 'Nested element',
|
||||
);
|
||||
|
||||
// Set up parent array.
|
||||
$this->parents = array('fieldset', 'element');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getting nested array values.
|
||||
*/
|
||||
function testGet() {
|
||||
// Verify getting a value of a nested element.
|
||||
$value = drupal_array_get_nested_value($this->form, $this->parents);
|
||||
$this->assertEqual($value['#value'], 'Nested element', 'Nested element value found.');
|
||||
|
||||
// Verify changing a value of a nested element by reference.
|
||||
$value = &drupal_array_get_nested_value($this->form, $this->parents);
|
||||
$value['#value'] = 'New value';
|
||||
$value = drupal_array_get_nested_value($this->form, $this->parents);
|
||||
$this->assertEqual($value['#value'], 'New value', 'Nested element value was changed by reference.');
|
||||
$this->assertEqual($this->form['fieldset']['element']['#value'], 'New value', 'Nested element value was changed by reference.');
|
||||
|
||||
// Verify that an existing key is reported back.
|
||||
$key_exists = NULL;
|
||||
drupal_array_get_nested_value($this->form, $this->parents, $key_exists);
|
||||
$this->assertIdentical($key_exists, TRUE, 'Existing key found.');
|
||||
|
||||
// Verify that a non-existing key is reported back and throws no errors.
|
||||
$key_exists = NULL;
|
||||
$parents = $this->parents;
|
||||
$parents[] = 'foo';
|
||||
drupal_array_get_nested_value($this->form, $parents, $key_exists);
|
||||
$this->assertIdentical($key_exists, FALSE, 'Non-existing key not found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests setting nested array values.
|
||||
*/
|
||||
function testSet() {
|
||||
$new_value = array(
|
||||
'#value' => 'New value',
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
// Verify setting the value of a nested element.
|
||||
drupal_array_set_nested_value($this->form, $this->parents, $new_value);
|
||||
$this->assertEqual($this->form['fieldset']['element']['#value'], 'New value', 'Changed nested element value found.');
|
||||
$this->assertIdentical($this->form['fieldset']['element']['#required'], TRUE, 'New nested element value found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests unsetting nested array values.
|
||||
*/
|
||||
function testUnset() {
|
||||
// Verify unsetting a non-existing nested element throws no errors and the
|
||||
// non-existing key is properly reported.
|
||||
$key_existed = NULL;
|
||||
$parents = $this->parents;
|
||||
$parents[] = 'foo';
|
||||
drupal_array_unset_nested_value($this->form, $parents, $key_existed);
|
||||
$this->assertTrue(isset($this->form['fieldset']['element']['#value']), 'Outermost nested element key still exists.');
|
||||
$this->assertIdentical($key_existed, FALSE, 'Non-existing key not found.');
|
||||
|
||||
// Verify unsetting a nested element.
|
||||
$key_existed = NULL;
|
||||
drupal_array_unset_nested_value($this->form, $this->parents, $key_existed);
|
||||
$this->assertFalse(isset($this->form['fieldset']['element']), 'Removed nested element not found.');
|
||||
$this->assertIdentical($key_existed, TRUE, 'Existing key was found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests existence of array key.
|
||||
*/
|
||||
function testKeyExists() {
|
||||
// Verify that existing key is found.
|
||||
$this->assertIdentical(drupal_array_nested_key_exists($this->form, $this->parents), TRUE, 'Nested key found.');
|
||||
|
||||
// Verify that non-existing keys are not found.
|
||||
$parents = $this->parents;
|
||||
$parents[] = 'foo';
|
||||
$this->assertIdentical(drupal_array_nested_key_exists($this->form, $parents), FALSE, 'Non-existing nested key not found.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests converting PHP variables to JSON strings and back.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue