Nested Form Input in Drupal

HTML forms are made up of input controls that, when submitted, are converted into an array of values. For example, consider the following form:

<form method="post" action="/">
<input type="text" name="input1" />
<input type="text" name="input2" />
<input type="submit" name="send" value="Send" />
</form>

When a user fills out this form, and submits it, the data is sent by the browser using the POST HTTP method in this fashion:

input1: value
input2: value
send: send

If you were to read that with PHP, you would have to access the `$_POST` array, which would contain those key-value pairs. However, some forms are complex enough that flat arrays like that make it hard to work with the data. In those cases it is useful to get multidimensional arrays. HTML allows you to do just that:

<form method="post" action="/">
<input type="text" name="persons[0][name]" />
<input type="text" name="persons[0][address]" />
<input type="text" name="persons[1][name]" />
<input type="text" name="persons[1][address]" />
<input type="text" name="persons[2][name]" />
<input type="text" name="persons[2][address]" />
<input type="submit" name="send" value="Send" />
</form>

In PHP that results in the following `​$_POST` array

Array
(
 [persons] => Array(
   [0] => Array(
     [name] => john
     [address] => smith
   )
   [1] => Array(
     [name] => jane
     [address] => doe
   )
   [2] => Array(
     [name] => jason
     [address] => foo
   )
 )
 [send] => send
)

As you can see, the information for `persons` is now nicely arranged in an array of arrays, each of which contains the information associated with a person.

If you want to replicate that same structure in Drupal, it is quite easy. Using the Drupal Form Api you can easily create form arrays that Drupal knows how to render. But those forms usually submit data in the flat array form. If you want to get multidimensional array like we did above, you need to use the `#tree` attribute on the element that you want to be the root array member. For example, to get the same input we have above, you would do something like:

$form = [
  'persons' => [
    '#type' => 'markup',
    '#tree' => TRUE,
    '0' => [
      'name' => [
        '#type' => 'textfield'
      ],
      'address' => [
        '#type' => 'textfield'
      ],
    ],
    '1' => [
      'name' => [
        '#type' => 'textfield'
      ],
      'address' => [
        '#type' => 'textfield'
      ],
    ],
    '2' => [
      'name' => [
        '#type' => 'textfield'
      ],
      'address' => [
        '#type' => 'textfield'
      ],
    ],
  ],
];

If you were to omit the `#tree` attribute on the `persons` element in the form array, you would get a flat array of values with name, and address values for the last input fields only. Also note that the nested arrays begin at the point where the `#tree` attribute is specified. For example, if `persons` was itself a child of another element called `personal_data`, the resulting POST data wold remain the same, unless the `#tree` attribute was specified in the `personal_data` element, in which case, the `persons` array would also be child to a `personal_data` member in the `values` array where Drupal saves the submitted data when dealing with form submissions.

Advertisements

404 on Private Drupal Files

A few days ago, it was brought to my attention that some links pointing to private images in a drupal site were not working. The images are submitted by users of the site to request an estimate on repairs for their luxurious cars, and they go to the `private` directory in the drupal site.

For those who don’t know, drupal uses different types of files, such as public, and private. Private files, with the protocol `private://` live in a different place than public ones in the server. When Drupal builds a link to the file, it uses a path that is not really the actual path on disk. The path usually starts with  `system/files/` , but in the drupal directory structure there is no directory called `system`. This means a redirection is made from that url to the actual path of the file in the system.

For some reason, however, when trying to access a private file in the site, all that was returned was a 404 error. This started to happen after the site was moved to a new server. Tracking the problem I found that the issue was that the drupal function drupal_fast_404 was being called in the settings.php file. This function takes care of returning a 404 page whenever the requested url doesn’t match certain criteria. In this case, the fix was to simply edit the 404_fast_paths_exclude to make sure that any path starting with system/files/ and ending with a recognized image extension would not fast 404.