ネストセットツリー管理モジュール

挑戦する



ええ、あなたはボートに乗って水に乗って人生を楽しみます。 私は休息するために次の湖に行きました、そして彼らは犬やボートは許可されていないと言っているとあなたに話します、そして一般的に私たちの湖はいつも凍っています、ここであなたはスケートを持っています-お楽しみください。 「仮想ホスティング湖へようこそ。」 どういうわけか、 スーパーユーザーのみがMySQLでトリガーを作成できるという事実に注意を払っていませんでしたが、これはやや驚くべきことですが、開発者の良心に任せましょう。 基本的にPerlのソリューションはありますが、作成した時点では完全に異なるタスクと要件がありました。 したがって、この記事は以前の開発をキャンセルするのではなく、追加のソリューションを提供するだけです。 データベースを操作するための特定のオブジェクトセットと特定の「ラッパー」があります。 この「ラッパー」には、このモジュールを機能の拡張として含めます。 ラッパーは自己記述型です。 DBIx :: Classやその他の既成のソリューションの反対者ではないので、事前に予約します。仕事でそれらを使用して満足しています。 質問は仮想ホスティングとそれに似た他のものにかかっています:mod_perlの欠如と追加モジュールのインストールのhemo。 同じDBIx :: Classのソリューションは開発中ですが、必要がないのであまり高速ではないので、十分なトリガーがあるため、 挿入更新削除の 3つの手順だけが必要です。 これはプロシージャであり、「ラッパー」のオブジェクトのメソッドとして継承されます。 ただし、この記事では、ほぼ自給自足にします。 このモジュールにはトランザクションを含めませんでした。1レベル上で使用しているため、自分でコードに含めることは難しくないと思います。 、機能の少しのテストが実行されましたが。



基本的な手順と変数



もちろん、データベースに接続するための手順ですが、外部から定義されているパッケージ$ dbhのオブジェクトがあります。 また、普遍性を確保するために、ツリーの構造を担当する独自のフィールドセットを各テーブルに定義する配列を作成します。

Perlコード(1)
パッケージMY :: NestedSets;
 #妥協のない大人としてのすべて;-)
厳格な使用;
警告を使用します。
 $ VERSION = '0.0.1';
 #パッケージ内で使用する変数を定義します
 $ dbh = undef;
 $テーブル= {
                デフォルト=> {#テーブル名
                    フィールド=> {#テーブルフィールド
                         id => 'id'、#実際にID、だれもがどのように電話するかわかりません
                         left_key => 'left_key'、#左キー
                         right_key => 'right_key'、#右キー
                         level => 'level'、#レベル
                         parent_id => 'parent_id'、#親ID
                         tree => 'tree'#ツリー識別子
                                 }、
                     multi => 1、#テーブルに複数のツリーがあることを示します
                             }、
                };

 sub dbh {
 #まだ作成している場合、最初の値はパッケージの名前またはパッケージのクラスになります
 #それで、私たちは時々それを断ち切り、クラスを持っていません。
     shift if $ _ [0] &&($ _ [0] eq __PACKAGE__ ||(ref $ _ [0] && ref $ _ [0] eq __PACKAGE__));
     $ dbh = $ _ [0] if $ _ [0];
     return $ dbh;
 }

 sub set_table_params {
     shift if $ _ [0] &&($ _ [0] eq __PACKAGE__ ||(ref $ _ [0] && ref $ _ [0] eq __PACKAGE__));
 #特定のテーブルのフィールドを設定する
     my($ table_name、$ params)= @_;
     $ tables-> {$ table_name} = $ params;
     $テーブルを返します。
 }
    


並行して、useスクリプト自体を記述しますが、これもテスト用です。 そのため、モジュールを使用して、そのメインデータを決定します。

Perlコード(2)
 #!/ usr / bin / perl
厳格な使用; 警告を使用します。
 lib '../lib'を使用します。
 MY :: NestedSetsを使用します。
 DBIを使用します。
 Data :: Dumperを使用します。

 #------------------------------------------------- -------------------------------------------------- -----
 #INIT

 my $ dbh = DBI-> connect( 'dbi:mysql:database = test; host = localhost; port = 3306'、 'user'、 'pass');
私の$ table_name = 'test_nested_sets';
 my%f =(
         id => 'ids'、
         left_key => 'lk'、
         right_key => 'rk'、
        レベル=> 'lv'、
         parent_id => 'pi'、
        ツリー=> 'tr'、
         );
 $ dbh-> do( "DROP TABLE` $ table_name`;");
 my $ query = "CREATE TABLE` $ table_name`(
     `$ f {id}` int(11)NOT NULL auto_increment、
     `$ f {left_key}` int(11)NOT NULLデフォルト '0'、
     `$ f {right_key}` int(11)NOT NULLデフォルト '0'、
     `$ f {level}` int(11)NOT NULLデフォルト '0'、
     `$ f {parent_id}` int(11)NOT NULLデフォルト '0'、
     `$ f {tree}` int(11)NOT NULLデフォルト '1'、
     `field1` VARCHAR(100)、
    主キー( `$ f {id}`)
 )エンジン= MyISAM; ";
 $ dbh-> do($ query);

 MY :: NestedSets-> dbh($ dbh);
 MY :: NestedSets-> set_table_params($ table_name => {fields => \%f、multi => 1});
 ...
    




