多階層カテゴリ構造を作るクラスを作ってみる
いや、仕事によっちゃ、こう言うのを実現したい時があると思ったし、サンプル化しとけば何かと便利だろうと思って作ってみた。
解説
案外難しそうな気がしていたが、考えようによっては簡単にできるかもしれないと思ったので、プログラム作ってみた。クラスは全部で2つ。1つは抽象クラスで必ず継承してもらう。ので使うときに実質必要なのは3クラスね。
DBにカテゴリデータを保持することを考えて、まずはデータ設計から。まずcategoriesテーブルにはもちろんcategory_idとcategory_nameを定義する。これは絶対。category_idはサロゲートキー、つまりオートインクリメントでプライマリーキーにする。このキーだけは他のカラムと作用しない。基本的にはcategory_idが親であろうが子であろうが、一意にカテゴリを特定するものとなる。
次に親子関係を構築するにはどうするのか考えてみた。parent_idというカラムを作成して、親となるcategory_idを設定する。つまり内部結合テーブルを作る、、、っぽく見えるけど内部結合はしない。というかできない。これではカテゴリの階層を自由にできない。
ということで、ここの部分はプログラムで行うことにする。
でプログラム、もといクラスの設計。まずは、多階層カテゴリを管理するためのMultilevelCategoryという抽象クラスを作成する。このクラスの役割は、全カテゴリの非階層構造の保持、カテゴリの親子構造の保持をする。非階層構造とは親子関係のない、つまり単純にcategoryテーブルをSELECTしたデータを保持する。その時に連想配列でインデックスをcategory_idにしておく。
そして、1つのカテゴリを表すCategoryクラス。このクラスにはカテゴリID、カテゴリ名、親カテゴリのCategoryクラスオブジェクト、子カテゴリのCategoryクラスオブジェクトの配列を保持する。
ここでポイント。
Categoryクラスのオブジェクトは親カテゴリと子カテゴリのオブジェクトを保持する。それぞれのCategoryオブジェクトが自分自身と関係のあるオブジェクトを保持することで、カテゴリ同士のリンク構造を形成する。すごく分かりにくい! けど、そんな感じ。MultilevelCategoryクラスのオブジェクトが保持する非階層構造カテゴリへの参照として親子のカテゴリを作成します。PHPの特徴というかなんというか、別クラスであっても、private変数の参照渡しが可能という仕様。多分上書きとかはできないんだろうね。参照渡しにするのはリソースを節約するため。実際のパフォーマンスや本当にリソースが節約されるかどうかは不明。あとは、参照にしておくことで、オブジェクトの変更を全Categoryクラスのオブジェクトで共有可能ということ。
そして、親子構造の保持にはこれまた非階層構造カテゴリへの参照とする。とにかく、非階層構造カテゴリの配列をマスタデータにするのがポイントとなる。
実際はMultilevelCategoryのコンストラクタで、ここまでの構造を一気に作ってしまう。そのためにカテゴリID、カテゴリ名、親カテゴリIDのデータ定義名を取得するためのメソッドとそのデータを配列で取得するためのメソッドを継承するように制限をかける。これらはMultilevelCategoryでしか使わないので、protected宣言で固定しておく。もちろんコンストラクタはオーバーライドされないようにfinal宣言しておく。
その結果真面目にループ処理して、3回非階層構造カテゴリをなめることになる。
- 1回目は、カテゴリIDを連想配列のキーとする非階層構造のカテゴリオブジェクト群を作成するためのループ。
- 2回目は、親カテゴリIDが設定されているカテゴリオブジェクトに対して親カテゴリのオブジェクトを紐付けるループ。
- 3回目は、親カテゴリIDが設定されているカテゴリオブジェクトにその親カテゴリオブジェクトに対して、自分がそいつの子カテゴリであることを紐付けさせるループ。
ここまですることで、カテゴリの親子構造を作成することができる。
その他に必要になるだろうメソッドを付け足して完成。