webプログラミング



2011 7月30日

DBIx::Custom – search.cpan.org
DBIx-Custom-0.1705

DBIx::Custom select メソッドの whereの項目を見ると様々な指定方法が出来ることが分かる。

注意する点はStringを渡す時。

Selec All Code:
where => "url = 'http://hoge.com/huga.cgi?key=value' ",

上のように条件に ? が含まれる場合、SQLの作成に失敗する。(DBIx::Custom::QueryBuilder::build_queryでかな?)

? がメタ文字として扱われるため?(\?とエスケープしてもダメ)

Hashリファレンスで渡すと大丈夫です。

Selec All Code:
where => {url => 'http://hoge.com/huga.cgi?key=value' },

これを踏まえてコードにすると、安全なのはこんな感じのコードになるのかな。

Selec All Code:
    my $id = 1;
    my $url = 'http://hoge.com/huga.cgi?key=value';
    $result = $dbi->select(
        table   =>  'table_name',
        column  => [qw/title content url/],
        where => [
                    ["and", "{= id}", "url = :url", "update_time > SUBDATE( NOW(), interval 7 day )"],
                    { id => $id, url => $url},
        ],
    );

※ {= id} は “id = :id” とも書ける(url = :urlも同様)。あえて両方含めてみた。

where にはDBIx::Custom::Whereオブジェクトも指定できますが、DBIx::Custom::Whereオブジェクトを生成する時にも同様で、? を含めた条件には注意が必要。

追記:タグ機能は廃止予定だそうです。
http://twitter.com/#!/perlcodesample/status/97162783644319744







2011 7月29日

perlモジュールのバージョンを一発で調べられるコマンド

$ pmvers DBIx::Cutom
0.168

cpanmがインストールしてあれば

$ cpanm pmvers

でインストールできます。

もうこんな事しなくていいんです。

perl -MDBI -e 'print $DBIx::Custom::VERSION'






2011 7月29日

DBIx::Customが生SQL感覚でも使えてお気に入りなのだけれど、ちょっこしハマったのでメモ。

DBIx::Custom – search.cpan.org

MySQL(に限らないと思う)でwhereに関数を利用したい時は多々あると思います。
例えば、更新時刻を見て7日以上古ければ選択しないという条件をwhereに指定したい時、

Selec All Code:
CREATE TABLE  `table` (
    `name` VARCHAR( 5 ) ,
    `update_time` TIMESTAMP
)
 
SELECT * FROM `table` WHERE update_time > SUBDATE(NOW(), INTERVAL 7 DAY);

このようなSQLだとします。

行の選択 select / DBIx::Custom リファレンス – サンプルコードによるPerl入門によれば、where句の設定は、

Selec All Code:
where => {title => 'Perl', author => 'Ken'}

と、ハッシュリファレンスで渡すことになっています。

= 以外での比較は DBIx::Custom::Whereオブジェクト を作成して渡すことになっているのですが、ハッシュリファレンスで SUBDATE(NOW(), interval 7 day) を渡すとうまくいかないので悩んでいました。

append => ” で文字列を追加できるので、無理やり実装してみたのですが作者にツイートしてみたところ、

twitterのキャプチャ

がーん、そうなのか。恥ずかしい。。さらに、

twitterのキャプチャ2