ノードを挿入



作業のロジックは、トリガーのロジックと同じです。

Perlコード(3)
サブ挿入{
 #着信データを適切に場所に配布し、それに応じて十分なデータがあるかどうかを確認します
     shift if $ _ [0] &&($ _ [0] eq __PACKAGE__ ||(ref $ _ [0] && ref $ _ [0] eq __PACKAGE__));
     my($ table_name、$ new)= @_;
     return {success => 0、error => 'Bad Income data!'} $ dbh && $ table_name && $ new && ref $ new && ref $ new eq 'HASH';
 #どんな種類のテーブルを見つけて、追加の属性とフィールドシノニムを取得します
    私の$ table = $ tables-> {$ table_name} ||  $ tables-> {default};
    私の$ f = $ table-> {fields};
    私の$ result_flags = {is_last_unit => undef};
 #ツリーキーの初期データを決定する
     $ new-> {$ f-> {left_key}} || = 0;
     $ new-> {$ f-> {right_key}} = undef;
     $ new-> {$ f-> {level}} = undef;
     $ new-> {$ f-> {parent_id}} || = 0;
 #親ノードを指定または変更した場合、キーを決定します
     if($ new-> {$ f-> {parent_id}}){
        私の$ sql = 'SELECT'。
                         ($テーブル-> {multi}?$ f-> {tree}。「ASツリー」: '')。
                         $ f-> {right_key}。 '  AS left_key、 '。
                         $ f-> {レベル}。 '  + 1 ASレベル '。
                  「FROM」$ Table_name。
                  'WHERE'。$ F-> {id}。 '  = '。$ new-> {$ f-> {parent_id}};
 #明確にするために、これはクエリです(角括弧はオプションの式です):
 #SELECT [tree AS tree、] right_key AS left_key、level + 1 AS level FROM $ table_name WHERE id = $ parent_id;
        私の$ sth = $ dbh-> prepare($ sql);  $ sth->実行||  return {success => 0、error => $ dbh-> errstr};
        私の$ row = $ sth-> fetchrow_hashref();
         $ sth-> finish;
 #親ノードが見つかったため、キー値を再定義します
         if($ row){
             $ new-> {$ f-> {tree}} = $ row-> {tree} || 未定義
             $ new-> {$ f-> {left_key}} = $ row-> {left_key};
             $ new-> {$ f-> {level}} = $ row-> {level};
         } else {
 #親ノードが見つからないため、parent_idが残っているため、リセットします
             $ new-> {$ f-> {parent_id}} = 0;
             $ new-> {$ f-> {level}} = 0;
         }
     }
 #左キーが指定されている場合、キーを決定しますが、同時に、親ノードが指定されていないか、見つかりません
     if(!$ new-> {$ f-> {parent_id}} && $ new-> {$ f-> {left_key}}){
 #これは重要です! マルチツリーの場合、$ treeパラメーターが必要です
         $ new-> {$ f-> {tree}} && $ table-> {multi};でない限り、{success => 0、error => 'No tree value!'}
 #最初はSQLを使用したかった::抽象的だが、気に入らなかった。複雑なクエリを記述するのは難しくて長い
 #左右のキーでノードを見つける
        私の$ sql = 'SELECT'。
                         $ f-> {id}。 '  AS id、 '。
                         $ f-> {left_key}。 '  AS left_key、 '。
                         $ f-> {right_key}。 '  AS right_key、 '。
                         $ f-> {レベル}。 '  ASレベル、 '。
                         $ f-> {parent_id}。 '  AS parent_id '。
                  「FROM」$ Table_name。
                  「どこ」。
                  ($テーブル-> {multi}?$ f-> {tree}。 '='。$ new-> {$ f-> {tree}}。 'AND': '')。
                  '('。$ f-> {left_key}。 '='。$ new-> {$ f-> {left_key}}。 'OR'。
                  $ f-> {right_key}。 '  = '。$ new-> {$ f-> {left_key}}。')LIMIT 1 ';
 #読み取り可能なリクエスト:
 #選択
 #id AS id、
 #left_key AS left_key、
 #right_key AS right_key、
 #レベルASレベル、
 #parent_id AS parent_id
 #FROM $ table_name
 #どこ
 #[tree = $ tree AND]
 #(left_key = $ left_keyまたはright_key = $ left_key)
 #LIMIT 1;
        私の$ sth = $ dbh-> prepare($ sql);  $ sth->実行||  return {success => 0、error => $ dbh-> errstr};
        私の$ row = $ sth-> fetchrow_hashref();
         $ sth-> finish;
 #左キーでノードが見つかったため、見つかった新しいノード
         if($ row && $ row-> {left_key} == $ new-> {$ f-> {left_key}}){
             $ new-> {$ f-> {parent_id}} = $ row-> {parent_id};
             $ new-> {$ f-> {level}} = $ row-> {level};
 #ノードは正しいキーで検出されたため、新しいノードは検出されたノードの下にあります
         } elsif($行){
             $ new-> {$ f-> {parent_id}} = $ row-> {id};
             $ new-> {$ f-> {level}} = $ row-> {level} + 1;
         } else {
 #繰り返しますが、そのようながらくたは、完全に残ったデータを示しています。 誓うのは良いことですが、今のところ、これらの群れを無視してください。
 #このデータがなくても処理できるため
             $ new-> {$ f-> {left_key}} = undef;
         }
     }
 #実際に、挿入ポイントを取得できなかったか、単に示されていませんでした。
 #ツリーの最後に挿入するため、既存のノードを更新する必要はありません。したがって、対応するフラグを作成します。
     ($ new-> {$ f-> {left_key}}){
         $ result_flags-> {is_last_unit} = 1;
 #これもまた重要です! 複数ツリーの場合は、$ treeパラメーターが必要です。
 #一般に、最初にこれを確認できますが、parent_idを指定した場合、このパラメーターは不要です。
 #次に、ツリーキーの値が決定されます。
         $ new-> {$ f-> {tree}} && $ table-> {multi};でない限り、{success => 0、error => 'No tree value!'}
 #それは簡単です、最大の正しいキーを決定して喜ぶ
        私の$ sql = 'SELECT MAX('。$ f-> {right_key}。 ')+ 1 AS left_key
             FROM '。$ Table_name。
             ($ table-> {multi}? 'WHERE'。$ f-> {tree}。 '='。$ new-> {$ f-> {tree}}: '');
 #読み取り可能なリクエスト:
 #SELECT MAX(right_key)+ 1 AS left_key、
 #FROM $ table_name
 #[WHERE tree = $ tree];
        私の$ sth = $ dbh-> prepare($ sql);  $ sth->実行||  return {success => 0、error => $ dbh-> errstr};
        私の$ row = $ sth-> fetchrow_hashref();
         $ sth-> finish;
 #しかし、ノードがまったくない可能性があるため、喜びは完全ではない可能性があります
         $ new-> {$ f-> {left_key}} = $ row-> {left_key} ||  1;
         $ new-> {$ f-> {parent_id}} = 0;
         $ new-> {$ f-> {level}} = 0;
     }
 #さて、場所で、ツリーのキーを壊すことができると決めました:
     ($ result_flags-> {is_last_unit}){
         my $ query = 'UPDATE'。$ table_name。
                        'SET'。$ F-> {left_key}。 '  =ケース
                                     '。$ F-> {left_key}の場合。  > = '。$ new-> {$ f-> {left_key}}。
                                    それから '。$ F-> {left_key}'。  + 2 ELSE '。$ F-> {left_key}'。  END、
                             '。$ f-> {right_key}'。  = '。$ f-> {right_key}。'  + 2
                      WHERE '。
                      ($テーブル-> {multi}?$ f-> {tree}。 '='。$ new-> {$ f-> {tree}}。 'AND': '')。
                       $ f-> {right_key}。 '  > = '。$ new-> {$ f-> {left_key}};
 #読み取り可能なリクエスト:
 #UPDATE $ table_name
 #セット
 #left_key = left_key> = $ left_keyの場合 
 #THEN left_key + 2 
 #ELSE left_key
 #END、
 #right_key = right_key + 2
 #WHERE [tree = $ tree AND] right_key> = $ left_key;
         $ dbh-> do($ query)||  return {success => 0、error => $ dbh-> errstr};
     }
 #実際、なぜここに来たのか:
 #正しいキーが計算されます
     $ new-> {$ f-> {right_key}} = $ new-> {$ f-> {left_key}} + 1;
 #キーを置きます
     $ new-> {$ f-> {tree}} = $ new-> {$ f-> {tree}} if if table-> {multi};
 #フィールドを特定の順序で表示する必要がある
    私の@fields = keys%{$ new};
 #ここで、非数値の空の行を引用して@fieldsの順に詰めるには
 #そしてはい、少なくとも二重引用符については、ここに来る前にチェックする必要があります
    私の@values = map {defined $ new-> {$ _} && $ new-> {$ _} =〜/ ^ \ d + $ /?  $ new-> {$ _}: '"'。$ new-> {$ _}。 '"'} @fields;
 #実際に挿入
     my $ query = 'INSERT INTO'。$ table_name。 '  ( '。(join'、 '、@fields)')VALUES( '。(join'、 '、@values)。') ';
     $ dbh-> do($ query)||  return {success => 0、error => $ dbh-> errstr};
 #しかし、返すべきものは別の質問です。残念ながら、フェッチせずに挿入された行を返すことはできません。
 #テーブルにはデフォルトのフィールド値がありますが、INSERTでそれらを指定しなかったため。
 #同じSELECTをしましょう
    私の$ sql = 'SELECT * FROM'。$ table_name。 '  ORDER BY '。$ F-> {id}。'  DESC LIMIT 1 ';
    私の$ sth = $ dbh-> prepare($ sql);  $ sth->実行||  return {success => 0、error => $ dbh-> errstr};
    私の$ row = $ sth-> fetchrow_hashref;
     $ sth-> finish;
     return {success => 1、row => $ row};
 }
    


