関数「getPageList」と、pagesテーブルについて
well > 関数「getPageList」と、pagesテーブルについて @ 2015/1/2 3:24 |
---|
baserCMS関係者の皆様、
2015年 新年あけましておめでとうございます。 本年も益々のご繁栄がありますよう心よりお祈り申し上げます。 久しぶりに、baserCMSで開発途中だったものをいじり出したのですが、 関数とデータベースデータの扱いで、アレっと思うことがありましたので、お話しさせていただきます。 関数名は「getPageList」です。 以前にもウィジェットのPHPテンプレートでテスト導入してみましたが、、 今回は、カテゴリの固定ページの階層はとりあえず2層まで作り、 その下層側の固定ページに、新設の商品テーブルのデータを動的に出力する為に、 ソースをいじり出しました。 簡単な例で説明しますと、 まず、pagesテーブルを確認後、 関数「getPageList」に1か所パラメータ'page_category_id'を追加しました。 app/View/Helper/BcBaserHelper.php
そして、カテゴリリストのリンク先URLを次のように設定しました。 app/webroot/theme/kaizo/Elements/widgets/categoryList.php
デバッグコードで出力させてみると、$page['page_category_id']が、意図したidではなく、 どうやらparent_idになっているようでした。 pagesテーブルを確認するとカラム'page_category_id'にはすべて_page_categoriesテーブルのparent_idの値が入っていました。 関数「getPageList」の目的は、配下に属する子カテゴリのリスト化だと思いますので、ソースを見てそれは達成されいるとわかりましたが、 pagesテーブル内のpage_categoriesテーブルへの外部キーが、表記では'page_category_id'となっていますが、実際は'page_category_parent_id'ですので、矛盾が生じ、拡張性に問題が生じるようです。 ソースの変更、さらにテーブルの設計にも影響する事ですので、改善要望として挙げさせていただきました。 どうぞよろしくお願いいたします。 ■ BaserCMS:3.0.6.1 |
n1215 > Re: 関数「getPageList」と、pagesテーブルについて @ 2015/1/2 14:48 |
---|
well 様
3.0.6.1でBcBaserHelper::getPageList()に単体テストが追加され、 処理も大幅に改修されているのでアップデートしていただければと思います。 https://github.com/baserproject/basercms/commit/e756514becb92599ddd051e30a30cc259c98bf2d また、第二引数に$options配列を取ることができるように変更されています。 メソッドに手を入れずして、取得するフィールドを増やせます。
Twitter: @n_1215 |
well > Re: 関数「getPageList」と、pagesテーブルについて @ 2015/1/3 6:04 |
---|
n1215様
お久しぶりです。 いつもお世話になっております。 新バージョンでの改修情報を教えていただきありがとうございました。 早速ver.3.0.6.1にアップデートし、getPageList()メソッドの確認をさせていただきました。 オプション機能が増えてますね。ただ基本的な設計は前とは変わっていないと思いました。 私の説明の中でもっとも強調したい部分が、やや説明不足だったようですので、 再度説明を付け加えさせていただきたいと思います。 まず、前回の分でもっとも強調したかったのが、下記の部分です。 引用:
具体的な例図で説明させていただきます。
[新規固定ページ登録]でページ登録する際に、カテゴリーを設定できますが、 ここが、親カテゴリを選ぶ前提の設定になっているようで、事前に作った自身と同名のカテゴリを選択しても、URLのページ名が2重になってしまい意図通りに設定はできません。 (例)/BOOK/BOOK やむを得ず親カテゴリを選択した結果、下のようになってしまいます。
[view-source]は以下のようになります
結果として、この関数「getPageList」からは、 page_categoriesテーブルの主キーであるidの値を取得することは難しい状況です。 ■ BaserCMS:3.0.6.1 |
n1215 > Re: 関数「getPageList」と、pagesテーブルについて @ 2015/1/3 9:18 |
---|
なるほどそういうことですか。
引用: [新規固定ページ登録]でページ登録する際に、カテゴリーを設定できますが、 問題を整理しましょう。 ページを保存した時点で、親カテゴリをそのページのカテゴリとして選択したならそのidが参照されるのは当たり前です。 むしろこの状態で設定すらしていない子カテゴリのidを持ってこられるならPHPは一体何の情報を元にしているのでしょう、ということになります。 要望を実現するために、カテゴリのURLの仕様が合わないということですね。 baserCMSにおけるページカテゴリと固定ページはフォルダとファイルのような関係です。 そもそもですが、カテゴリ名とページ名を重複させずに使うのがいいのではないでしょうか? カテゴリとカテゴリに所属する固定ページはレイヤーが違うはずなので、同じ名前が付くところにまず疑問を感じます。 カテゴリとカテゴリを代表する固定ページが一対一で存在し、カテゴリに相当するURLをそのページに用いる場合は、 フォルダの中にindex.htmlファイルを用意するがごとく、 ページをbook/index, book/magazine/indexなどとすることが意図されていると思います。 URLとしてはbook/でもアクセスできます。 もしくは新設の商品テーブルの商品カテゴリとしてページカテゴリを無理に用いるのではなく、 ページ名のslug等を使う設計も考えられます。 これらのようにbaserCMSの仕様の中で要望を実現する方向性では何か問題があるということでしょうか? Twitter: @n_1215 |
well > Re: 関数「getPageList」と、pagesテーブルについて @ 2015/1/3 20:43 |
---|
n1215様、
早速ご解説いただき、誠にありがとうございます。 ああ、そうだなぁ、という具合で得心しました。 cms初心者が陥りやすいトラブルの一つというところでご容赦いただければ幸いです。 だいぶ前ですが、手順としておそらく、2層のうちの上層の各カテゴリ名の固定ページを初めに作ったと思います。 当然、最初は固有のページ名が必要だと思いましたので、単純に各カテゴリの名前をページとして設定しました。またカテゴリはとりあえず「指定しない」にしていたと思います。 その後に、カテゴリ管理メニューでカテゴリ新規追加していき、その後に、再度固定ページ編集で、カテゴリを設定したのでしょう。 その結果、今の状態になったと思われます。 フォルダ、ファイルの階層をよく見て考えれば、気づいたのかもしれませんが、ベテランの方に客観的に指摘してもらうまでなかなか気づかないものですね。 とりあえず1カテゴリについて、2層のカテゴリの固定ページを編集し、上下層それぞれindex.phpとして動作が正常行われることを確認させていただきました。 前述の例でいうと、
これで、無事完了と一瞬思ったのですが、しかしそうとはなりませんでした。 前の意図通りにいかなかった状態が幸いして、都合よくリスト化されていた 以下のgetPageList(6)が、
修正後は
になってしまったということです。 頭を隠したらお尻が出てしまった感じでしょうか。 どうするべきかと考えたのですが、やはりpage_categoriesテーブルのparent_idに目をつけ、 parent_id=6のもののid(20,21,22)を検索して取得するしかないなと思いました。 私のつたない知識で作った新しいメソッドgetCategoryList()は以下の通りです。
しかし、これをこのままではヘルパーに実装できないですよね? PageCategoriesController.phpに入れて試したりもしてるのですが、 modelの指定がうまく行っていないのか何なのか今のところ確認できていません。 これがCMSカスタマイズのハードルの高さでしょうか もし、おわかりになりましたらご教示いただけると幸いです。 どうぞよろしくお願いいたします。 ■ BaserCMS:3.0.6.1 |
n1215 > Re: 関数「getPageList」と、pagesテーブルについて @ 2015/1/4 19:42 |
---|
well 様
どこから説明したものかという感じですが、まずはどこに処理を書くべきかという話から始めましょうか。 ※MVCについて最後に補足を書きます。 あらゆるカスタマイズが許されるなら書く場所自体に論理的な制限はありません。 ただやり方によってはお手軽でもメンテナンスや再利用が大変になるなどということはあり得ます。 コアのコードとどの程度独立しているかという点が一つのポイントかと思います。 ------------------------------------------------------------------- ●1. Helperに書く ------------------------------------------------------------------- 1-1. コアのBcBaserHelperを直接書き換える ------------------------------------------------------------------- lib/Baser/View/Helper/BcBaserHelper.phpを直接書き換えてメソッドを付け加える方法です。 → baserCMSのバージョンアップのたびに書き換えが変更が必要になります。 手軽さ:◎ 保守性:× 1-2. BcBaserHelperをアプリケーション専用の領域にコピーして書き換える ------------------------------------------------------------------- ファイル読込の優先順位を利用し、app/View/Helper/にコピーしてメソッドを付け加える方法です。 http://basercms.net/manuals/3/programmers/3.html → baserCMSのバージョンアップの影響は受けにくくなります。 BcBaserHelperに新メソッドが追加された場合には変更を追う必要があります。 手軽さ:◎ 保守性:△ 1-3. テーマヘルパーを利用する ------------------------------------------------------------------- http://basercms.net/functions/theme_helper にあるように、テーマには独自のヘルパーを含めることができます。 → BcBaserHelperと独立することで影響をさらに受けにくくなります。 テーマを変える際にコピーしないといけない点が唯一難点でしょうか。 手軽さ:○ 保守性:○ 1-4. プラグインでBcBaserHelper用の拡張メソッドを定義する ------------------------------------------------------------------- baserCMSはBcBaserHelperをプラグインから拡張する仕組みを持っています。 http://basercms.net/manuals/3/programmers/5.html テーマヘルパー同様、コアのコードとは独立するので保守は楽ですし、テーマを変更しても使えます。 手軽さ:△ 保守性:◎ ------------------------------------------------------------------- ●2. Controllerに書く ------------------------------------------------------------------- 2-1.PagesControllerを直接書き換える ------------------------------------------------------------------- 固定ページへのリクエストを処理するためのコントローラのメソッドは lib/Baser/Controller/PagesController.phpのdisplay(とmobile_displayとsmartphone_display)になります。 Modelを呼び出してカテゴリの配列を取得しView変数にセットします。 →displayメソッドは複雑なので正直ここに手を付けるのはお勧めしません。 コアを直接書き換えるとさらにややこしくなります。 手軽さ:○ 保守性:× 2-2.PagesControllerをアプリケーション専用の領域にコピーして書き換える ------------------------------------------------------------------- app/Controller/PagesController.phpにコピーしてdisplayメソッドを書き換える方法です。 手軽さ:○ 保守性:△ ------------------------------------------------------------------- ●3. EventListenerに書く ------------------------------------------------------------------- 3-1. イベントでController層の処理に介入する ------------------------------------------------------------------- プラグインでイベントの仕組みを用いてControllerのイベントにフックし、 テンプレートが呼ばれる直前にカテゴリの配列をView変数としてセットする方法です。 →baserCMS/CakePHPのイベントの仕組みを理解する必要があるため、ハードルは少し高いでしょう。 手軽さ:× 保守性:◎ ------------------------------------------------------------------- ※手軽さと保守性の評価は主観です。 実装しようとする機能の複雑さにもよりますが、テーマヘルパーかプラグインによるBcBaserHelperの拡張あたりがお勧めです。 【以下参考】 ●MVCパターン ------------------------------------------------------------------- PageCategoriesControllerをいじっていたということはおそらくMVCを理解されていないのだと思います。 CakePHPやその他のMVCフレームワークが従うMVCデザインパターンは、アプリケーション全体の処理を3つの層に分ける考え方です。 非常に単純化した説明ですが、それぞれの層の役割は下記の通りです。 参考URL: http://book.cakephp.org/2.0/ja/cakephp-overview/understanding-model-view-controller.html * Model → アプリケーションのメインの処理(=ビジネスロジック)を担当する層 文脈によってデータベースを取り扱う層と捉えられることも多い * Controller → ユーザーからのリクエストに応じて適切にModelに処理を任せ、データを受け取り、Viewに受け渡すための層 * View → Controllerを通じてModelから受け取ったデータをどのように表現するか(=ビューロジック)を担当する層 テンプレートはここに含まれる 基本的には構造を分割整理し、それぞれの層の役割を明確にすることで、複雑なアプリケーションの保守しやすさを向上するためのもの、と考えておいてください。 書き捨ての簡易な処理まですべてMVCでやらなければ!と考えるのは大げさですし、 MVCを知らない非プログラマにとっては逆にわかり辛くなるとも言えます。 ●CakePHPの仕様 ------------------------------------------------------------------- CakePHPのデフォルトではURLと、呼び出されるControllerとメソッド(≒Action)が紐づきます。
※baserCMSの固定ページについてはこのデフォルトの規則を変更していますが、管理画面では呼ばれるControllerの名前はわかり易いかと思います。 CakePHPでは、MVCの各層に、繰り返し使う処理をまとめる為のクラスが用意されており Model → Behavior Controller → Component View → Helper となっています。 ●baserCMSの事情 ------------------------------------------------------------------- 理想的にはControllerにおいてModel(PageやPageCategory等)のメソッドを呼び出してカテゴリのデータを取得し、 Viewで利用する変数にセットされるという流れになります。 HelperはViewの中で配列を整形して出力する、くらいの役割分担になるでしょう。 Helperから直接Modelを呼んでHelperにビジネスロジックを記述するのは、MVCパターンに従っているとは言えない設計です。 本来Helperはあくまでテンプレートの処理を手助けする程度の役割しかありません。 それでも、baserCMSは非プログラマへのわかり易さやちょっとしたカスタマイズの簡易さを優先する傾向があり、 Helperを通して様々な処理ができるようになっています。 Twitter: @n_1215 |
well > Re: 関数「getPageList」と、pagesテーブルについて @ 2015/1/8 0:19 |
---|
n1215様、
貴重な情報を丁寧に説明していただき誠にありがとうございました。 これは、baserCMSのカスタマイズを考えている人がまず最初に知っておきたい情報ですね。 公式ページの開発系のトップに是非載せておいて欲しいところです。 引用:
今の私の状況から「テーマヘルパー」で即決させていただきました。 引用:
気になったので、ネットで検索していろいろ調べてみました。 baserCMS2の時から「テーマヘルパー」が使えるようになっていたのですね。 以前は、扱いを誤るとサイトのルーティングが全滅する現象が起きた等の話も知りました(既にフィックスされているとのこと)。 また、ビューからモデルを呼ぶのはなるべく避けるべきとの意見も多く聞かれ、どうしたものかとも思いましたが、まずはとにかく動くようにすることを優先しました。 あれこれ躓きましたが、なんとか、独自の「テーマヘルパー」のメソッドで動くようになり、 カテゴリのリスト化、IDのGET送信、2層カテゴリ下層に分類する商品を固定ページでリストアップする、ところまで確認できました。 app/webroot/theme/kaizo/Helper/BcKaizoHelper.php
app/webroot/theme/kaizo/Elements/widgets/categoryList.php
テーマヘルパーなど情報がさほど多いとは言えないところで、ハマった主な点は、 ・テーマヘルパーがすぐに有効にならなかったこと →命名規則等 ・ヘルパーからのモデルの使用方法 ・メソッドからなかなか値を得られなかったこと。 ・そしてこれは、話が逸れますが、 以前、ドキュメントルートの変更(下記参照)をしたのですが、 http://magazine.barket.jp/article/archives/7 今回のカスタマイズで、気が付けば、themeフォルダが /webroot/app/webroot/theme/[テーマ名] /webroot/theme/[テーマ名] の2系統になってしまっていて(汗 ウィジェット、ヘルパー、imgファイルなど両方ケアしないとうまく動かなかった点。 片方のフォルダを削除してもエラーになるという珍事。 仕方なく、今回新たに別の新Vagrantボックスで、最初からver3.0.6.1をインストールし システム設定のデータメンテナンスのデータの復元で、ドキュメントルートをデフォルト状態で復元させました。 参考にさせていただいたサイト(一部ですが) ・[baserCMS]テーマヘルパを利用してWordPress風味のコンテンツネームを取得する http://qiita.com/materializing/items/adfc767b13fb59be5eef ・ヘルパーからのモデルの使用 http://cakephp.jp/modules/newbb/viewtopic.php?topic_id=2118&forum=7 ・CakePHP 今さらですがClassRegistryクラスのメモ http://web.mt-systems.jp/archives/754 ・baserCMS公式wiki テーマの構造 http://wiki.basercms.net/%E3%83%86%E3%83%BC%E3%83%9E%E3%81%AE%E6%A7%8B%E9%80%A0 n1215様、 ご丁寧にアドバイスしていただいたおかげでCMSカスタマイズに少し道が開いたような気がします。 反面、今後も同様にヘルパーに頼って機能追加していっていいものか不安な気持ちもあります。 ソースなど率直なご感想・アドバイスをいただけますと幸いです。どうかよろしくお願いします。 baserCMS開発スタッフ様、 getCategoryList()メソッドはblogヘルパーにあるようですが、汎用性の高いメソッドですので是非BcBaserヘルパー(固定ページ用)にも作っていただければより安心して使えると思います。ご検討どうかよろしくお願いします。 ■ BaserCMS:3.0.6.1 |
n1215 > Re: 関数「getPageList」と、pagesテーブルについて @ 2015/1/8 14:55 |
---|
引用:
テーマヘルパーなど情報がさほど多いとは言えないところで、ハマった主な点は、 命名規則は確かに引っかかりやすいかもしれませんね。 引用: ・ヘルパーからのモデルの使用方法 CakePHPのコントローラは$usesというプロパティで利用するモデルを簡単に取り込める仕組みになっていますが、(裏ではClassRegistryを用いています) ヘルパーからモデルの利用はそもそも推奨されていないので使いにくいのも当然といえば当然ですね……。 引用: ・メソッドからなかなか値を得られなかったこと。 これについてはPHPの基本である関数や返り値について勉強してくださいとしか言いようがないです コピペと試行錯誤では限界があります。 また、もしテキストエディタなどで開発をされているのであれば、NetBeansやPhpStormなど統合開発環境の利用をお勧めします。 ●その他コードについて テンプレート側は$categoriesという配列の中身を最終的に利用しないということであれば、 目的のカテゴリに対応する固定ページの配列を取りに行くメソッドを追加し、配列を取得する中途処理をHelperに全部移してしまえばすっきりするのではないかと思います。 MVCパターンに従わないまでも、Helperにビジネスロジックをなるべくまとめるなど、ルールを決めておくと後で修正するときの助けにはなります。 ※あくまで自分一人で触っている場合やチーム内で認識を共有できる場合は、ということですが。 また、Helperが太りすぎたのでModelにロジックを移して整理しようとなった時に少し手間が省けます。 ※下記コードはItemモデルを作らずざっと書いただけなので動作は保証しません。
BcKaizoHelper
Itemなる独自のModelを追加しているのであれば、getItemListをModelのメソッドとして実装するのも一つの手です。 PageCategoryモデルなどはコアに含まれるので修正するとバージョンアップが面倒ですが、Itemは貴方の管理下にあるクラスですので。 MVCパターンに従いModelに実装しておくと Controllerなど各所で $this->Item->getListByCategoryId($catgoryId, $options); 等として使いまわせるのが利点です。(使いまわしにくいメソッドを実装すると逆に無駄が出ますが) Twitter: @n_1215 |