2014年10月5日日曜日

郵便番号データ+検索について考えてみた

郵便番号データ、郵便番号検索についてエントリをしてみようと思う。

この郵便番号データってやつは、様々なアプリで必要な場面が多い。
日本郵便が提供していてダウンロード可能であるが、市区町村統廃合等の理由により月1度なり最新化されるので、 ある時点で取得しても、そのうち最新データでなくなってしまう。

こういった問題の解決方法の一つとして、AjaxZip3 というプロダクトもあって メンテナンスも AjaxZip3 側でしていただけるので、 コレを使えば、郵便番号検索は凄く簡単に実装出来るし、常に最新のデータを参照出来る。

自分もこの AjaxZip3 は 5年前ぐらいから数回使っていて、 便利だなと思う。
しかし、個人的にただ一つ物足りないのは、郵便番号7ケタ入力しないと住所補完してくれない点。
Google 日本語入力 のようなサジェスト機能を用いて、インクリメンタル検索出来れば、もっと使いやすいなと個人的には思う。

AjaxZip3 が対応してくれれば嬉しいんだけど、たぶんこの先も対応されないと思うので、常に最新の郵便番号データを使いつつ(※1)、郵便番号検索する際はインクリメンタルに出来るようにする(※2)には、自分で実装するしか手立ては無さそう。

※1 はお決まりな方法やけど、実際に作ってみた。
※2 は別の機会に公開するかも。

[動作環境]
  • CentOS release 6.5 (Final)
  • MySQL 5.1.73
#!/bin/sh
# ====================================================================
# $Id$
#
# Description:
#  郵政省郵便番号(zip_codes) を最新化します。
#
# Usage:
#   ./renew_zipcodes.sh
#
# Date        Author      Description
# --------------------------------------------------------------------
# 2014-10-05  Seiji Hojo  新規作成
#
# ====================================================================

# 設定ファイル読み込み
. "./config/renew_zipcodes.ini"

# ====================================================================
# 前処理
# ====================================================================

# clean
find ${TMP_DIR} \( -name "KEN_ALL.CSV" -o -name "ken_all.zip" \) -print0 | \
xargs -0 --no-run-if-empty rm 2>/dev/null

# ====================================================================
# 本処理
# ====================================================================

# zip ファイル取得
wget ${ZIP_ALL_URL} -P ${TMP_DIR}

# zip 解凍
cd ${TMP_DIR}
unzip $(basename ${ZIP_ALL_URL})

# テーブル再作成
${MYSQL_CMD} < ${SQL_DIR}"/drop-create-zipcodes.sql"

# データ投入
${MYSQL_CMD} <<SQL

-- Shift_JIS ファイルを読み込む
SET character_set_database=sjis;

-- 郵政省郵便番号(zip_codes) に最新データ投入
LOAD DATA INFILE "/tmp/KEN_ALL.CSV"
INTO TABLE zip_codes
FIELDS
    TERMINATED BY ','
    OPTIONALLY ENCLOSED BY '"'
LINES
    TERMINATED BY '\r\n'
IGNORE 0 LINES
;

-- 「以下に掲載がない場合」は消す
UPDATE zip_codes
SET address = NULL
WHERE address = '以下に掲載がない場合'
;

SQL

# ====================================================================
# 後処理
# ====================================================================

# clean
find ${TMP_DIR} \( -name "KEN_ALL.CSV" -o -name "ken_all.zip" \) -print0 | \
xargs -0 --no-run-if-empty rm 2>/dev/null

# end
exit 0


[補足・注意]
コピーして使っても構いませんが、一切責任持ちません。
動作テストはしてますが、cron 実行とかはまだ試していません。

[参考]
AjaxZip3
https://code.google.com/p/ajaxzip3/
AjaxZip3 設置サンプル(お試し出来ます)
http://ninkigumi.com/ajaxzip3/
郵便番号データダウンロード - 日本郵便
http://www.post.japanpost.jp/zipcode/download.html

2014年10月4日土曜日

CakePHP で独自の親クラスを作成する場合の注意点

CakePHP で、全てのコントローラに共通な内容であれば AppController に記述すれば良いけれど、
全てのコントローラに共通する内容で無かったり、ある特定のドメインや機能で共通化を図りたい場合、どう解決するか?
まず思いつくのが AppController と各コントローラの間に独自親コントローラ (以下、DomainController) を作成する方法。
CakePHP でコントローラを作成する場合、AppController を継承して作成するが、
AppController を継承した DomainController を継承してコントローラを作成するようにする。

AppController
全てのコントローラに共通するプロパティやメソッドを定義。

DomainController
ある特定のドメインだけに共通するプロパティやメソッドを定義。

