2012-07-12 106 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