Reputation: 594
I have a multidimensional array and need to verify if the array includes the mandatory fields on the correct layer.
Is there a good approche to achieve that? The input can be an array or a JSON.
My approche so far:
Lets assume the input array is the following:
Array (
[key] => key string
[sub] => Array (
[0] => Array (
[id] => 123456
[src] => source string
[src_ids] => Array (
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
[data] => Array (
[a_data] => a string
[b_data] => b string
[c_data] => c string
)
)
[1] => Array (
[id] => 557799
[src] => source string
[src_ids] => Array (
[0] => 1
[1] => 2
)
[data] => Array (
[a_data] => a string
[b_data] => b string
[c_data] => c string
)
)
)
)
The mandatory values are:
sub, id, src, src_ids, data, a_data
Optional values are everything else like:
key, 0 (of sub), 0-3 (of src_ids), b_data, c_data
I would like to have a function which checks any input array against the mandatory fields. My idea was to create the mandatory values as an array based in layers like:
$mandatory = array(
1 => array( 'sub' ),
3 => array( 'id', 'src', 'src_id', 'data' ),
4 => array( 'a_data' )
);
The key is the depth of the layer and the array value is the allowed key names for that layer.
Now I try to crawl through the input array and check if the key is in the mandatory field based on the depth:
/**
*
* @param array $i input
* @param array $m mandatory
* @param integer $d depth
* @return boolean
*/
function validate( $i, $m, $d=1 ) {
foreach( $i as $k => $v ) {
if( isset($m[$d]) ) {
if( !in_array($k, $m[$d]) ) {
return false;
} else {
if( is_array($v) ) {
$d++;
validate($v, $m, $d );
}
}
} else {
if( is_array($v) ) {
$d++;
validate($v, $m, $d );
}
}
}
return true;
}
But this will cause two major issues:
I also tried to use a comparing array but due to the multiple entries I was not able to compare all the entries against the mandatory array.
Any help, suggestion or solutions are much appreciated.
Thanks
Upvotes: 1
Views: 184
Reputation: 11711
If you define $input
and $mandatory
as described, and the rest of the code looked like this:
$values[1] = $input;
$layer = 1;
$found_layer = true;
while($found_layer)
{
$found_layer = false;
foreach($values[$layer] as $li=>$le)
{
if(is_array($le))
{
$found_layer = true;
if(!isset($values[$layer+1])) $values[$layer+1] = array();
$values[$layer+1] = array_merge($le, $values[$layer+1]);
$values[$layer][$li] = 'array';
}
}
$layer++;
}
$not_found = $mandatory;
foreach($not_found as $layer=>$keys_to_match)
{
foreach($values[$layer] as $key=>$value)
{
foreach($keys_to_match as $ktmi=>$ktm)
{
if($ktm==$key) unset($not_found[$layer][$ktmi]);
}
}
if(!count($not_found[$layer])) unset($not_found[$layer]);
else $not_found[$layer] = array_values($not_found[$layer]);
}
then the code would produce $not_found
as the following:
Array
(
[3] => Array
(
[0] => src_id
)
)
which means, that there is no element on the third level ("layer") of input with the key "src_id" which is mandatory according to $mandatory
. If all mandatory elements are found then $not_found
will be empty. Note, you have 'src_id'
in $mandatory
but the $input
clearly only has a key 'src_ids'
.
I avoided the use of recursion for performance.
Upvotes: 1
Reputation: 20873
Does this fulfill your requirements?
Required field structure:
$required = array(
'sub' => array(
array(
'id' => '',
'src' => '',
'src_ids' => '',
'data' => array(
'a_data' => '',
),
),
),
);
Basically just mimic the structure of the input array. Field names are keys; required subfields are descendants. Leave key numeric/unnamed if it's a list as with sub[0]
and sub[1]
, and it will check structure of each item in the list.
Recursive validation function:
function checkRequired($data, $req)
{
// no more required fields
if (empty($req))
return true;
// no more data fields; obviously lacks required field(s)
if (empty($data))
return false;
foreach ($req as $name => $subtree) {
// unnamed; it's a list
if (is_numeric($name)) {
foreach ($data as $dataitem) {
if (checkRequired($dataitem, $subtree) == false)
return false;
}
} else {
// required field doesn't exist
if (!isset($data[$name]))
return false;
// fine so far; down we go
if (!empty($subtree)
&& checkRequired($data[$name], $subtree) == false
) {
return false;
}
}
}
return true;
}
I likely goofed somewhere, but hopefully you can adapt this into something useful. Here's a working example of this you can experiment with.
Upvotes: 1