各コントローラ(以下、MyController)
自身に必要なロジックだけを記述。

継承関係が適していればそうしたいけれど、この方法だと DomainController で定義した components, uses といったプロパティが自動マージされず、 DomainController を継承している MyController で参照出来ない。
AppController を直接継承している MyController では、これらプロパティは CakePHP が自動でマージしてくれるて参照出来るのに。。。
DomainController でも共通化ロジックを書くために components, uses といったプロパティを定義する必要があるので、自動マージしてくれないとせっかく共通化したのに MyController で同じ記述しないといけない(全てじゃないにしろ)。。。

何故か?
原因を探ろう。

自動マージされず参照出来ない理由は AppController の親クラス Controller の $_mergeParent にあります。
Controller クラスをソースコード読めば、AppController を直接継承している MyController では自動マージが行われるのかが逆に分かります。
ちなみに Controller::$_mergeParent の値を AppController から DomainController に変えると、今度は AppController で定義している uses などが自動マージされなくなって参照出来なくなる(当たり前)。

ちょっと前置きが長くなったけれど、これを解決する方法は調べると複数あったけれど、
自分は下記のようなアプローチでこの問題を解決するようにした。
class DomainController extends AppController {

    /**
     * コンストラクタ
     * 
     * @see Controller::__construct()
     */
    public function __construct($request = null, $response = null) {

        // uses, components をマージ

        $this->uses = am($this->uses, array(
            'User',
            'Label',
         ));

         $this->components = am($this->components, array(
            'Me.AuthTest',
         ));

    }

    // 以下、共通ロジックなど ...

}
class MyController extends DomainController {

    public $uses = array('Employee');

    public $components = array('Search.Prg');

    public function index() {

        debug($this->uses); // User, Label, Employee + AppController::uses
        debug($this->components); // AuthTest, Search + AppController::components

    }

}


[参考]
CakePHPで独自に定義した親クラスでのComponentとHelperのマージ
http://qiita.com/uda0922/items/e9501c46f5b4cd91106a
$componentsと$helpersと$uses — CakePHP Cookbook 2.x ドキュメント http://book.cakephp.org/2.0/ja/controllers.html#components-helpers-uses

Trello を使って仕事をもっと楽にしよう

随分ひさしぶりの更新です。

今日は 2012 年ぐらいから使ってきていて、無くてはならない Trello というツールの紹介と、
自分なりの使い方を簡単に紹介しようと思います。

Trello は有名なツールで、 もっと分かりやすく説明されているページが世の中に多数ありますが、 大まかに書くと「●●する」といった大小様々な仕事を、ホワイトボードに付箋を張って管理していくようなイメージのツールです。

付箋を「カード」という形で表現し、 それを優先順位やタスクの種類等によって色分けしたり、 タスクの進行状況を「グループ(リスト)」で分けたり出来ます。
パソコン、タブレット、スマートフォンでもアプリがあって、 どの端末でも書けます、見れます。
どの端末で書いても、他の端末でその内容がスグ見れます。

そんな素敵なツールです。 

自分の使い方はこんな感じ(左:パソコンで見た画面、右:iPhoneで見た画面)

  


自分は大きく分類すると6種類ぐらいの仕事をしていて、
その場所もデスク、上の階、別の店舗、客先等と様々。
この何処でも書けて見れて、直感的に触れる Trello は素敵過ぎます。

「カード」を色分け出来るんですが、自分は仕事の種類を分けるのに使っています。
「グループ(リスト)」は進行状況を管理しています。
5つ作っていて、下記のように使っています。

 ・Idea & Memo
その名の通り、アイデアやメモを管理するグループ

・Things Comming Up
言わば Todo の事。
でも ToDo って言われると MustDo みたく「やらないとイケない」ってイメージがあったので名前変えましたw

・Today
今日のタスク。 ここは帰る時には無くなっている状態ですね。

・Doing & Waitng
ここは現在進行中のタスク。何とかなう!ですねw

・Done
終わったタスク(お疲れ様でした)

「カード」は、パソコンならマウスで掴んで別のグループに移動出来ます。
タブレットやスマホなら指でスワイプして移動出来ます。
凄く直感的で、Trello 知らない人でも、こういうツール使った事無かった人でも
教えたら結構すぐ使えるようになって、数日経てば普通に使っています。

特にテンパってる人向けの救世主的解決方法だと思うので、
もっと信仰してみようかなwww

[参考]
海外注目クラウド 3/100「Trello」
http://cloud-plus.biz/blog/?p=265

カード型タスク管理ツール「Trello」で行うタスク管理のご紹介
http://news.ko-zu.com/trello/