はい、たくさんのコードが判明しました...しかし、コメントを削除すると、行数が半分になります;-)が、はっきりしていると思います。 基本的に:繰り返しますが、親の設定が優先されます。 親が指定され、左のキーが指定されている場合、有効なツリーでは後者が無視されます。 したがって、何かに従属するノードを作成すると同時に、子のリスト内でその場所を指定する場合は、parent_idを渡す必要がないことに注意してください。

Perlコード(4)
 ...私の$ツリー= 1;  #------------------------------------------------- -------------------------------------------------- --------------------#INSERT#座標なしで記録my $ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row1-'。 $ tree、tr => $ tree});  Dumper $ insertに警告します。  #親のあるレコード$ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row2-'。$ Tree、pi => $ insert-> {row}-> {ids}、tr => $ツリー});  Dumper $ insertに警告します。  #left_keyのエントリ$ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row3-'。$ Tree、lk => 1、tr => $ tree});  Dumper $ insertに警告します。  $ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row4-'。$ tree、lk => 4、tr => $ tree});  Dumper $ insertに警告します。  #間違ったパラメーター$ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row5-'。$ Tree、pi => 1000、tr => $ tree});  Dumper $ insertに警告します。  $ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row6-'。$ tree、lk => 100、tr => $ tree});  Dumper $ insertに警告します。  ... 




