[IM] MySQLでエンコードにはまったとき

INTER-Mediatorの話題です。こういうことがあるかどうは微妙かもしれませんが、私の郵便番号検索のサイトで、以下のような状況になりました。

  • 郵便番号検索のアプリケーション(A)はmysql_Connectで稼働している(あー、5.5ではついに書き直さないといかんなー)
  • UTF-8で動いているつもりだったが、MySQLで、エンコーディングの指定をしないままに動かしてしまっていた(これは失敗、でも、UTF-8でなんとなく動いている)
  • その上に、INTER-Mediatorで作った、書籍販売サイト(B)を動かす。これも、なんとなく動いている。郵便番号とは別のデータベースを作ったので、独立しているから問題なかった。
  • INTER-Mediatorでの郵便番号検索ページ(C)をいくつかの理由で立ち上げて、郵便番号データを読み込んでいるデータベースを利用して検索しようとしたら、文字化けた。

とまあ、要するに、2項目目が失敗なのですが、なんとなく動いているという状況下気づかなかったものの、最後の項目ではちゃんとやろうとして失敗に気づいたということです。my.cnfに、エンコードとしてUTF-8をつけると、(C)はきちんと動きました。それから、(A)もきちんと動きました。はいおしまいと思っていたら、(B)が文字化けます。つまり、(A)(B)(C)、同時に動かなくなったのです。なお、(C)の後追加した「character_set_client=utf8」が問題(かどうかも問題)のようで、これはmy.cnfから削除しました。(C)の発覚後、「character_set_server=utf8」も追加しましたが、最終的にはこれは残してあります。

結局どうしたか? (A)は、実は、「SET NAMES utf8」というSQLコマンドを発行して、うまく動かしていたのです。つまり、これを動かさないとうまく行かない大昔の状況のまま運用していて、エンコードの指定が適切でなかったことに気づいたわけです。(A)(B)(C)全部を動かすために結局何をしたかというと、INTER-Mediatorのアプリケーションで「SET NAMES utf8」を実行するようにしました。クエリーするたびにまず、このコマンドを実施して、SELECTを出すようにしました。これも、定義ファイルの設定でできます。こんな感じの定義ファイルです。scriptというキーワードは、FileMakerではよく使いますが、すべてのデータベースで利用可能です。

IM_Entry(
    array(
        array(
            'name' => 'postalcode',
            'view' => 'pcode',
            'records' => 50,
            'maxrecords' => 50,
            'paging' => true,
            'script' => array(
                array(
                    "db-operation"=>"load",
                    "situation"=>"pre",
                    "definition"=>"SET NAMES utf8"
                ),
            ),
        ),
    ),
    null,
    array('db-class' => 'PDO'),
    false
);

そういうことで、あっさりトラブル解決できました。まあ、でも、郵便番号サイトは、今シーズン終わったら、PHP 5.5か5.6で動くように、全面改修だな。

[IM]ページ上のオブジェクトに機能を割り付ける

データベースの内容を一覧するときに、検索結果を適用するという仕組みを一切プログラムを書かずに実現するために、ボタンやテキストフィールド、あるいは一般的なノードに対して機能を割り当てるという考え方を導入しました。要素のdata-im属性を利用して、ローカルコンテキスト(名前は「_」)に特別なキー名でバインドすることで、機能が割り当てられます。今の所、検索ページを作るための以下のものが利用できます。抽象的に記述してもわかりにくいと思いますので、具体的なタグのテキストともに紹介します。

検索条件の付加

テキストフィールドを「_@condition:….」のローカルコンテキストへバインドさせると、そのテキストフィールドに入れた文字列が検索条件になります。また、Enterキーで、コンテキストの更新が実行されます。

 <input type="text" data-im="_@condition:postalcode:f3,f7,f8,f9:*match*">

@以降は、コロン(:)で4つのセクションに分かれます。

  • 第1セクション(例:condition):この文字列
  • 第2セクション(例:postalcode):コンテキスト名
  • 第3セクション(例:f3,f7):フィールド名。複数の指定も可能
  • 第4セクション(例:*match*):演算子

最初の2つはいいとして、3つ目のフィールドは複数指定も可能です。複数指定をすると、それぞれのフィールドに対して同じ値の検索条件をORで与えます。演算子は、一般的なものに加えて「*match」「match*」「*match*」の3つが用意されています。データベースエンジンに関わらずに、部分一致や前方一致などをこの演算子で記述します。

上記のテキストフィールドに、例えば「新宿」と入れてEnterキーを押すと、以下の検索条件がコンテキストに付加されて、再度検索を行い、そのコンテキストのエンクロージャー内が更新されます。

(f3 LIKE '%新宿%' OR f7 LIKE '%新宿%' OR f8 LIKE '%新宿%' OR f9 LIKE '%新宿%')

表示件数の制御

以下のポップアップメニューを選択すると、レコードの表示件数をポップアップの選択肢で指定でき、選択と同時にコンテキストが更新されます。「limitnumber」が決められた名前で、コロンより後にはコンテキスト名を記述します。changeイベントにより、コンテキストの更新します。

<select type="text" data-im="_@limitnumber:postalcode">...</select>

コンテキストの更新ボタン(検索ボタン)

以下のボタンをクリックすると、指定したコンテキストが更新されます。つまり、「検索」ボタンとして機能するということです。「update」が決められた名前で、コロンより後にはコンテキスト名を記述します。clickイベントにより、コンテキストの更新します。

<button data-im="_@update:postalcode">search</button>

並べ替えフィールドの指定

以下のSPANタグ内の▲をクリックすると、f3フィールドの昇順で並べ替えを行います。同一のコンテキストに対する「addorder」の機能を持った要素は連動します。たとえば「f3で昇順」の後に「f9の降順」を選択すると、「f9の降順」を最優先とし、続くキーとして「f3で昇順」を設定します。最後に設定した条件が最優先になるようになっています。このバインドはclickイベントに対応しており、クリックすれば指定したコンテキストが更新されます。

<span style="cursor: pointer" data-im="_@addorder:postalcode:f3:asc">▲</span>

@以降は、コロン(:)で4つのセクションに分かれます。

  • 第1セクション(例:addorder):この文字列
  • 第2セクション(例:postalcode):コンテキスト名
  • 第3セクション(例:f3):フィールド名。1つのみ
  • 第4セクション(例:asc):昇順ならasc、降順ならdesc