すべての例はPHPにあり、mysqlデータベースが使用されます。 上記のコードはどのデータベースにも関連付けられていませんが、削除する行、追加する行、変更する行を決定するだけです。 さらに、これらの「命令」は、任意のデータベースに簡単に実装できます。
たとえば、「識別子」、「名前」、「作成日」などの単一のプロパティを持つ単純なドキュメントがあり、このドキュメントには複数のフィールドがあります-フォーム内のアクセス制御テーブル:ユーザーコード、アクセス許可の開始日時、アクセスが拒否された日時。
PHPの特定のドキュメントのデータ構造は、次のように表すことができます。
$document["id"] = "1"; // $document["name"] = " "; // $document["create_date"] = "25-10-2012"; // $document["permissions_table"] = array( array( "user_id" => 1, // "grant_from" => "2012-10-25 00:00:00", // "grant_to" => "2012-10-27 23:59:59" // ) );
データベースでは、そのようなドキュメントは2つのテーブルに格納されると想定しています。
/* - document_header ( , - ) id INT NOT NULL AUTOINCREMENT name TEXT NOT NULL create_date DATETIME NOT NULL - document_permissions ( , - ) id INT NOT NULL AUTOINCREMENT document_id INT NOT NULL user_id INT NOT NULL grant_from DATETIME grant_to DATETIME */
次に、ドキュメントのアクセステーブルを変更するタスクが発生することを想像してください。 さらに、ユーザーが送信した後、処理用のドキュメントの2つの配列を取得します。古いデータの配列と新しいデータの配列です。
次に、これらの配列をSQLクエリのシーケンスに変換して、データベース内のドキュメントを変更する方法を見てみましょう。
フラットデータでは、すべてが非常に単純で、次のコードで処理できます
$changes = array(); foreach($old_document as $k => $v) { if($k == "permissions_table") continue; if($old_document[$k] != $new_document[$k]) $changes[$k] = $new_document[$k]; } $changes["id"] = $old_document["id"] $changes["document_id"] = $old_document["document_id"]
その結果、変更されたフィールドとその新しい値を含む$変更の配列を取得します。これは、UPDATEデータベースクエリに簡単に変換できます。 この操作で記事をオーバーロードしたくないので、省略します。
次に、ドキュメントアクセステーブルの変更を処理し、データベースに必要な変更を加える必要があります。
ここでは、さまざまな状況が発生する可能性があります。例えば:
-古い行が変更されました
-新しい行が追加されました
-古い行が削除されました
-行の順序が変更されました
上記の操作の任意の組み合わせ。
この場合、データベースに適切なクエリを生成し、必ず次の順序で実行する必要があります。
1.余分な行を削除する
2.既存の行を変更する
3.新しい行を追加する
削除は、主に追加または変更操作中にデータベース内の一意のキーの競合がないように実行されます。
その結果、入力で古い値と新しい値の配列を受け取る関数が必要になり、出力では、削除、変更、およびデータベースへの追加が必要なテーブル行を含む3つの配列を提供します。
このタスクのために、表データの任意の構成で機能するユニバーサル関数を作成しました。 記事の最後に示されているいくつかの制限がある場合のみ。
そのため、マジック関数には次のインターフェースがあります。
/* @$data - @$old_data - @$keys - (, . ) @$hidden_keys - , (. ) @$options - */
出力では、大切な配列の削除、更新、挿入を取得します。これらは、後続の実行のためにデータベースクエリに簡単に変換できます。
関数のソースコード:
static function generateOperationsFromMultiData($data, $old_data, $keys, $hidden_keys, $options) { $out = array("insert" => array(), "update" => array(), "delete" => array()); $unique_elements = array(); $unique_keys = array(); // $old_elements_hashes = array(); $old_elements_keys = array(); foreach($old_data as $k => $fields) { $res = self::__getKeyAndHashFromLine($fields, $keys, $hidden_keys); $old_data[$k]["___key"] = $res["key"]; $old_data[$k]["___hash"] = $res["hash"]; if($res["key"]) { $old_elements_hashes[$res["key"]] = $res["hash"]; $old_elements_keys[$res["key"]] = $k; } else { $old_elements_hashes[$k] = $res["hash"]; } } // $data = array_merge($data); foreach($data as $k => $fields) { $res = self::__getKeyAndHashFromLine($fields, $keys); $data[$k]["___key"] = $res["key"]; $data[$k]["___hash"] = $res["hash"]; foreach($hidden_keys as $k2) unset($fields[$k2]); // if($options["unique"]) { if(in_array($res["hash"], $unique_elements)) continue; else $unique_elements[] = $res["hash"]; } if($res["key"]) { // if(in_array($res["key"], $unique_keys)) continue; else $unique_keys[] = $res["key"]; // if(!isset($old_elements_hashes[$res["key"]])) $out["insert"][$k] = $fields; else { // , if($res["hash"] != $old_elements_hashes[$res["key"]]) { // foreach($hidden_keys as $v) { $fields[$v] = $old_data[$old_elements_keys[$res["key"]]][$v]; } // $out["update"][$k] = $fields; } $old_data[$old_elements_keys[$res["key"]]]["___new_key"] = $k; unset($old_elements_hashes[$res["key"]]); unset($old_elements_keys[$res["key"]]); } } else { // if($key = array_keys($old_elements_hashes, $res["hash"])) { $key = current($key); unset($old_elements_hashes[$key]); $old_data[$key]["___new_key"] = $k; } else { // , $out["insert"][$k] = $fields; } } } // old_data if($keys) foreach($old_elements_keys as $k => $v) { unset($old_data[$v]["___key"]); unset($old_data[$v]["___hash"]); unset($old_data[$v]["___new_key"]); $out["delete"][] = $old_data[$v]; unset($old_data[$v]); } else foreach($old_elements_hashes as $k => $v) { unset($old_data[$k]["___key"]); unset($old_data[$k]["___hash"]); unset($old_data[$k]["___new_key"]); $out["delete"][] = $old_data[$k]; unset($old_data[$k]); } // // $old_data = array_merge($old_data); $data = array_merge($data); if($options["save_order"]) { $delete = false; // ( , update ) if($old_data[0]["___new_key"] != "0") $delete = true; foreach($old_data as $k => $v) { // , if($v["___new_key"] != $k) $delete = true; if($delete) { unset($old_data[$k]["___key"]); unset($old_data[$k]["___hash"]); unset($old_data[$k]["___new_key"]); unset($data[$v["___new_key"]]["___key"]); unset($data[$v["___new_key"]]["___hash"]); $out["delete"][] = $old_data[$k]; foreach($hidden_keys as $hk) { $data[$v["___new_key"]][$hk] = $old_data[$k][$hk]; } $out["insert"][$v["___new_key"]] = $data[$v["___new_key"]]; if($keys) unset($out["update"][$v["___new_key"]]); } } } $out["update"] = array_merge($out["update"]); ksort($out["insert"]); $out["insert"] = array_merge($out["insert"]); return $out; } // function __getKeyAndHashFromLine($line, $keys, $hide_keys = array()) { $hash = $line; // foreach($keys as $v) unset($hash[$v]); foreach($hide_keys as $v) unset($hash[$v]); // $hash = serialize($hash); // $key = ""; foreach($keys as $v) $key .= "__" . $line[$v]; return array("hash" => $hash, "key" => $key); }
この場合、関数呼び出しは次のようになります。
$result = generateOperationsFromMultiData($new_document["permissions_table"], $old_document["permissions_table"], false, array("id"), array("unique" => false));
その結果、 $ resultには、 delete 、 update 、 insertの 3つの配列が含まれます。
説明のためにいくつかの例を示します。
最初の例では、2人のユーザー用の2行があります。 変更をエミュレートして、3番目のユーザーを紹介し、2番目のユーザーを削除します。 同時に、特別に最初のユーザーの行を複製し、両方の行の日付を変更します。
$old_document["permissions_table"] = array( array( "id" => 1, "document_id" => 1, "user_id" => 1, "grant_from" => "2012-10-25 00:00:00", "grant_to" => "2012-10-27 00:00:00" ), array( "id" => 2, "document_id" => 1, "user_id" => 2, "grant_from" => "2012-10-25 00:00:00", "grant_to" => "2012-10-27 00:00:00" ) ); $new_document["permissions_table"] = array( array( "document_id" => 1, "user_id" => 3, "grant_from" => "2012-10-25 00:00:00", "grant_to" => "2012-10-27 00:00:00" ), array( "document_id" => 1, "user_id" => 1, "grant_from" => "2012-10-25 00:00:00", "grant_to" => "2012-10-03 00:00:00" ), array( "document_id" => 1, "user_id" => 1, "grant_from" => "2012-10-25 00:00:00", "grant_to" => "2012-10-31 00:00:00" ) ); generateOperationsFromMultiData( $new_document["permissions_table"], $old_document["permissions_table"], array("user_id"), array("id"), array( "unique" => false, "save_order" => false ) )
出力では次のようになります
Array ( [insert] => Array ( [0] => Array ( [document_id] => 1 [user_id] => 3 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-27 00:00:00 ) ) [update] => Array ( [0] => Array ( [document_id] => 1 [user_id] => 1 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-03 00:00:00 [id] => 1 ) ) [delete] => Array ( [0] => Array ( [id] => 2 [document_id] => 1 [user_id] => 2 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-27 00:00:00 ) ) )
その結果、3番目のユーザーで行を挿入し、2番目のユーザーで行を削除し、最初のユーザーで変更を加える必要があることがわかりました。 最初のユーザーの変更は、 $ new_document [permissions_table]配列のこのユーザーの最初の行から取得されることに注意してください。 これにより、「複製されたデータ」の正しい処理を示したかったのです。
次に、関数の動作を制御するパラメーターを検討します。
$ keys-テーブルデータキーの配列。 指定すると、関数は自動的に重複キーを持つ行をスローし始めます。上記の例では、キーは「user_id」であるため、同じユーザーの行の繰り返しを禁止しています。 キーはコンポジットにすることができます。このため、このパラメーターの配列でキーを指定するだけで十分です。 キーを指定しない場合、関数は引き続き機能しますが、データベースに何らかのIDを入力する必要があります。そのため、ある行を別の行と区別する必要があります。 $ hidden_keys関数に登録する必要があります。
$ hidden_keys-非表示キー。これらは、変更されたデータの配列ではなく、古いデータの配列に存在する可能性があるキーです。 この場合、関数はこれらのキーを行の削除および変更の出力配列に自動的に転送します。 特に、行が1つ以上の非キーフィールドで構成されている場合、複数のデータを管理するために必要です。 次に、そのような行を識別するために、一意のIDがデータベースに入力されますが、編集中にフォームに「ドラッグ」してその「安全性」を監視する必要はありません。 関数自体は、削除する特定のIDを持つ行、変更する行、および追加する行を決定します。
$ options [unique] -このフラグをtrueに設定すると、キーの一意性に加えて、関数は残りの文字列データの一意性のチェックを開始します。つまり、 $ options [unique]フラグを設定すると、異なる期間に同じ期間を指定できなくなりますユーザー。この場合、関数は最初の利用可能な期間を残し、後続の繰り返し期間を削除します。
$ options [save_order] -データベース内のデータの順序を保持する必要があることを示すフラグ。 $ data配列と同じです(この例では、 $ new_document [permissions_table] )。 このフラグがどのように機能するかを理解するために、 $ options [save_order]フラグが設定されている場合のみ、この例の結果を検討してください。
Array ( [insert] => Array ( [0] => Array ( [document_id] => 1 [user_id] => 3 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-03 00:00:00 ) [1] => Array ( [document_id] => 1 [user_id] => 1 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-03 00:00:00 [id] => 1 ) ) [update] => Array ( ) [delete] => Array ( [0] => Array ( [id] => 2 [document_id] => 1 [user_id] => 2 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-27 00:00:00 ) [1] => Array ( [id] => 1 [document_id] => 1 [user_id] => 1 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-27 00:00:00 ) ) )
最初に、この関数は、3番目のユーザーで新しいレコードを挿入し、その後に最初のユーザーでレコードを挿入するために、既存のレコードをすべて削除することを提案していることがわかります。 したがって、データベースでは、新しい配列のように、ソートせずにフェッチするときに同じシーケンスを取得します。 この機能を使用すると、行のソートに必要な追加フィールドを保存できます。 ただし、行がテーブルの中央または先頭に挿入される場合、最初にこの行に続くすべてのデータを削除し、次にそれらを再度追加する必要があります(これらのアクションは最後の例で見ました)
注:目的の結果を得るために、関数は常に最小数のデータベースクエリを提供します。
制限:行データは、関数の実行時にのみフラットにする必要があります。 フィールドは「___ key」、「___ hash」、「___ new_key」と呼ばないでください。