ノード変更



ツリー構造を(必要に応じて)直接変更することに加えて、変更は必要に応じて他のフィールドにも適用されます。

Perlコード(5)
サブアップデート{
 #受信データを場所に配布し、それに応じて、十分なデータがあるかどうかを確認します
    シフトif $ _ [0] &&($ _ [0] eq __PACKAGE__ ||(ref $ _ [0] && ref $ _ [0] eq __PACKAGE__));
     my($ table_name、$ new)= @_;
     return {success => 0、error => 'Bad Income data!'} $ dbh && $ table_name && $ new && ref $ new && ref $ new eq 'HASH';
 #どんな種類のテーブルを見つけて、追加の属性とフィールドシノニムを取得します
    私の$ table = $ tables-> {$ table_name} ||  $ tables-> {default};
    私の$ f = $ table-> {fields};
    リターン{成功=> 0、エラー=> '悪い収入データ!'} $ new-> {$ f-> {id}};
 #個別に変更できないフィールドは削除します
    削除$ new-> {$ f-> {right_key}};
    削除$ new-> {$ f-> {tree}};
    削除$ new-> {$ f-> {level}};
    私の$ tmp_left_key = $ new-> {$ f-> {left_key}};
    私の$ result_flags = {it_is_moving => undef};
 #さらにジレンマ。 変更を受け入れるには、ソースデータが必要です
 #この場合、どの初期データがあり、どのフィールドが実際に変更されたかはわかりませんが、
 #可変ノードをサンプリングする
    私の$ sql = 'SELECT * FROM'。$ table_name。 '  WHERE '。$ F-> {id}。'  = '。$ new-> {$ f-> {id}};
    私の$ sth = $ dbh-> prepare($ sql);  $ sth->実行||  return {success => 0、error => $ dbh-> errstr};
     $ old = $ sth-> fetchrow_hashref;
     $ sth-> finish;
     return {success => 0、error => 'No old unit!'}が$ oldでない限り;
 #新しいノード座標を計算する
 #親ノードを変更した場合、キーを決定します
     if(定義済み$ new-> {$ f-> {parent_id}} && $ new-> {$ f-> {parent_id}}!= $ old-> {$ f-> {parent_id}}){
         if($ new-> {$ f-> {parent_id}}> 0){
            私の$ sql = 'SELECT'。
                             ($テーブル-> {multi}?$ f-> {tree}。「ASツリー」: '')。
                             $ f-> {right_key}。 '  AS left_key、 '。
                             $ f-> {レベル}。 '  + 1 ASレベル '。
                      「FROM」$ Table_name。
                      'WHERE'。$ F-> {id}。 '  = '。$ new-> {$ f-> {parent_id}};
 #明確にするために、これはクエリです(角括弧はオプションの式です):
 #SELECT [tree AS tree、] right_key AS left_key、level + 1 AS level FROM $ table_name WHERE id = $ parent_id;
            私の$ sth = $ dbh-> prepare($ sql);  $ sth->実行||  return {success => 0、error => $ dbh-> errstr};
            私の$ row = $ sth-> fetchrow_hashref();
             $ sth-> finish;
 #親ノードが見つかった後、キー値を再定義します
             if($ row){
                 $ new-> {$ f-> {tree}} = $ row-> {tree} if if table-> {multi};
                 $ new-> {$ f-> {left_key}} = $ row-> {left_key};
                 $ new-> {$ f-> {level}} = $ row-> {level};
                 $ result_flags-> {it_is_moving} = 1;
             } else {
 #親ノードが見つからないため、parent_idが残っているため、リセットします
                 $ new-> {$ f-> {parent_id}} = $ old-> {$ f-> {parent_id}};
             }
         } else {
 #最高レベルに移行
 #それは簡単です、最大の正しいキーを決定して喜ぶ
            私の$ sql = 'SELECT MAX('。$ f-> {right_key}。 ')+ 1 AS left_key
                 FROM '。$ Table_name。
                 ($ table-> {multi}? 'WHERE'。$ f-> {tree}。 '='。$ old-> {$ f-> {tree}}: '');
 #読み取り可能なリクエスト:
 #SELECT MAX(right_key)+ 1 AS left_key、
 #FROM $ table_name
 #[WHERE tree = $ tree];
            私の$ sth = $ dbh-> prepare($ sql);  $ sth->実行||  return {success => 0、error => $ dbh-> errstr};
            私の$ row = $ sth-> fetchrow_hashref();
             $ sth-> finish;
             $ new-> {$ f-> {left_key}} = $ row-> {left_key};
             $ new-> {$ f-> {parent_id}} = 0;
             $ new-> {$ f-> {level}} = 0;
         }
     }
 #左キーが設定されているが、親ノードが指定されていないか見つからない場合、キーを決定します
     if($ tmp_left_key && $ new-> {$ f-> {left_key}} &&#left_keyが指定された
          $ new-> {$ f-> {left_key}} == $ tmp_left_key &&#parent_idは変更されていません
          $ tmp_left_key!= $ old-> {$ f-> {left_key}}){#left_key changed
 #最初はSQLを使用したかった::抽象的だが、気に入らなかった。複雑なクエリを記述するのは難しくて長い
 #左右のキーでノードを見つける
        私の$ sql = 'SELECT'。
                         $ f-> {id}。 '  AS id、 '。
                         $ f-> {left_key}。 '  AS left_key、 '。
                         $ f-> {right_key}。 '  AS right_key、 '。
                         $ f-> {レベル}。 '  ASレベル、 '。
                         $ f-> {parent_id}。 '  AS parent_id '。
                  「FROM」$ Table_name。
                  「どこ」。
                  ($ table-> {multi}?$ f-> {tree}。 '='。$ old-> {$ f-> {tree}}。 'AND': '')。
                  '('。$ f-> {left_key}。 '='。$ new-> {$ f-> {left_key}}。 'OR'。
                  $ f-> {right_key}。 '  = '。$ new-> {$ f-> {left_key}}。')LIMIT 1 ';
 #読み取り可能なリクエスト:
 #選択
 #id AS id、
 #left_key AS left_key、
 #right_key AS right_key、
 #レベルASレベル、
 #parent_id AS parent_id
 #FROM $ table_name
 #どこ
 #[tree = $ tree AND]
 #(left_key = $ left_keyまたはright_key = $ left_key)
 #LIMIT 1;
        私の$ sth = $ dbh-> prepare($ sql);  $ sth->実行||  return {success => 0、error => $ dbh-> errstr};
        私の$ row = $ sth-> fetchrow_hashref();
         $ sth-> finish;
 #左キーでノードが見つかったため、見つかった新しいノード
         if($ row && $ row-> {left_key} == $ new-> {$ f-> {left_key}}){
             $ new-> {$ f-> {parent_id}} = $ row-> {parent_id};
             $ new-> {$ f-> {level}} = $ row-> {level};
 #ノードは正しいキーで検出されたため、新しいノードは検出されたノードの下にあります
         } elsif($行){
             $ new-> {$ f-> {parent_id}} = $ row-> {id};
             $ new-> {$ f-> {level}} = $ row-> {level} + 1;
         } else {
 #繰り返しますが、そのようながらくたは、完全に残ったデータを示しています。 ノードを最初に置くオプションがありますが、
 #次に、これは間違いではありません。 しかし、他の場合には、移動を無視してください
             $ new-> {$ f-> {left_key}} = $ new-> {$ f-> {left_key}} && $ new-> {$ f-> {left_key}} == 1?  1:$ old-> {$ f-> {left_key}};
         }
     }
 #これで、左のキーが何であるかがわかったので、内側に送信しているかどうかを確認できます
     if($ new-> {$ f-> {left_key}}> $ old-> {$ f-> {left_key}} && $ new-> {$ f-> {left_key}} <$ old-> {$ f-> {right_key}}){
         return {success => 0、error => 'ユニットを内部に移動できません'};
     }
 #座標を計算しましたが、唯一のものは、見て、ツリーに変更があったかどうかです
     if($ new-> {$ f-> {left_key}} && $ new-> {$ f-> {left_key}}!= $ old-> {$ f-> {left_key}}){
 #レベルとツリーのオフセットを定義する
        私の$ skew_level = $ new-> {$ f-> {level}}-$ old-> {$ f-> {level}};
        私の$ skew_tree = $ old-> {$ f-> {right_key}}-$ old-> {$ f-> {left_key}} + 1;
 #ツリーを下に移動する
         if($ new-> {$ f-> {left_key}}> $ old-> {$ f-> {left_key}}){
            私の$ skew_edit = $ new-> {$ f-> {left_key}}-$ old-> {$ f-> {left_key}}-$ skew_tree;
             my $ query = 'UPDATE'。$ table_name。
                            'SET'。$ F-> {left_key}。 '  = '。$ F-> {right_key}の場合。  <= '。$ old-> {$ f-> {right_key}}。'
                                     それから '。$ F-> {left_key}'。  + '。$ skew_edit。'
                                      「。$ F-> {left_key}」の場合のその他の場合。  > '。$ old-> {$ f-> {right_key}}。'
                                               それから '。$ F-> {left_key}'。  -'。$ skew_tree。'
                                                ELSE '。$ F-> {left_key}'。
                                          終了
                                END、
                     '。$ f-> {レベル}。'  = '。$ F-> {right_key}の場合。  <= '。$ old-> {$ f-> {right_key}}。'
                                     THEN '。$ F-> {レベル}。  + '。$ skew_level。'
                                     ELSE '。$ F-> {レベル}'。
                                END、
                     '。$ f-> {right_key}'。  = '。$ F-> {right_key}の場合。  <= '。$ old-> {$ f-> {right_key}}。'
                                      THEN '。$ F-> {right_key}'。  + '。$ skew_edit。'
                                      「。$ F-> {right_key}」の場合のその他の場合。  <'。$ new-> {$ f-> {left_key}}'。
                                                THEN '。$ F-> {right_key}'。  -'。$ skew_tree。'
                                                ELSE '。$ F-> {right_key}。
                                          終了
                                終了
                どこ
                     '。($ table-> {multi}?$ f-> {tree}。' = '。$ old-> {$ f-> {tree}}。' AND ':' ')。
                      $ f-> {right_key}。 '  > '。$ old-> {$ f-> {left_key}}。'  AND '。
                      $ f-> {left_key}。 '  <'。$ new-> {$ f-> {left_key}}。'; ';
             $ dbh-> do($ query)||  return {success => 0、error => $ dbh-> errstr};
             $ new-> {$ f-> {left_key}} = $ new-> {$ f-> {left_key}}-$ skew_tree;
         } else {
 #ツリーを上に移動する
            私の$ skew_edit = $ new-> {$ f-> {left_key}}-$ old-> {$ f-> {left_key}};
             my $ query = 'UPDATE'。$ table_name。 '
                セット
                     '。$ f-> {right_key}'。  =「。$ F-> {left_key}」の場合。  > = '。$ old-> {$ f-> {left_key}}'。
                                      THEN '。$ F-> {right_key}'。  + '。$ skew_edit。'
                                      「。$ F-> {right_key}」の場合のその他の場合。  <'。$ old-> {$ f-> {left_key}}'。
                                                THEN '。$ F-> {right_key}'。  + '。$ skew_tree。'
                                                ELSE '。$ F-> {right_key}。
                                          終了
                                 END、
                     '。$ f-> {レベル}。'  =「。$ F-> {left_key}」の場合。  > = '。$ old-> {$ f-> {left_key}}'。
                                      THEN '。$ F-> {レベル}。  + '。$ skew_level。'
                                      ELSE '。$ F-> {レベル}'。
                                 END、
                     '。$ f-> {left_key}'。  =「。$ F-> {left_key}」の場合。  > = '。$ old-> {$ f-> {left_key}}'。
                                     それから '。$ F-> {left_key}'。  + '。$ skew_edit。'
                                      「。$ F-> {left_key}」の場合のその他の場合。  > = '。$ new-> {$ f-> {left_key}}。
                                               それから '。$ F-> {left_key}'。  + '。$ skew_tree。'
                                                ELSE '。$ F-> {left_key}'。
                                          終了
                                終了
                どこ
                     '。($ table-> {multi}?$ f-> {tree}。' = '。$ old-> {$ f-> {tree}}。' AND ':' ')。
                     $ f-> {right_key}。 '  > = '。$ new-> {$ f-> {left_key}}。  AND '。
                     $ f-> {left_key}。 '  <'。$ old-> {$ f-> {right_key}}。'; ';
             $ dbh-> do($ query)||  return {success => 0、error => $ dbh-> errstr};
         }
     }
 #まず最初に、実際に変更されたフィールドのみを$ newのままにします。
    私の@sets =();
     $キーをforeach(keys%{$ new}){
         #そのようなフィールドはまったくありません
        削除$ new-> {$ key}、次に存在しない限り$ old-> {$ key};
         #コンテンツフィールドは変更されていません
         $ new-> {$ key}を削除、$ old-> {$ key} && $ new-> {$ key} && $ new-> {$ key} eq $ old-> {$ key};
         #コンテンツのないフィールドは変更されていません
        削除$ new-> {$ key}、next if!$ old-> {$ key} &&!$ new-> {$ key};
         #IDは変更しませんが、念のため削除します
        削除$ new-> {$ key}、次に$ key eq $ f-> {id};
 #同じこと、値チェックなし
         @ sets、$キーを押します。  「=」。  (定義された$ new-> {$ key} && $ new-> {$ key} =〜/ ^ \ d + $ /?$ new-> {$ key}: '"'。$ new-> {$ key}。 '"');
     }
 #変更されたフィールドを更新
     my $ query = 'UPDATE'。$ table_name。
                    「SET」(「、」、@ setsに参加)。
                    'WHERE'。$ F-> {id}。 '  = '。$ old-> {$ f-> {id}};
     $ dbh-> do($ query)||  return {success => 0、error => $ dbh-> errstr};
 #繰り返しますが、UPDATE後に行をリクエストします。どのトリガーが更新されたかはわかりません
     $ sql = 'SELECT * FROM'。$ table_name。 '  WHERE '。$ F-> {id}。'  = '。$ old-> {$ f-> {id}}'  LIMIT 1 ';
     $ sth = $ dbh-> prepare($ sql);  $ sth->実行||  return {success => 0、error => $ dbh-> errstr};
    私の$ row = $ sth-> fetchrow_hashref;
     $ sth-> finish;
     return {success => 1、row => $ row};
 }
    


