Sajaxとか使っとけばいいんじゃね?

先日のAjaSQLに関するエントリでのコメントで「Sajax使えばいいんじゃね?」みたいなことを言ったけど、実際どんな感じになるのかAjax郵便番号検索を作って試してみた。製作時間約30分。

<?php
ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . './lib');
require_once 'Sajax.php';
require_once 'DB.php';
require_once 'Services/JSON.php';

define('DB_DSN', 'sqlite:///zipdb');

function sql2json($sql, $offset, $limit, $params)
{
    $db = DB::connect(DB_DSN);
    if (PEAR::isError($db)) {
        return false;
    }
    $db->setFetchMode(DB_FETCHMODE_ASSOC);

    $result = $db->limitQuery($sql, $offset, $limit, $params);
    if (PEAR::isError($result)) {
        return false;
    }

    $records = array();
    while ($row = $result->fetchRow()) {
        $records[] = $row;
    }

    $json_obj = new Services_JSON();
    $json = $json_obj->encode($records);

    return $json;
}

function addr2zip($address)
{
    $params = array(
        str_replace(array('%', '_'), array('\%', '\_'), $address) . '%'
    );
    return sql2json('SELECT code, address FROM zip WHERE address like ?', 0, 20, $params);
}

function zip2addr($zipcode)
{
    $params = array(
        str_replace(array('%', '_'), array('\%', '\_'), $zipcode) . '%'
    );

    return sql2json('SELECT code, address FROM zip WHERE code like ?', 0, 20, $params);
}

sajax_init();
sajax_export('addr2zip');
sajax_export('zip2addr');
sajax_handle_client_request();

header('Content-type: text/html; charset=utf-8');
?>
<!DOCTYPE HTML PUBLIC "-//W3C/DTD HTML 4.01/EN">
<html>
<head>
<title>郵便番号検索</title>
<script type="text/javascript" src="prototype.js"></script>
<script type="text/javascript">
<?php sajax_show_javascript(); ?>

window.onload = function() {
    Event.observe(
            $('zipcode'),
            'keyup',
            function() {
                if (!$F('zipcode')) return;

                x_zip2addr($F('zipcode'), showResponse);
            },
            false);
    Event.observe(
            $('address'),
            'keyup',
            function() {
            if (!$F('address')) return;
                x_addr2zip($F('address'), showResponse);
            },
            false);
}

function showResponse(json) {
    var result = eval(json);
    if (result.length > 0) {
        var ul = document.createElement('ul');
        result.each(function(item) {
            var html = [];
            html.push(item.code.escapeHTML());
            html.push(':');
            html.push(item.address.escapeHTML());
            var anchor = document.createElement("a");
            anchor.href = 'javascript:void(0)';
            anchor.innerHTML = html.join("");
            var li = document.createElement('li');
            li.appendChild(anchor);
            ul.appendChild(li);

            Event.observe(anchor, 'click', function() {
                $('zipcode').value = item.code;
                $('address').value = item.address;
            }, true);
        });
        $('output').innerHTML = '';
        $('output').appendChild(ul);
    } else {
        $('output').innerHTML = '見つかりません';
    }
}

</script>
</head>
<body>
<form action="" onsubmit="return false;">
 郵便番号<input type="text" id="zipcode" maxlength="7" size="8"/>
 住所<input type="text" id="address" size="100"/>
</form>
<div id="output"></div>
</body>
</html>

Prototype.js ってあまり使ったことないから詳しい人からしたら変かも知れないというか超手抜きなので細かいツッコミは勘弁。あと、Sajax.php のほうは escape を encodeURIComponent に変えてある。
とりあえず、SQLを実行するところは

function addr2zip($address)
{
    $params = array(
       str_replace(array('%', '_'), array('\%', '\_'), $address) . '%'
    );
    return sql2json('SELECT code, address FROM zip WHERE address like ?', 0, 20, $params);
}

と定義しておいて

x_zip2addr($F('zipcode'), showResponse);

と、コールバック関数付きで呼び出せば良いだけ。ライブラリ以外は1ファイルで完結してるし、手軽に作りたいだけならこんなんでいいんじゃないかと思うんだが、どうだろう。

一応、そのまま実行できるアーカイブを置いておく。要PHP+SQLite拡張。