2012-07-12 134 views
1

我有一个多维数组,需要验证数组是否包含正确图层上的必填字段。将多维数组与强制值进行比较

是否有很好的方法来实现这一目标?输入可以是数组或JSON。

我至今approche:

让我们假设输入数组如下:

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 
      ) 
     ) 
    ) 
) 

强制值:

sub, id, src, src_ids, data, a_data 

可选值有一切,如:

key, 0 (of sub), 0-3 (of src_ids), b_data, c_data 

我想有一个函数检查任何输入数组与强制字段。 我的想法是基于在类似的层的阵列来创建强制值:

$mandatory = array( 
    1 => array('sub'), 
    3 => array('id', 'src', 'src_id', 'data'), 
    4 => array('a_data') 
); 

的关键是该层的深度和阵列值是该层所允许的键名。

现在,我尝试通过输入数组抓取并检查重点是必填字段基于深度:

/** 
* 
* @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; 
} 

但是,这将导致两个主要问题:

  1. 层数字4保存src_ids和数据的数组,但只有在数据中有必须的字段a_data。所以它会返回错误的层数4
  2. 但主要问题是这个函数的逻辑问题。现在它不检查必填字段是否设置,它只检查深度的输入值是否在必填字段中。这种行为是错误的。

我也尝试过使用比较数组,但是由于多个条目,我无法将所有条目与强制数组进行比较。

任何帮助,建议或解决方案,非常感谢。

谢谢

+1

是否在适当级别的每个元素上都需要强制性元素,或者如果适当级别的元素之一具有强制性元素,那么整个输入被认为是好的?例如,如果'$ mandatory = array(3 =>​​ array('a','b'));'和'$ input = array(array('a'=> 1),array('b'=> 2 ));',答案是什么? – ghbarratt 2012-07-12 19:48:55

+0

谢谢ghbarratt。答案应该是错误的,因为a和b对于拨款级别的每个元素都是强制性的。 – Talisin 2012-07-13 01:03:20

回答

1

这是否符合您的要求?

必填字段结构:

$required = array(
    'sub' => array(
     array(
      'id' => '', 
      'src' => '', 
      'src_ids' => '', 
      'data' => array(
       'a_data' => '', 
      ), 
     ), 
    ), 
); 

基本上只是模仿输入阵列的结构。字段名称是键;所需的子字段是子孙。如果是sub[0]sub[1]这样的列表,请留下关键的数字/未命名,并且它将检查列表中每个项目的结构。

递归验证功能:

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; 
} 

我可能什么地方出了差错,但希望你能适应到一些有用的东西这一点。以下是您可以尝试的working example of this

+0

嗨Wiseguy,我自己尝试过一种场地结构,但我想我会疲倦找到一种方法。我会做更多的测试,但就目前来看,您的代码完美无缺。我非常喜欢结构设计,因为它很容易管理,并且可以适用于其他布局。也感谢您的评论,节省了大量的时间来阅读代码:)。标记为已接受的答案,因为它符合要求(即使它们没有100%清晰)并且示例代码清晰。谢谢! – Talisin 2012-07-13 01:17:47

1

如果定义描述$input$mandatory,以及其余代码是这样的:

$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]); 
} 

那么代码会产生$not_found如下所示:

Array 
(
    [3] => Array 
     (
      [0] => src_id 
     ) 

) 

这意味着,根据$mandatory强制输入的密钥“src_id”在输入的第三级(“图层”)上没有元素。如果找到所有强制性元素,则$not_found将为空。请注意,您的'src_id'$mandatory,但$input显然只有一个密钥'src_ids'

我避免使用递归来提高性能。

+0

再次ghbarratt,感谢您的代码。我看了一下,根据你的假设,强制只需要在一个入口上设置为适当的级别,它就是完美的。对于遗漏的关于行为的描述很抱歉,但应该在每个条目中设置适当的级别。无论如何,无需编写更多代码,因为我对Wiseguys发布的解决方案感到满意。真的很感激你的解决方案和你的快速回答。谢谢! – Talisin 2012-07-13 01:12:09