挿入時と同じ優先順位。 送信されるデータの妥当性もチェックされないという事実は、覚えておいてください。

Perlコード(6)
 #------------------------------------------------- -------------------------------------------------- --------------------
 #更新
    
     #ツリーを下に移動する
     my $ update = MY :: NestedSets-> update($ table_name、{field1 => 'row-u-1-'。$ tree、ids => 1、lk => 10、tr => $ tree});
         Dumper $の更新を警告します。
     #ツリーを上に移動する
     $ update = MY :: NestedSets-> update($ table_name、{field1 => 'row-u-4-'。$ tree、ids => 6、lk => 1、tr => $ tree});
         Dumper $の更新を警告します。
     #親を変更
     $ update = MY :: NestedSets-> update($ table_name、{field1 => 'row-u-8-'。$ tree、ids => 2、pi => 5、tr => $ tree});
         Dumper $の更新を警告します。
    




ノードを削除



すぐにコーディング、内部のコメント:

Perlコード(7)
サブ削除{
 #着信データを適切に場所に配布し、それに応じて十分なデータがあるかどうかをチェック
    シフトif $ _ [0] &&($ _ [0] eq __PACKAGE__ ||(ref $ _ [0] && ref $ _ [0] eq __PACKAGE__));
     my($ table_name、$ id、$ flag)= @_;
     return {success => 0、error => 'Bad Income data!'} $ dbh && $ table_name && $ id;
 #どんな種類のテーブルを見つけて、追加の属性とフィールドシノニムを取得します
    私の$ table = $ tables-> {$ table_name} ||  $ tables-> {default};
    私の$ f = $ table-> {fields};
 #渡されるパラメーターの数と量のトリガーのように制限されていないため、
 #削除の実装は二重になります:ブランチ全体を削除し、ツリーの1つのノードを削除します
 #デフォルトでは、ブランチ全体を削除します
     $ flag = {cascade => 'cascade'、one => 'one'}-> {$ flag ||  'カスケード'} ||  'カスケード';
 #削除するノードを選択します。必要なフィールドは、tree、left_key、right_keyの3つだけです
 #それをパラメーターとして渡すことはできますが、何がわからないのか、その前にキーを変更することもできますが、
 #これでツリーが崩れます。
    私の$ sql = 'SELECT'。
             ($テーブル-> {multi}?$ f-> {tree}。「ASツリー」: '')。
             $ f-> {parent_id}。 '  AS parent_id、 '。
             $ f-> {レベル}。 '  ASレベル、 '。
             $ f-> {left_key}。 '  AS left_key、 '。
             $ f-> {right_key}。 '  AS right_key '。
              「FROM」$ Table_name。
              'WHERE'。$ F-> {id}。 '  = '。$ id;
    私の$ sth = $ dbh-> prepare($ sql);  $ sth->実行||  return {success => 0、error => $ dbh-> errstr};
    私の古い$ $ sth-> fetchrow_hashref();
     $ sth-> finish;
     return {success => 0、error => 'No old unit!'}} $ oldでない限り;
     if($ flag eq 'cascade'){
 #ブランチを削除
         my $ query = 'DELETE FROM'。$ table_name。
                    「どこ」。
                         ($ table-> {multi}?$ f-> {tree}。 '='。$ old-> {tree}。 'AND': '')。
                         $ f-> {left_key}。 '  > = '。$ old-> {left_key}。'  AND '。
                         $ f-> {right_key}。 '  <= '。$ old-> {right_key};
         $ dbh-> do($ query)||  return {success => 0、error => $ dbh-> errstr};
 #キーギャップを削除します。
        私の$ skew_tree = $ old-> {right_key}-$ old-> {left_key} + 1;
         $ query = 'UPDATE' $ table_name。
                     'SET'。$ F-> {left_key}。 '  =「。$ F-> {left_key}」の場合。  > '。$ old-> {left_key}。'
                                                    それから '。$ F-> {left_key}'。  -'。$ skew_tree。'
                                                     ELSE '。$ F-> {left_key}'。
                                                END、 '。
                             $ f-> {right_key}。 '  = '。$ f-> {right_key}。'  -'。$ skew_tree。
                     「どこ」。
                         ($ table-> {multi}?$ f-> {tree}。 '='。$ old-> {tree}。 'AND': '')。
                         $ f-> {right_key}。 '  > '。$ old-> {right_key}。'; ';
 #読み取り可能な形式のリクエスト:
 #UPDATE $ table_name
 #SET left_key = left_key> OLD.left_keyの場合
 #THEN left_key-$ skew_tree
 #ELSE left_key
 #END、
 #right_key = right_key-$ skew_tree
 #どこ
 #[tree = OLD.tree AND]
 #right_key> OLD.right_key;
         $ dbh-> do($ query)||  return {success => 0、error => $ dbh-> errstr};
     } else {
 #ノードを削除
         my $ query = 'DELETE FROM'。$ table_name。 '  WHERE '。$ F-> {id}。'  = '。$ id。'  LIMIT 1 ';  #知らない
         $ dbh-> do($ query)||  return {success => 0、error => $ dbh-> errstr};
 #ギャップを削除し、下位ブランチを再構築します
         $ query = 'UPDATE' $ table_name。
                     'SET'。$ F-> {left_key}。 '  =「。$ F-> {left_key}」の場合。  <'。$ old-> {left_key}。'
                                                    それから '。$ F-> {left_key}'。
                                                     「。$ F-> {right_key}」の場合のその他の場合。  <'。$ old-> {right_key}。'
                                                              それから '。$ F-> {left_key}'。  -1 
                                                               ELSE '。$ F-> {left_key}'。  -2
                                                         終了
                                                END、 '。
                             $ f-> {parent_id}。 '  = '。$ F-> {right_key}の場合。  <'。$ old-> {right_key}。
                                                           「AND」。$ F-> {レベル}。  = '。$ old-> {level}。'  + 1
                                                      THEN '。$ Old-> {parent_id}'
                                                      ELSE '。$ F-> {parent_id}'。
                                                 END、 '。
                             $ f-> {レベル}。 '  = '。$ F-> {right_key}の場合。  <'。$ old-> {right_key}。'
                                                  THEN '。$ F-> {レベル}。  -1
                                                  ELSE '。$ F-> {レベル}'。
                                             END、 '。
                             $ f-> {right_key}。 '  = '。$ F-> {right_key}の場合。  <'。$ old-> {right_key}。'
                                                      THEN '。$ F-> {right_key}'。  -1 
                                                      ELSE '。$ F-> {right_key}。  -2
                                                終了
                       WHERE '。
                             ($ table-> {multi}?$ f-> {tree}。 '='。$ old-> {tree}。 'AND': '')。
                            '('。$ f-> {right_key}。 '>'。$ old-> {right_key}。 'OR
                             ( '。$ f-> {left_key}。'> '。$ old-> {left_key}。' AND '。$ f-> {right_key}。' <'。$ old-> {right_key}。')) ; ';
 #読み取り可能な形式のリクエスト:
 #UPDATE $ table_name
 #SET left_key = left_key <OLD.left_keyの場合
 #THEN left_key
 #その他の場合right_key <OLD.right_key
 #THEN left_key-1 
 #ELSE left_key-2
 #END
 #END、
 #parent_id = right_key <OLD.right_key AND `level` = OLD.level + 1の場合
 #THEN OLD.parent_id
 #ELSE parent_id
 #END、
 # `level` = right_key <OLD.right_keyの場合
 #THEN `レベル`-1 
 #ELSE `レベル`
 #END、
 #right_key = right_key <OLD.right_keyの場合
 #THEN right_key-1 
 #ELSE right_key-2
 #END
 #どこ
 #[tree = OLD.tree AND]
 #(right_key> OLD.right_key OR
 #(left_key> OLD.left_key AND right_key <OLD.right_key));
         $ dbh-> do($ query)||  return {success => 0、error => $ dbh-> errstr};
     }
     return {成功=> 1};
 }
    


正直に言うと、結果として返すのに何が正しいかはまだわかりませんが、成功したというフラグだけで十分なようです。

Perlコード(8)
     my $ delete = MY :: NestedSets-> delete($ table_name、2);
     $ delete = MY :: NestedSets-> delete($ table_name、3、 'one');
     $ delete = MY :: NestedSets-> delete($ table_name、4);
    


実際にはそれだけです。 輝くフランネルの布で拭いて、行ってください。



All Articles