自分のための次世代CMS製作メモ
Jeans & Development | 電子ブロック工房 | 三日坊主 | フロントページ |
さらにシンプルにするために その3 [General]
2008年11月26日
風邪で一日仕事を休み、布団に包まったりしてのんびりしながら一日考えてみた。
結論は、3つのメソッド、parse_skin, parse_template, parse_item は、さわる必要がまったくないということ。これら3つのメソッドは、copileメソッドおよびparse_compliedメソッドの実装をラップしている存在であり、インターフェースが違うだけで実質は同じメカニズムを利用しているためである。
(どうも、こういったことをまともに勉強したことが無く独学なので、自分自身で良く分かっていない部分があるのだが、仕方の無いところ。)
他方で、少し変更したいと思っている点は次の通り。skin, template, item用の変数を実装するための各クラスでの記述などが、現在の仕様では別々になっているのだが、これを一元化する。これにより、『template用のメソッドを見つけようとして見つからなかった場合にskin用のメソッドを呼び出す』などの記述が必要なくなり、各変数用のコードがシンプルに記述出来る。
今回の件について、少しまとめてみた。
1)Jeans CMSを利用する上で、スキン・テンプレート・アイテムはそれぞれ異なった概念(Nucleusと同じ)。
2)これらを呼び出すためのviewクラスでのメソッドは、parse_skin, parse_template, parse_itemと、3つ用意されている。
3)スキン・テンプレート・アイテムのパースは、viewクラスに記述された共通のメソッドを通じて実行される。
4)パースされたコードから各変数を記述するためのメソッドは、共通のメカニズムで呼び出される。
つまり、今回の変更で行おうとしているのは、4)の部分だけ。
結論は、3つのメソッド、parse_skin, parse_template, parse_item は、さわる必要がまったくないということ。これら3つのメソッドは、copileメソッドおよびparse_compliedメソッドの実装をラップしている存在であり、インターフェースが違うだけで実質は同じメカニズムを利用しているためである。
(どうも、こういったことをまともに勉強したことが無く独学なので、自分自身で良く分かっていない部分があるのだが、仕方の無いところ。)
他方で、少し変更したいと思っている点は次の通り。skin, template, item用の変数を実装するための各クラスでの記述などが、現在の仕様では別々になっているのだが、これを一元化する。これにより、『template用のメソッドを見つけようとして見つからなかった場合にskin用のメソッドを呼び出す』などの記述が必要なくなり、各変数用のコードがシンプルに記述出来る。
今回の件について、少しまとめてみた。
1)Jeans CMSを利用する上で、スキン・テンプレート・アイテムはそれぞれ異なった概念(Nucleusと同じ)。
2)これらを呼び出すためのviewクラスでのメソッドは、parse_skin, parse_template, parse_itemと、3つ用意されている。
3)スキン・テンプレート・アイテムのパースは、viewクラスに記述された共通のメソッドを通じて実行される。
4)パースされたコードから各変数を記述するためのメソッドは、共通のメカニズムで呼び出される。
つまり、今回の変更で行おうとしているのは、4)の部分だけ。
さらにシンプルにするために その2 [General]
2008年11月24日
さて、アイテムとスキン・テンプレートの所有者がすべてsuperadminだと結論付けられるようになった状態で、改めてこれらをパースするための現在のコードを眺めてみる。
まずは、viewクラスに記述の3つのパース用メソッドの定義部分から。
3つに共通しているのは、$additional_dataの部分。異なっているのは、パースするソースを指定する部分で、文字列を直接受け渡す場合と、ファイルから読み込む場合がある。加えて、テンプレートとアイテムの場合、$dataという、SQLクエリーから得られたrowデータを保持する変数への参照が引数にある。
&$dataに関しては、スキンでも『&$data=null』のようにしておけばよいので、簡単。問題は、パースするソースを、どのようにして、共通のメカニズムで受け渡すかである。
まずは、viewクラスに記述の3つのパース用メソッドの定義部分から。
function parse_skin($skin_or_skinname,$file=null,$additional_data=array()); function parse_template($tempname,$type,$additional_data=array(),&$data=null); function parse_item($item,$admin=false,$additional_data=array(),&$data=null);
3つに共通しているのは、$additional_dataの部分。異なっているのは、パースするソースを指定する部分で、文字列を直接受け渡す場合と、ファイルから読み込む場合がある。加えて、テンプレートとアイテムの場合、$dataという、SQLクエリーから得られたrowデータを保持する変数への参照が引数にある。
&$dataに関しては、スキンでも『&$data=null』のようにしておけばよいので、簡単。問題は、パースするソースを、どのようにして、共通のメカニズムで受け渡すかである。
さらにシンプルにするために その1 [General]
2008年11月24日
ごく初めのころ、次のように書いた。
最初にどんな特徴を持たせるかを考えたとき、テンプレートを廃止して、スキンを多層化しようと思っていたのだが、これが大間違いなアイデアであることが判明した。そもそも、スキンとテンプレートは全く別のもので、テンプレートの概念をスキンに入れ込んでしまうことなど不可能だった。それに、Nucleusのスキンは、parsedinclude などの機能で、すでに多層化が実現している。
始め、テンプレートの概念を廃止しようとして、次にそれが無理であると結論していた。で、再度、テンプレートとスキンの概念を統合しようとしている。以前無理だと考えていたことが可能かもしれないという結論になった背景には、実際にコードを書いてみてテンプレートとスキンの機能を比較することが出来るようになったことがある。
viewクラス(旧jitクラス)には、parse_skin, parse_template, parse_itemという、3つのパース用のメソッドがある。これらを統合して、一つにできないかと考えている。つまり、スキンもテンプレートもアイテムも、すべて同じオブジェクトとして扱うことができないかということ。
最初にどんな特徴を持たせるかを考えたとき、テンプレートを廃止して、スキンを多層化しようと思っていたのだが、これが大間違いなアイデアであることが判明した。そもそも、スキンとテンプレートは全く別のもので、テンプレートの概念をスキンに入れ込んでしまうことなど不可能だった。それに、Nucleusのスキンは、parsedinclude などの機能で、すでに多層化が実現している。
始め、テンプレートの概念を廃止しようとして、次にそれが無理であると結論していた。で、再度、テンプレートとスキンの概念を統合しようとしている。以前無理だと考えていたことが可能かもしれないという結論になった背景には、実際にコードを書いてみてテンプレートとスキンの機能を比較することが出来るようになったことがある。
viewクラス(旧jitクラス)には、parse_skin, parse_template, parse_itemという、3つのパース用のメソッドがある。これらを統合して、一つにできないかと考えている。つまり、スキンもテンプレートもアイテムも、すべて同じオブジェクトとして扱うことができないかということ。
汎用PDOエミュレータ [General]
2008年11月17日
主に(な)さんへ(まだ、SkinabbleAdminでPDO使ってたらだけど)。
JeansでのPDOエミュレータを、バージョンアップした。SQLiteだけでなく、MySQLやpgSQLでの使用も視野に入れてある。
JeansでのPDOエミュレータを、バージョンアップした。SQLiteだけでなく、MySQLやpgSQLでの使用も視野に入れてある。
クラスの継承についてのまとめ [General]
2008年11月16日
現在、リファクタリング中。今までのシステムでは、スキン変数・テンプレート変数について、XMLの記述でどのクラスのどのメソッドを呼び出すかを定義していた。この機能は、変数のオーバライドなどを行うには便利であるが、一方でデバッグを困難にしている。Nucleusのスキンの上位互換を保つのに必要な機能なのではあるが、それは別の方法(取り込む際に書き換える)で実現可能なのは、先日の記事で書いたとおり。
で、XMLの記述でどのクラスのどのメソッドを呼び出すかを定義する機能は残すものの、コアのライブラリのコードでは封印することにした。この機能は、プラグインでのみ使用することが推奨される(コアの機能をプラグインでオーバライドするのに必要)。
基本的に、スキン変数の記述は、例えば次のようにする。
<%xxx%>
<%xxx.yyy%>
<%xxx.yyy.zzz%>
<%xxx%>の場合、xxxクラスのdoSkinVarメソッドを呼び出す。<%xxx.yyy%>の場合、xxxクラスのskinvar_yyyメソッドを、<%xxx.yyy.zzz%>の場合は、xxx_yyyクラスの、skinvar_zzzメソッドを呼び出す。
で、XMLの記述でどのクラスのどのメソッドを呼び出すかを定義する機能は残すものの、コアのライブラリのコードでは封印することにした。この機能は、プラグインでのみ使用することが推奨される(コアの機能をプラグインでオーバライドするのに必要)。
基本的に、スキン変数の記述は、例えば次のようにする。
<%xxx%>
<%xxx.yyy%>
<%xxx.yyy.zzz%>
<%xxx%>の場合、xxxクラスのdoSkinVarメソッドを呼び出す。<%xxx.yyy%>の場合、xxxクラスのskinvar_yyyメソッドを、<%xxx.yyy.zzz%>の場合は、xxx_yyyクラスの、skinvar_zzzメソッドを呼び出す。
非PDO環境のサポート [General]
2008年10月26日
2ヵ月半ぶりの更新。ここのところ、コードをガリガリ書くよりも、基本部分の仕様を決めるための思考実験が続いている。また後日記事を書くが、どうやらスキンに関して、Nucleusに対する上位互換性の維持は切り捨てることになりそう。ただし、完全に切り捨てるのではなく、スキン変数の文法をNucleusと同じにはしないということ。Nucleusのスキンを取り込むときには、専用のプラグインを利用し、このプラグインがNucleusのスキンをJeansのスキンに翻訳して取り込むことで、互換性を確保する予定。
さて、本題。PDOは、PHP 5.1 以降でサポートされている。Jeansは、PHP 5.2以降で動作するように作成するつもり(もしかしたら、5.3以降になる可能性もあり)だから、当然PDOをサポートしているPHPが対象になる。
で、表題の『非PDO環境のサポート』であるが、なぜこんなことが必要かというと、PDOはサポートしていても、PDO-SQLiteのみでPDO-MySQLなどがサポートされていない環境が結構あるようだというのが理由。そういう環境でもJeansでPDOをエミュレートして、通常のMySQL/SQLite/pgSQLなどで使えるようにしようというのが、目的である。
さて、本題。PDOは、PHP 5.1 以降でサポートされている。Jeansは、PHP 5.2以降で動作するように作成するつもり(もしかしたら、5.3以降になる可能性もあり)だから、当然PDOをサポートしているPHPが対象になる。
で、表題の『非PDO環境のサポート』であるが、なぜこんなことが必要かというと、PDOはサポートしていても、PDO-SQLiteのみでPDO-MySQLなどがサポートされていない環境が結構あるようだというのが理由。そういう環境でもJeansでPDOをエミュレートして、通常のMySQL/SQLite/pgSQLなどで使えるようにしようというのが、目的である。
ブログ・カテゴリ・アイテム・タグの関係 [General]
2008年8月14日
先日考えたブログ・カテゴリ・アイテムの関連は、このツールを正常に機能させるには十分であるが、表示のためのSQLクエリーがどのようになるかを考えてみると、どうやらあまりよくない構造になっているらしい。
例えば、あるブログに所属するアイテムの一覧を表示させる場合を考えてみる。これは、多くのサイトでは入り口のページを構成する場合に用いられていて、最もアクセスの多いケースである。先日の方法では、まずアイテムとカテゴリを関連付け、関連付けられたカテゴリをツリーテーブルに従ってどのブログに所属するかを決定し、所属ブログが指定のものになっているケースについて表示することになる。これは、SQLテーブルにインデックスを張ったとしても、無視できない量の情報を操作しなければならない。アイテムの数が増えてくると、表示速度の大幅な低下が起こりうる。
加えて、タグのついたアイテムを表示するケースでは、さらに複雑なクエリーを記述する必要がある。タグのそれぞれについて、所属先のブログを設定すればよいのだろうけれど、この場合には、アイテムの所属先が、タグで指定されたブログなのか、カテゴリーで指定されたブログなのかという問題が生ずる。
例えば、あるブログに所属するアイテムの一覧を表示させる場合を考えてみる。これは、多くのサイトでは入り口のページを構成する場合に用いられていて、最もアクセスの多いケースである。先日の方法では、まずアイテムとカテゴリを関連付け、関連付けられたカテゴリをツリーテーブルに従ってどのブログに所属するかを決定し、所属ブログが指定のものになっているケースについて表示することになる。これは、SQLテーブルにインデックスを張ったとしても、無視できない量の情報を操作しなければならない。アイテムの数が増えてくると、表示速度の大幅な低下が起こりうる。
加えて、タグのついたアイテムを表示するケースでは、さらに複雑なクエリーを記述する必要がある。タグのそれぞれについて、所属先のブログを設定すればよいのだろうけれど、この場合には、アイテムの所属先が、タグで指定されたブログなのか、カテゴリーで指定されたブログなのかという問題が生ずる。
カテゴリーとブログ [General]
2008年8月2日
Nucleusでは複数ブログに対応しているが、当然のことながらJeansでも対応させる。一方で、Jeansでは多層のカテゴリー分けが出来るようにするつもりだ。
Nucleusの場合、サブカテゴリーのためのプラグインを導入しなくても、複数ブログを複数のカテゴリーと考えれば、通常のカテゴリーを一段だけのサブカテゴリーとして扱うことが可能である。このような考え方が出来ることから、複数のブログと複数のカテゴリの間には明確な区分は無いことになる。
ならば、ブログという概念を一切導入せずに、すべてカテゴリという概念だけで処理できるのではないかと考えてみた。ただし、ここでの議論はJeansの内部処理をどう行うかだけについてである。ユーザーにとっては、ブログ及びカテゴリという両方の概念が存在する。
Nucleusの場合、サブカテゴリーのためのプラグインを導入しなくても、複数ブログを複数のカテゴリーと考えれば、通常のカテゴリーを一段だけのサブカテゴリーとして扱うことが可能である。このような考え方が出来ることから、複数のブログと複数のカテゴリの間には明確な区分は無いことになる。
ならば、ブログという概念を一切導入せずに、すべてカテゴリという概念だけで処理できるのではないかと考えてみた。ただし、ここでの議論はJeansの内部処理をどう行うかだけについてである。ユーザーにとっては、ブログ及びカテゴリという両方の概念が存在する。
restriction::restrictHtmlTags()メソッド [Security]
2008年7月27日
先日取り上げた複数ユーザで使用時のアイテムパースでの脆弱性の回避について、結論が出せた。
やはり、ホワイトリストで対処するのが一番確実なやり方なので、利用可能なタグをホワイトリストで用意し、それに該当しないものはずべてhtmlspecialchars()互換の方法で無効化することにした。
やはり、ホワイトリストで対処するのが一番確実なやり方なので、利用可能なタグをホワイトリストで用意し、それに該当しないものはずべてhtmlspecialchars()互換の方法で無効化することにした。
skinの下にtemplate、さらにその下にitem [General]
2008年7月27日
久しぶりに、Jeansのコードを見ている。プログラミングの手を止めて、頭の中でだけ試行錯誤していたときに気になっていたのが、テンプレートエンジンの動作について。
単一のスタティックメソッドを、スキン変数にもテンプレート変数にも対応できるように割り当てられるような仕様は良いのであるが、改めてJeansのコードを眺めてみると、スパゲッティ気味のところもあるような、無いような。
スキン変数の展開や、テンプレート変数の展開には、jitクラスを用いていて、それぞれjit:parse_skin()、jit::parse_tempale()メソッドを利用することになっている。加えて、jit::parse_item()というのもある。これらは結局、同じjitエンジン(self::compile()とself::parse_compiled())を解してコード実行にまわされるのであるが、同じエンジンを用いているにもかかわらず異なる実行内容になるのは、jeans_skinvarテーブルのうち、subtypeカラムの値が異なるものを拾って実行しているからである。
skinの下にtemplateがあり、さらにその下にitemがあるという3段構造になっている。
これをもっとフレキシブルに出来ないのであろうか?最初考えていた、テンプレートの概念をなくしてスキンを多層にするというのがそれなのであるが、もう少し考えてみる余地がありそうである。
単一のスタティックメソッドを、スキン変数にもテンプレート変数にも対応できるように割り当てられるような仕様は良いのであるが、改めてJeansのコードを眺めてみると、スパゲッティ気味のところもあるような、無いような。
スキン変数の展開や、テンプレート変数の展開には、jitクラスを用いていて、それぞれjit:parse_skin()、jit::parse_tempale()メソッドを利用することになっている。加えて、jit::parse_item()というのもある。これらは結局、同じjitエンジン(self::compile()とself::parse_compiled())を解してコード実行にまわされるのであるが、同じエンジンを用いているにもかかわらず異なる実行内容になるのは、jeans_skinvarテーブルのうち、subtypeカラムの値が異なるものを拾って実行しているからである。
skinの下にtemplateがあり、さらにその下にitemがあるという3段構造になっている。
これをもっとフレキシブルに出来ないのであろうか?最初考えていた、テンプレートの概念をなくしてスキンを多層にするというのがそれなのであるが、もう少し考えてみる余地がありそうである。