GoodsunCheckツイートいや、仕事によっちゃ、こう言うのを実現したい時があると思ったし、サンプル化しとけば何かと便利だろうと思って作ってみた。難しそうな気がしていたが、考えようによっては簡単にできるかもしれないと思ったので、プログラム作ってみた。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が設定されているカテゴリオブジェクトにその親カテゴリオブジェクトに対して、自分がそいつの子カテゴリであることを紐付けさせるループ。ここまですることで、カテゴリの親子構造を作成することができる。その他に必要になるだろうメソッドを付け足して完成。