[FMRP] 繰り返しフィールド、ポータル、ポータルフィルタ

しばらくさぼってしまっていましたが、FileMaker Relationship Patternsの続きです。

カテゴリ:1対多

名前:繰り返しフィールド

問題:

1エンティティに対して複数のエンティティが存在する場合に、複数のエンティティを一覧表示したい

解決策:

繰り返しフィールドを必要な数、つまり複数のエンティティに対応するフィールドの数だけ定義して、レイアウト上に配置する

フォース:

TO間の結合を定義するのではなく、フィールドのオプション設定として、繰り返す数の上限を1より大きな値に設定する事で、繰り返しフィールドを用意する

繰り返しフィールドで複数のレコードに対する保存は確保できるが、厳密な意味でのテーブル間結合ではなく、第一正規形も満たしていない点を考慮する必要がある

複数エンティティを起点としたリレーションシップは確保できず、集計処理などができない。たとえば、伝票で明細を繰り返しフィールドで作れば「伝票」という帳票は作成できるが、明細行のレコードに関して商品ごとの売り上げ集計はできなくなる。

繰り返し数の上限は、データベースの定義で決める必要がある。繰り返し数が後から足りなくなった場合に増やす事もできるが、データベースの設計変更を伴う

繰り返しフィールドはスクロールができないため、レコード数が多数になると、レイアウトの広い範囲を繰り返しフィールドが占めてしまい、使い勝手が悪いレイアウトができてしまう

関連パターン:

ポータル


カテゴリ:1対多

名前:ポータル

問題:

1エンティティに対して複数のエンティティが存在する場合に、複数のエンティティを一覧表示したい

解決策:

レイアウト上にポータルを配置して、レイアウトのTOとリレーションシップでつながっている別のTOを割り当てる。これにより、レイアウトのTOのレコードと対応関係にあるポータルのTOのレコードが、ポータルに一覧される

フォース:

典型的な1対多の展開である。リレーションで直接つながっているTOだけでなく、複数のTOを経由した先のTOでもポータルには配置できる。

ポータルの中にポータルは配置できない。ポータルの中では1対1のリレーションシップの先の単一のフィールドしか配置できない。

関連パターン:

ポータルフィルタ、繰り返しフィールド


カテゴリ:1対多

名前:ポータルフィルタ

問題:

ポータルに表示するレコードを条件に応じて制限したいが、制約をリレーションシップで定義したくない

解決策:

ポータルフィルタの設定を行う

フォース:

FileMakerのリレーションシップの制約の1つは、複数のTOが存在するTOGにおいて、すでに2つ先になっているTOと直接結合することができないことである。つまり、条件の設定をSQLのように柔軟にできないため、リレーションシップだけで必要なレコードに絞り込むことが困難な場合も出てくる。ポータルフィルタは単にレコードに式をあてはめて、表示するかどうかを判定するだけである。ただし、式に使えるフィールドはリレーションシップに影響する可能性が発生するが、1つの解決方法はグローバルフィールドを用いて条件を与え、式で判定させるということができる点がある。従って、レイアウトに表示するという状況では、リレーション以外に制約を与える方法が存在するため、すべてをリレーションで解決する必要はない。

フィルタにより一部のレコードだけが表示されるが、フィルタの式の結果がすべてtrueつまり、フィルタ前のすべてのレコードを一度は読み込むため、レイアウトを表示した最初のときに非常に時間がかかるケースも発生する。FIleMaker 12の段階では、サーバサイドでフィルタを適用しているのではなく、クライアントサイドで適用していることが原因と考えられる。

関連パターン:

ポータル

INTER-Mediatorのターゲット指定を汎用化する

INTER-Mediatorでのターゲット指定は、タグ要素のclass属性に、IM[table@field@target] といった形式で記述するものだ。これにより、tableで指定したコンテキストにあるfieldというフィールドのデータを、そのタグ要素に埋め込む。targetを省略すると、フォーム要素以外ではテキストノードとして追加し、フォーム要素ではvalueやcheckedなどの適切な属性に設定される。targetでは、Ver.3.8現在、属性名、innerHTML、nodeText、$target、#target、style.styleNameをサポートしている。

