0

The task is to remove arrays recursively that have error => 4 (i.e key with that value) with their keys, and then turn remained arrays into objects. The structure of incoming array might be different. Two examples of it are this ones:

// Example input #1
$ex_input_1 = array(
    'files' => array(
        0 => array(
            'name' => 'file.jpg',
            'size' => '244235',
            'tmp_name' => '/usr/tmp/24ffds.tmp',
            'error' => 0
        ),

        1 => array(
            'name' => '',
            'size' => '',
            'tmp_name' => '',
            'error' => 4
        )
    ),

    'cover' => array(
        'name' => '',
        'size' => '',
        'tmp_name' => '',
        'error' => 4
    ),

    'document' => array(
        'name' => 'file.doc',
        'size' => '244235',
        'tmp_name' => '/usr/tmp/24ffds.tmp',
        'error' => 0
    )
);

// Example input #2
$ex_input_2 = array(
    0 => array(
        'name' => 'file.jpg',
        'size' => '244235',
        'tmp_name' => '/usr/tmp/24ffds.tmp',
        'error' => 0
    ),

    1 => array(
        'name' => '',
        'size' => '',
        'tmp_name' => '',
        'error' => 4
    )
);

i.e an array that have name, size, tmp_name, error keys might be at any level down.

What I tried:

Tried to write a simple handler with two methods, where the first one is recursive handler and the second one is hydrator method. Here's it with relevant parts:

<?php

class FileInputParser
{
    /**
     * Recursively hydrate array entires skipping empty files
     * 
     * @param array $files
     * @return array
     */
    public function hydrateAll(array $files)
    {
        foreach ($files as $name => $file) {
            if (!is_array($file)) {
                continue;
            }

            foreach ($file as $key => $value) {
                if (is_array($value)) {
                    // Recursise call
                    $files[$name] = $this->hydrateAll($files[$name]);
                } else {
                    $target = $this->hydrateSingle($file);

                    // Here I'm EXPLICTLY asking not to push an array, which has error = 4
                    // But it pushes anyway!!
                    if ($target !== false) {
                        unset($files[$name]);
                    }
                }
            }
        }

        return $files;
    }

    /**
     * Hydrates a single file item
     * 
     * @param array $file
     * @return mixed
     */
    private function hydrateSingle(array $file)
    {
        $entity = new stdclass;
        $entity->name = $file['name'];
        $entity->tmp_name = $file['tmp_name'];
        $entity->error = $file['error'];
        $entity->size = $file['size'];

        if ($entity->error != 4) {
            return $entity;
        } else {
            // Returning false to indicate, that this one should not be pushed in output
            return false;
        }
    }
}

The problem

While at first glance it works, the problem is that, when I'm asking explicitly not to add an array that has error = 4 to output, but it continues to add!

You can run aforementioned code with input examples:

<?php

$parser = new FileInputParser();
$output = $parser->hydrateAll($ex_input_1);

echo '<pre>', print_r($output, true);

to see that it also returns unwanted arrays (i.e the ones that have error = 4).

The question

Why it continues to add arrays to output that have error = 4 ? if you have a better idea on handling this, I'd love to hear it.

1 Answer 1

1

Here's a recursive function that will do the filtering you want. When it reaches the bottom of the tree, it checks for error == 4 and if it is, returns an empty array, otherwise it returns the current array. At the next level down any empty values returned are removed by array_filter:

function array_filter_recursive($array) {
    if (isset($array['error'])) {
        // bottom of tree
        return $array['error'] == 4 ? array() : $array;
    }
    foreach ($array as $key => $value) {
        $array[$key] = array_filter_recursive($value);
    }
    // remove any empty values
    return array_filter($array);
}

Output from filtering your two input arrays:

Array ( 
    [files] => Array (
        [0] => Array ( 
            [name] => file.jpg
            [size] => 244235
            [tmp_name] => /usr/tmp/24ffds.tmp
            [error] => 0
        )
    )
    [document] => Array (
         [name] => file.doc
         [size] => 244235
         [tmp_name] => /usr/tmp/24ffds.tmp
         [error] => 0
    ) 
)

Array ( 
    [0] => Array (
        [name] => file.jpg
        [size] => 244235
        [tmp_name] => /usr/tmp/24ffds.tmp
        [error] => 0
    )
)

Demo on 3v4l.org

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.