がーん、DBIx::Custom::Where でも文字列が指定できたのか。。。(恥恥

という事で、

Selec All Code:
use DBIx::Custom;
my $dbi = DBIx::Custom->connect(
    ...........  端折ります
);
my $result = $dbi->select(
    table => 'table',
    where => 'create_time > SUBDATE(NOW(),  interval 7 day)', 
);

あるいは、

Selec All Code:
use DBIx::Custom;
my $where = $dbi->where;
$where->clause([
    'and', 'create_time > SUBDATE(NOW(),  interval 7 day)'
]);
my $result = $dbi->select(
    table => 'table',
    where => $where, 
);

で、出来るって事なんですね。(ソース嫁!)

id:perlcodesampleさんありがとうございました!
DBIx::Customいいよー。

ところで

SYNOPSYSにあるinsertとかupdateとかが失敗するのはボクの日頃の行いが悪いせいでしょうか?

Selec All Code:
    # Insert 
    $dbi->insert({title => 'Perl', author => 'Ken'}, table  => 'book');
 
    # Update 
    $dbi->update({title => 'Perl', author => 'Ken'}, table  => 'book',
      where  => {id => 5});
Selec All Code:
    # Insert 
    $dbi->insert( param => {title => 'Perl', author => 'Ken'}, table  => 'book' );
 
    # Update 
    $dbi->update( param => {title => 'Perl', author => 'Ken'}, table  => 'book',
      where  => {id => 5} );

だと性交いや、成功するのですが。
param が必要??(だからソース嫁!)

追記:DBIx::Customのバージョンが 0.168 だったからのようです…APIが追加された模様。







2011 6月12日

とあるスクリプトで javascriptでiframeを書き、そのフレームをさらに書き換える・・・というものがあるのですが、スクリプトをページ内に複数設置すると、chromeでエラーになってしまうので回避策。

今までは

document.write('<IFRAME id="フレーム名" name="フレーム名" ....></IFRAME>');

で描写して、ターゲットとなるiframeを

var target_iframe = frames[フレーム名];

で取得していたのですが、これが2度目以降の実行時にundefinedとなってしまう。

var target_iframe = document.getElementById(ifrname).contentWindow;

でもやはり取得できず。
他のブラウザでは問題ないので気が付かなかったのだけれど、chromeのみ症状が出た。

DOMでiframeを追加

解決策としてはDOMでiframeを追加する事で望んだ結果が得られた。

var iframe = document.createElement('IFRAME');
iframe.setAttribute('id', 'フレーム名');
iframe.setAttribute('name', 'フレーム名');
...
document.body.appendChild(iframe);

…つづきを読む







2011 4月13日

やっと出来たのでメモ。
起動スクリプト mojo.cgiを

#!/usr/bin/env perl

use strict;
use warnings;
use lib "../lib";
use App;

app->start('cgi');
exit;

こんな感じで呼び出すと通常のCGIとしてならなんの問題もなく実行出来るのだけれど、SpeedyCGIで実行しようとすると初回実行時に不具合が出る(テンプレートが読み込まれない?)上記実行方法でも2回目以降(キャッシュ後)は動作している感じ。

FastCGIやmod_perlでのエントリーは見かけるんだけど、いかんせんマイナーなSpeedyCGI。結構便利なのにあまり使われていないのかなぁ。

で、とりあえず解決方法が見つかったのでメモ。結論から言えば起動スクリプトで Mojo::Server::CGI を使ってアプリを実行すればいいみたい。

ApacheでCGI(SpeedyCGI)としてデプロイする

起動用スクリプトを mojoアプリケーション本体と同じディレクトリに置く。これは必須ではないので公開するときには配置を変えたり出来る。
(例えば App/public/mojo.cgi として App/public を公開ディレクトリにするなど)

__DATA__セクションにテンプレートを書けるけど、ここではテストのため外部ファイル化している。

最小構成

App +
    - App.pm
    - mojo.cgi
    - templates +
                - index.html.ep

スクリプト

起動用スクリプト mojo.cgi

#!/usr/bin/env speedy

use strict;
use warnings;

use Mojo::Server::CGI;
$ENV{MOJO_APP} = 'App';
#$ENV{SCRIPT_NAME} = '';
Mojo::Server::CGI->new->run;
exit;

App.pm と 起動スクリプトが同じディレクトリの場合は use lib; しなくても大丈夫のようだ。別のディレクトリに起動スクリプトを置く場合、例えばApp/public/mojo.cgi とするなら use “../”; が必要になる。

mojoアプリケーション本体 App.pm

package App;

use strict;    # use Mojolicious::Lite;で自動でされるが明示的に
use warnings;  # しておく。
use utf8;
use Mojolicious::Lite;

# テンプレートへ渡すハッシュリファレンス
my $params = {};

# インデックスページ
get '/' => sub {
    my $self = shift;

    $params->{title}="Hello World!";
    $params->{messe} = "ようこそ 世界へ!";
    $self->stash(params => $params);
} => 'index';

# mojo.cgi/任意の文字に対応
get '/:foo' => sub {
    my $self = shift;

    $params->{title}= $self->param('foo');
    $params->{messe} = "このページは" . $self->param('foo') . "です";
    $self->stash(params => $params);
} => 'index';

テンプレートファイル templates/index.html.ep

<!doctype html>
<html>
    <head>
    <title><%= $params->{title} %></title>
    </head>
    <body>
    <h1><%= $params->{messe} %></h1>
    </body>
</html>

上記は最低限のファイル構成だけれど、テンプレートでレイアウト使っても動作していたのでSpeedyCGI化もこの方法なら大丈夫そう。

参考

  • Perl-Mojolicious/ApacheにCGIでデプロイ – yanor.net/wiki
  • Mojoことはじめ – Perl日記
  • Mojoを使ってみた – Charsbar::Note