このところ、いろいろなものをINTER-Mediatorで作っていて、ある同じようなパタンが頻繁に発生していることに気付いた。それは、

あるフィールドのデータがあれば表示し、なければ表示しない

という動作である。稀に逆もあるのだが、基本は同じだ。これを実現するために、たとえば、FileMakerだと、計算フィールドを利用する。あるフィールドfieldに対して、計算フィールドdisplayField = if ( field != “”; “block” ; “none” )を定義する。そしてたとえば、こんな感じのHTMLを書く。

<div class=”IM[table@displayField@style.display]”>
データ:<span class=”IM[table@field]”></span>
</div>

SQLデータベースなら、ビューを利用するのがいいだろう。たとえば、こんな感じだろうか?

CREATE VIEW tableview AS
SELECT field, if(LENGTH(field)>0, ‘block’, ‘none’) AS displayField FROM table;

これで対処はできるとは言え、もう少し簡単にならないかと考えてしまう。こうしたよくあることを手軽に対処できるというのはフレームワークに要求されることだ。もちろん、1つの方法は、ターゲット指定の3つ目のパラメータを増やす事だ。たとえば、こんなのはどうだろう?

<div>
データ:<span class=”IM[table@field|table@field@parentVisibility]”></span>
</div>

parentVisibilityという名前の属性はないので、HTMLのルールとのコンフリクトはない。フィールドの値が “” あるいは長さが0であれば、visibilityだったら自分自身、parentVisibilityだったら1レベル上位のノードのdisplayスタイルをnoneにするというところだ。

ということで、機能を増やしました…というのはなんかこの段階に来てやることかなと疑問に考えた。もっと汎用的にすべきではないのか?

そこで考えたのが、次のような仕様である。tagetの代わりに、プログラムのステートメントのような書き方をするということ。たぶん、これがいちばん汎用的と思われる。

table@field@object.method(parameters)

だが、いきなりこれだけですというのは敷居を高くするだけじゃないのかと思われるだろう。もちろん、その解決策はある。object.method(parameters)に対するエイリアスを定義することで、従来通りの記述をサポートするようにする。つまり、…@$onclickや、…@innerHTMLという記述はサポートする。ただし、これらはエイリアスという位置づけにする。ただ、内部的には#や$の扱いが微妙だが、これはif文をがんばって書くしかないだろう。

objectは、次の書き方をサポートしようと考えている。(self) (parent) (enclosure) (repeater) つまり、カッコの中に決められたキーワードを記述する。methodとparametersは任意だ。ただ、parametersは(“a”,’b’)なんて書いたときにカッコ内をそのまま渡すのはセキュリティ上の問題が出そうな感じありありであるので、ここは制約を付けることにする。

ターゲットの3つ目に記述する処理のためのオブジェクトINTERMediatorTargetを作っておく。たとえば、そこに、次のように、setInnerHTMLメソッドがあるとしよう。ここでの関数の最初の引数は、フィールドのデータであるというルールを適用することにする。

INTERMediatorTarget {
setInnerHTML: function(d) {
this.innerHTML = d;
}
}

ターゲット指定は table@field@(self).setInnerHTML() と記述する。そして、[(self).setInnerHTML()」のエイリアスが「innerHTML」であるというわけである。

ノード展開の処理では、ターゲット指定のあるノードnodeに対して、その指定に従ったフィールドのデータfieldDataが得られている。ということは、以下のようにapplyを使えばいいということになる。これは、INTER-Mediator内部の話であって、アプリケーションを作る側は気にしなくてもいい。

INTERMediatorTarget.setInnerHTML.apply( node, [fieldData] );

このノードに展開する仕上げに相当する値をセットする部分が現状ではひどくifの応酬となっているので、まずはそれを緩和したい。また、上記のような仕組みだと、INTERMediatorTargetオブジェクトへのメソッド追加や既存メソッドの書き換えにより、フレームワークの動作を改変することも可能だし、独自のターゲット指定記述を作る事もできる。

INTERMediatorTargetに記述する関数では、前記のように第1引数にフィールド値を設定するのはいいとして、汎用性を高めるために、2、3引数はフィールド名とコンテキスト名にする。これで、コンテキストやフィールドに応じて動作を変える事もできてします。

こういう実装を考えているところである。

[IM]MediaAccessクラスと新たな拡張点(3)

こちらの文書、さらにこちらの文書の続きです。

データ生成を指定したクラスにさせ生成結果を返す

URLを使用して、別のシステムにデータを取りに行くことができるということはかなり汎用的になります。しかしながら、別システムとの連動ということになり、開発はやや大変になると同時にセキュリティ面への配慮する場面も増えることになります。そこで、INTER-Mediatorで完結させるために、定義ファイルの呼び出しにおいて、

context.php?media=class://ClassName/path/info

という呼び出しができるようになりました。この場合、ClassNameは定義ファイルと同じディレクトリなど、PHPが取得できる場所にあれば問題ありません。パス情報を付与できますが、mediaキーの値を利用することができるのです。

ClassNameで指定したクラスには、processingというメソッドを記述します。そして、ヘッダを含めた応答すべてをこのメソッドの中で完結させます。

class ClassName {
function processing($contextData, $options) { }
}

スペック上はprocessingというメソッドがあればいいのですが、引数については、とりあえず作ったアプリケーションで必要なものを並べました。$contextDataは、アクセス権の設定と同じ情報をパスに持たせることで、そのレコードのフィールドとデータがキーと値になった配列を設定します。つまり、関連付けられているレコードのデータをそのまま使えるようになっています。現状は、認証の設定がなされていないとこの変数には値は設定されません。$optionは、定義ファイルのIM_Entryの2つ目の値が設定されます。なお、メソッドの引数は今後は増えると思われます。

この仕組みを作って作ったのが『FileMaker as a Relational Database』のサイトです。このサイトでは、書籍を購入した人にPDFおよびePubでの書籍を配布していますが、それぞれパーソナライズをしています。PDFはヘッダに購入者やメールアドレスを入れ込み、ePubでは特定のページに同じような内容のテキストを埋め込んで圧縮・アーカイブします。media=class::…という記述は、そうしたドキュメント生成処理を記述できるような仕組みなのです。

MediaAccessクラスの解説は以上で終了です。

[IM]MediaAccessクラスと新たな拡張点(2)

こちらの文書の続きです。

FileMakerのオブジェクトフィールドを参照する

オブジェクトフィールドはデータベースごとに扱いが異なり、統一的にはやりにくい処理ではあります。MediaAccessクラスでは、FileMaker Serverをターゲットにオブジェクトフィールドに対応する機能を作成しました。

FIleMakerはFXを経由し、XML共有の仕組みを使います。テキスト型や数値型は、基本的にテキストでフィールドにあるデータが得られます。一方、オブジェクトフィールドはオブジェクトそのもののデータではなく、フィールドのデータに応じた以下のような「テキスト」が得られます。

/fmi/xml/cnt/photo.jpg
http://server:16000/…

PDFは完全なURLで、FileMaker Serverに16000ポートで接続して取り出すことが可能です。JPEGなどの画像の場合は、URLのパスに相当するものが得られますが、たとえばIMGタグのSRC属性にそのまま指定が可能な文字列になります。

いずれにしても、両方ともURLであると解釈すればいいわけです。この仕組みはFileMaker Serverに限らず、一般的なアクセスにも使えます。つまり、media=URLと指定をした場合は、そのURLにアクセスしたデータをMediaAccessクラスが取得し、さらにクラスを呼び出した元にそのデータを返します。/fmi/xml/cntで始まる物だけは特別にURLであるという処理が組み込まれています。また、URLかどうかはそれ以外には、httpあるいはhttpsで開始するものかどうかで判定しています。

MediaAccessでのアクセス権

認証が成立したらすべて参照可能となり、成立しなければ参照不可という単純なものなら非常に話が早く、前に説明したmedia-tokenの仕組みで事は足りるのです。なお、データはCRUDの4つの側面がありますが、メディアに関しては「編集」というのはWeb世界ではかなり難易度が高い世界であり、MediaAccessクラスはほぼ参照のみのサポートになっています。

ここで、メディアそのものがログインしたユーザごとのアクセス権を持たせたい場合が出てきます。レコードについては、特定のフィールドにユーザ名やグループ名を入力することで、そのユーザやグループに所属したユーザでないと参照や更新ができない仕組みを持っています。フィールドのデータはそれでいいのですが、メディアは実体はレコードと別に有ります。ここで、個々のメディアをコンテキストのレコードと結合させ、レコードごとのアクセス権をメディアにまで及ぼす仕組みを組み込みました。

まず、IM_Entry関数の2つ目の引数(オプション引数)に、キーが’media-context’で値がコンテキスト名(コンテキストのnameキーに対する値)を与えます。すると、メディアはこのコンテキストにある特定のレコードの、1つのフィールドのようなふるまいになります。

‘media-context’ => ‘context-name’,

実際にメディアにアクセスするパスは次のような形式にします。つまり、コンテキスト名、レコードの検索条件をパスに入れます。最初のfilesは特に意味はなく、相対パスの最初のキーワードです。context-nameは、media-contextの値と同じでなければなりません。そのコンテキストのkeyキーに対する値、つまり主キーがpidであるなら、たとえば、field=valueは、pid=312 のような値になります。

context.php?media=files/context-name/field=value/filename.png

ここでもし、media-root-dirが /var/www/media であるなら、実際に

/var/www/media/files/context-name/pid=312/finename.png

という絶対パスの画像ファイルが存在する必要があります。コンテキストの定義には、レコード単位のアクセス権設定があれば、メディアに対するアクセス権の認証の確認を行い、ユーザを特定します。pid=312のレコードがそのユーザにアクセス権があるのかどうかを確認することによって、アクセスの可否を決めます。従って、適当にpid=316などとパスを変えても、その条件で検索されたレコードが他のユーザに対する権利があるものであれば、400番台のレスポンスを返してデータは返しません。認証の確認を行い、そのユーザに対するアクセス権がないものは出力しないという仕様によりアクセス権は定義した通りに適用されます。

pid=312を、age=45のようにできると言えばできますが、おそらく、そういうディレクトリは存在せず、漏洩にはならないでしょう。

ファイルのアップロードのコンポーネントは、コンテキスト名やレコード検索条件のパスを自動的に作成するようにも作られています。

とまあ、ここまで書いたところで、ソースに間違いを発見! また、グループ名をフィールドに入れる場合はまだ実装していなかったことも思い出しました。今のところ、メディア関連処理は、開発している側で「必要の合った」状況しかうまく動かない可能性があります。ぜひとも、いろいろ試してフィードバックをください。

(まだ続く)

[IM]MediaAccessクラスと新たな拡張点

INTER-Mediatorはデータベースの内容を取り出し、Webページに展開し、場合によっては書き直したデータをデータベースに書き戻します。この一連のDBを中心としたデータの流れがあるのですが、Webアプリケーションではこれだけではすべてはまかなえません。HTMLでページを作るときは写真などの画像を別のファイルで供給します。このHTML外に実データが存在するようなものを「メディア」と呼ぶことにします。

メディアにはいろいろな種類があります。主要なものはIMGタグ要素で表示する画像、OBJECTタグなどで表示するFlashのコンテンツやビデオなど、そしてリンク先で得られるものとなるでしょうか。また、それぞれ、サーバ上にスタティックにあるものや、データベースのオブジェクト型フィールドに存在する場合もあります。WebページからこれらにアクセスするためのものがMediaAccessクラスです。概ね、次のような用途に使用方法は分類できます。

  • サーバ上にある画像ファイルを参照する
  • FileMakerのオブジェクトフィールドを参照する
  • データ生成を指定したクラスにさせる、生成結果を返す

ここで、単なる画像は普通にHTMLを書けばいいじゃないかと思うかもしれませんが、MediaAccessクラスを使う理由は、認証やアクセス権の設定との連携が可能になっているところです。

サーバ上にある画像ファイルを参照する

スタティックな画像で、認証が絡まない場合は、普通にIMGタグを記述します。また、画像ファイル名やパスがデータベースにある場合でも、必ずしもMediaAccessクラスは必要ないかもしれません。たとえば、あるテーブルのfilepathフィールドにファイル名が記録されているのなら、このようなIMGタグで表示できるでしょう。#srcにより、この要素のSRC属性にフィールドのデータが追加されます。

<img src=”figs/” class=”IM[context@filepath@#src]” />

ページの内容を認証しなければ参照できないようにしたとき、やはりページに埋め込んだ画像なども認証を経由したいと考えます。Webサーバレベルでの認証の場合は、ある意味、認証がない場合と概ね同じことで可能ですが、INTER-Mediatorの認証機能を使った場合、SRC要素がスタティックな画像を参照していれば、もしかしたら、認証しなくても画像だけは見えてしまうかもしれません。そんなことをしても大した情報流出にならないとも言えるのですが、ガードしたいものはガードするのが基本ですし、認証しているのに一部は誰でも見えるのは正しい運用ではありません。

そこで、IM_Entry関数の2つ目の引数(つまりオプション引数)に、’media-root-dir’というキーで、サーバ上にあるメディアファイルのフォルダへのルートからの絶対パスを指定しておきます。たとえば、

‘media-root-dir’ => ‘/var/www/images’,

となっていたとします。あるページファイルで使われている定義ファイルのパスがcontext.phpだったとします。すると、次の部分URLが、メディアを返します。ここで背後では、MediaAccessクラスが使われており、このクラスがメディアに対するプロキシになっているとも言えます。

context.php?media=ch1/shot345.png

たとえば、IMGタグのSRC属性に上記のURLを記述すれば、media-root-dirと合成して、「/var/www/images/ch1/shot345.png」というファイルをアクセスし、その内容を取り出して、適切なMIMEタイプのヘッダとともに出力をします。

前記のURLにある画像ファイル名「shot345.png」がフィールドpicfileにあるような場合には、ページファイルの要素には以下のような記述ができます。media=は決められたキーワードです。

<img src=”context.php?media=ch1/” class=”IM[table@picfile@#src]” />

このとき、定義ファイルで認証が必要な設定になっていると、SRC属性のURLからの取得時にMediaAccessクラス内部で、認証の確認を行います。ここで、一般の認証時に使っているクレデンシャルをそのまま使うことが実はできません。一般の認証では、1つのアクセスごとに異なるチャレンジデータを使うことで、認証の乗っ取りをしにくくしています。しかし、そのためにメディア処理ではその仕組みが使えません。なぜなら、メディアへのアクセスは並列的にブラウザから行うからです。

そこで、メディアアクセス時の認証のためだけのクレデンシャルを生成させるようにしています。たとえば、直前のimgタグ要素の場合、tableという名前のコンテキストからの取得となりますが、そのコンテキスト定義(IM_Entry関数の第1引数)の’authentication’キー内部の’media-handling’キーの値をtrueにします。すると、このコンテキストのデータを取得するときに、サーバ側からメディア用のクレデンシャルを出力します。

IMGタグ要素などから実際にメディア取得を定義ファイルに対して行うとき、media=があれば、MediaAccessクラスに処理をまかせます。そのとき、クレデンシャルがクッキーに記録されてサーバ側に到達し、それを発行したクレデンシャルと比較することで認証が通っているかどうかを判定します。つまり、コンテキストが得られるということは認証が通っているわけで、その信頼関係をもとに秘密の合い言葉をやりとりします。このクレデンシャルは繰り返し使われる可能性があります。クッキーに記録し、時間が来れば消去するようにはなっているものの、クレデンシャルを盗まれるのはそれだけでメディアアクセスを可能にしてしまうことになります。従って、HTTPS(SSL)でのサーバ運用は必須とも言えるでしょう。

普通のHTMLでMediaAccessを経由させる

Webページを作って画像を埋め込むと、<img src=”img/cover.jpg” /> などと記述します。これをMediaAccessクラスを使ってデータの取り出しを行いたいとしたら、ソースを全部変更しないといけないのかというとそうではありません。リダイレクトを使うことで、HTMLソースはそのままに、MediaAccessクラスを使うことができます。たとえば、.htaccessファイルを作り、たとえば次のような記述を作ります。

RedirectMatch img/(.+) http://host.name/myapp/context.php?media=$1

すると、<img src=”img/cover.jpg” /> は、<img src=”http://host.name/myapp/context.php?media=cover.jpg” /> と同じことになるわけです。

部分パスと絶対パス、それらを消したり追加したりといろいろ複雑にはなりますが、このスタティックなメディアを認証した上で表示できるようにしたのがMediaAccessの最初のインプリメントでした。

(この内容、続く)

Booking.comを騙るメール

来ました。予約した覚えはないのですが、1泊で1800ドルとはゴージャスなものです。ただ、よくあるタイプの別のサイトへの誘導は明示的ではなく、HTML内にあるのリンクはちゃんとbooking.comに行きますね。しかし、金額は書いてあるけど、どこのホテルか書いていない。そんな予約はありえないでしょう。このメールアドレスで昔booking.comを使った可能性もあるのですが、なんとアカウントは作られていませんでした。まあ、これでほとんど安心なのですが、念のためアカウントを作ってみたのだけどやはり予約は入っていません。また、添付するzipを展開するとexeが入っていたので間違いなく、嘘メールでしょう。あと、巧妙なのは、本物のBooking.comの広告メールと同じような時間に配布しているところですね。

だけど、ClamXavだとマルウェアと判定はしませんでした。Booking.comには似たような警告はありますが、このメールではなく、1年ほど前の別のもののようです。ということで、警告の意味も含めてブログに記載します。1ヶ月ぶりの書き込みがこんな話題ですんません。

スクリーンショット 2013-08-06 14.52.52 スクリーンショット 2013-08-06 14.53.09

上から目線を評価する

「上から目線は言った側も言われた側も上から目線である」

「上から目線でものを言うんじゃない!」などと表現されるこの言い回しはもはや説明の必要がないくらい常套句となっています。下の立場の人から、上の立場のような言い方をされたときに、失礼だとか、お前に言われたくないよという意味で使われます。「上から目線の対処法」という記事が検索すると上位に来ます。確かに、認めてもらいたいがために上から目線になるというのは理解できますし、このページの対処法は確かにポジティブな対処法です。

役職や身分が決まっているならともかく、同等な相手で「上から目線」を感じるということは、言われて感じた側が「自分の方が上である」という認識をしているということでもあります。つまり、「低い位置で上から目線になっても、視野が極端に狭いだけじゃないのか」と感じることになるでしょう。

経過や大局を見ないで、その人が知っている範囲だけの知識で、大きな結論を出すような行為は、言われた側には狭い視野しかないのは一目瞭然だったりします。言われた側の方が、より広く多くの情報が分かっていることがやりとりで明確になれば、言われた側は自分が上であると判断し、相手を「上から目線」と思うわけです。

言う側も、言われる側も、そうなると所詮、自分の範疇が中心となりがちです。相手のことを知り、相手が何を考え、何を欲しているかを考慮するというコミュニケーションの原則もつい忘れがちです。上から目線でものを言わないようにしろと言うのは簡単ですが、上から目線でものを言われたとき、言った人の目線を水平にできるかどうかという点も、言われた側の器量が試されているのではないでしょうか。そして、自分の目線も水平にできるでしょうか?

怒る前に、そして怒ってもすぐに冷まし、そこから上から目線になる理由を探ることは、その人1人とのコミュニケーションだけでなく、重要なことを怠っていたことも分かるかもしれません。伝達されていない情報があったり、誤解されているということを探る機会になるのではないでしょうか。

[IM]PHP Ver.5.3 on OS Xで、APCを稼働させる方法

ファイルのアップロードをするときのプログレスバーを出す方法が「A Simple PHP Upload Progress Bar」というページに紹介されています。シンプルなのでやりやすそうと思われるのか、このサイトのスクリプトを単にコピーしただけのサイトなんかもあります(せめて出展くらい出すべきでしょう)。

当初、動かし方を紹介したサイトはないかと思って探したのが「Mac OS XのPHP 5.3にAPC(Alternative PHP Cache)をインストールする方法」というサイトでした。OS X Lion時代のものなのかこの通りでは動かなかったので、追加で必要な作業をまとめてみました。

プログレスバーを出す仕組みはちょっとややこしいのですが、ポイントの1つはPHPのAPC(Alternative PHP Cache)という機能を利用することです。残念ながら、PHP 5.3では生の状態ではこの機能は使えません。この機能を、OS X Moutain Lion + OS X Server Ver.2.2 + FileMaker Server 12という状況で使えるようにする方法を解説します。PHPは、Ver.5.3.13です。FileMaker Serverでない場合php.iniファイルの扱いが違ってくると思われます。

  1. Webサーバ稼働マシンに、Xcodeをインストールしてください。Xcode 4.6.2で以下の動作は確認しています。
  2. MacPortsをインストールします(インストール済みならもちろん何もしなくてもOKです)。まず、以下のコマンドでダウンロードします。以下のURLはアップデートにより変更されるかもしれません。
    curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.1.3-10.8-MountainLion.pkg
  3. 以下のコマンドでインストーラを使ってMacPortsをインストールします。
    sudo installer -target / -pkg MacPorts-2.1.3-10.8-MountainLion.pkg
  4. 以下のコマンドで、autoconfiをインストールします。
    sudo port install autoconf
  5. 以下のコマンドで、pcreをインストールします。
    sudo port install pcre
  6. 以下のコマンドで、ヘッダファイルの1つをコンパイラが認識するディレクトリにコピーします(参考)。
    sudo cp /opt/local/include/pcre.h /usr/include
  7. APCのソースをダウンロードします。URLはアップデートによって変更があるかもしれません。
    curl -O http://pecl.php.net/get/APC-3.1.13.tgz
  8. アーカイブを展開します。
    tar zfvx APC-3.1.13.tgz
  9. カレントディレクトリに移動します。
    cd APC-3.1.13
  10. 以下のコマンドを入れます。
    phpize
  11. 次のように表示されます。warningがありますが、問題ない模様です。
    Configuring for:
    PHP Api Version: 20090626
    Zend Module Api No: 20090626
    Zend Extension Api No: 220090626
    configure.in:3: warning: prefer named diversions
    configure.in:3: warning: prefer named diversions
  12. おなじみの以下のコマンドでコンパイルします。
    make
    sudo make install
  13. 最後のコマンドで以下のようなメッセージが表示されます。1行目のパスをphp.iniファイルに記述するので、コピーしておくといいでしょう。
    Installing shared extensions: /usr/lib/php/extensions/no-debug-non-zts-20090626/
    Installing header files: /usr/include/php/
  14. php.iniファイルを変更します。以下のパスは、Mountain Lion + FMS12の場合です。使用する状況に合わせて正しいphp.iniファイルを編集します。もし、ない場合は、/etc/php.iniあたりに作成します。使用しているphp.iniファイルのパスを調べるには、phpinfo関数の出力を利用しましょう。
    sudo nano ‘/Library/FileMaker Server/Web Publishing/publishing-engine/php/mountain lion/lib/php.ini’
  15. php.iniファイルに以下の3行を追加します。これらの設定をいままで全く行っていないのなら、そのまま追加でかまいません。すでに設定がないかどうかは検索して確認しましょう。
    extension_dir=/usr/lib/php/extensions/no-debug-non-zts-20090626/
    extension=apc.so
    apc.rfc1867=on
  16. 以下のコマンドを入力して、Apacheに設定変更を適用させます。
    sudo apachectl graceful
  17. phpinfo関数の出力を見て、APCのカテゴリがあることと、apc.rfc1867の値が「On」になっていることを確認します。

ポイントとしては、APCのコンパイルのために、autoconf、pcreが必要である点です。また、APCの設定は既定値ではrfc1867はOffですので、設定ファイルで記述してオンにしておく必要があります。

なぜ、この記事のカテゴリにINTER-Mediatorがあるかというと、この仕組みをINTER-Mediatorに組み込んだからです。

スクリーンショット 2013-06-16 16.44.40

[IM]新規レコード作成時の挙動

INTER-Mediatorで、テーブルに新たにレコードを作るときの挙動にバグがあり、全体的に見直しをしました。以下の内容は、Ver.3.4以降で有効です。

まず、「新規レコード作成」のクライアント側でのAPI、つまり、JavaScriptベースでの呼び出しは4カ所あります。最初の3つは、主としてINTER-Mediator自身が使うものです。

  • INTERMediator.insertButton(…):レコードの繰り返しの下などに表示されるボタン
  • INTERMediator.insertRecordFromNavi(…):ナビゲーションのボタン
  • INTERMediator.clickPostOnlyButton(node):新規レコード作成専用モード
  • INTERMediator_DBAdapter.db_createRecordWithAuth(args, completion):汎用

最後のメソッドは、INTERMediator_DBAdapter.db_createRecordでもかまいませんが、上記のメソッドだと認証のある場合、ない場合、どちらでも利用できます。

さて、データベース処理に関係する定義ファイル内のコンテキストのキーはまとめるとこんな感じです。ここでは、レコード作成に絞って考えます。

  • name:コンテキスト名、tableがないとこの名前のテーブルにINSERTする
  • table:実際のテーブル名を記述
  • view:(無視)
  • records:(ナビゲーションのボタンでレコードを作ったときの動作に影響)
  • key:(同上)
  • relation:(関連レコードの作成時に利用)
  • query:(この設定は無視する)
  • sort:(無意味)
  • default-values:(フィールドの初期値)
  • script:(新規レコード作成時に実行するスクリプトを指定、主にFileMaker)
  • アクセス権設定:(新規レコードの認可の定義)

一時期のINTER-Mediatorでは、queryキーで指定した内容を、初期値として設定するようなプログラムが組み込まれていました。そうしないと、新規レコードを作った後に「検索されない」という状況が発生するからです。しかし、それはdefault-valuesキーで指定をすることで、検索される状態は設定できるので、あえて、queryキーを無視するようにしました。

一方、relationキーについては、関連レコードのテンプレート処理側では、これに対応した外部キーへの値の設定がないと、新しく作ったレコードは関連レコードになりません。なので、INTERMediator.insertbuttonメソッド内で、コンテキストのこの情報を見て、外部キーのフィールドの初期値を自動的に与えています。なお、演算子は無視しているので、演算子に>があるような場合などは要注意です。INTERMediator.insertRecordFromNaviメソッドは、ナビゲーションのボタンで呼び出されます。従って、通常は関連レコードのコンテキストには適用されず、relationキーは無視します。INTERMediator_DBAdapter.db_createRecordWithAuthについても、relationキーは無視します。

一方、JavaScriptのプログラムで、検索条件、ソート条件、さらに新規レコードの初期値を指定するプロパティが以下のように定義されています。新規レコードの初期値はVer.3.4が初出です。

  • INTERMediator.additionalCondition:(無視する)
  • INTERMediator.additionalSortKey:(無意味)
  • INTERMediator.additionalFieldValueOnNewRecord:(初期値として適用される)

新規レコードではソート条件は関係ありません。検索条件のINTERMediator.additionalConditionについては、新規レコード作成時は一切無視されます。一方、すべての新規レコード作成時に、INTERMediator.additionalFieldValueOnNewRecordに指定した値が初期値として設定されます。

まとめると、新規レコード作成時には検索条件は一切利用しません。その代わり、スタティックな初期値としてのdefault-valuesキー、ダイナミックな初期値としてのINTERMediator.additionalFieldValueOnNewRecordが適用されます。また、関連レコード内でのInsertボタンを押したときにはrelationキーの値が利用されますが、その他の場合にはrelationキーは適用されません。