スタッフブログ

  • カテゴリ 技術全般 の最新配信
  • RSS

Sabelを使ってみる

 : 技術全般 2008/12/12 11:06

Blogger's Avatar

satoです。
今日は国産PHP5フレームワークのSabelを使ってみようと思います。

Sabelはチュートリアルが充実しているので簡単に使えると思います。
今回は1.1.2を使ってみようと思います。

■インストール
まずはインストールマニュアルの通りにインストールします。
Windows系でのインストール方法も書かれているので、Windowsで開発している方も簡単に利用できると思います。

Sabelでは、sabelコマンドでファイルの生成などを行います。
sabel -l ja
でプロジェクトをカレントディレクトリに生成します。

PHPでデフォルトタイムゾーンを設定していない場合Strict Standards警告が出るので、php.iniに設定をします。
[Date]
; Defines the default timezone used by the date functions
date.timezone = "Asia/Tokyo"

データベース
まずはconfig/Database.phpを編集します。
ENVIRONMENTという定数で分岐していますが、これはそれぞれ
・PRODUCTION(リリース版)
・TEST(テスト時に使う用)
・DEVELOPMENT(開発版)
の3種類を設定することができます。今回は試してみるだけなのでDEVELOPMENTのみ設定します。
packageの項目に使用するDBを指定します。今回はMySQLを使用します。
...
      case DEVELOPMENT:
        $params = array("default" => array(
                          "package"  => "sabel.db.mysql",
                          "host"     => "localhost",
                          "database" => "sabeltest",
                          "user"     => "sabeluser",
                          "password" => "sabelpass")
                       );
        break;
...
複数のDBを設定し、状況に応じてそれぞれを利用することもできるようです。マスタ/スレーブ構成などにも対応できそうです。

データベースを設定したら、次はテーブルを作成します。
Sabelでは、SQLを書かなくても、PHPコードのみでテーブルを作成することができます。このPHPコードが書かれたファイルを「マイグレーションファイル」と呼びます。

マイグレーションファイルは通常、migration/default/に設置します。
ファイル名に規則があり、
{バージョン番号}_{モデル名}_{コマンド}.php
という形式でファイル名を付ける必要があります。
バージョン番号は今回は最初なので1です。モデル名は、小文字にしたものがテーブル名になります。コマンドはテーブルを作成するので「create」です。
今回はPostというモデルを作ってみましょう。ファイル名は「1_Post_create.php」になります。
<?php

$create->column("id")->type(_INT)
                     ->primary(true)
                     ->increment(true);

$create->column("title")->type(_STRING)
                       ->length(256)
                       ->nullable(false);

$create->column("body")->type(_TEXT)
                       ->nullable(false);

$create->column("created")->type(_DATETIME)
                        ->nullable(false);


ファイルを作ったら、実行します。sabelコマンドではなくsakleコマンドを使います。
sakle Migration development head
sabeluser@localhost[sabeltest]> show tables;
+---------------------+
| Tables_in_sabeltest |
+---------------------+
| post                |
| sbl_version         |
+---------------------+
2 rows in set (0.00 sec)
テーブルが作成されているのがわかると思います。
sbl_versionは、テーブルのバージョン管理に使われているものだと思われます。

テーブルを作成したら、対応するモデルを作成します。
sakle Generator model Post

■書き込み
scaffoldが見あたらないので、お試しでも真面目に書き込み画面を作ります。
app/index/controllers/Post.php
<?php

class Index_Controllers_Post extends Sabel_Controller_Page
{

    public function show()
    {
        $paginate = new Paginate("Post");
        $paginate->setDefaultOrder("created", "desc");
        $this-%gt;paginate = $paginate->build(10, $this->request->fetchGetValues());
    }

    public function doPost()
    {
        $title = $this->request->fetchPostValue("title");
        $body = $this->request->fetchPostValue("body");

        $post = new Post();
        $post->title = $title;
        $post->body = $body;
        $post->created = date('Y-m-d H:i:s');
        $post->post();

        $this->redirect->to("c: post, a: show");
    }

}
app/index/views/post/show.tpl
<h1>Post</h1>
<form action="<?php echo uri("a: doPost") ?>" method="post">
  <div>title:<input type="text" name="title" /></div>
  <div><textarea name="body" rows="5" cols="50"></textarea></div>
  <div><input type="submit" value="Post" /></div>
</form>
<hr />
<?php if ($paginate->results): ?>
  <?php foreach($paginate->results as $post): ?>
    <div>
      <h2><?php echo htmlspecialchars($post->title) ?></h2>
      <div><?php echo nl2br(htmlspecialchars($post->body)) ?></div>
    </div>
  <?php endforeach ?>
<?php endif ?>
これで、 http:// 〜/public/index.php/post/show をブラウザで開くと、画面が表示されます。

■まとめ
斜め読みしただけなので、Sabelの特徴を全く生かしていないですが、雰囲気だけでもわかったと思います。
Sabelはアノテーションとかフロー制御とかが特徴的なので、興味のある方は使ってみてください。

Gearsを使ってフォームデータを保存する

 : 技術全般 2008/12/5 20:35

Blogger's Avatar

haltです.

唐突ですが,Webアプリケーションが抱えている致命的な問題点として,「オフラインになると,アプリケーションとして全く機能しなくなる」という点があると思います.
例えば,ログインが必要な掲示板やグループウェアに書き込みをしている途中に一度オフラインになってしまうと,投稿しようとしたデータが反映されずログイン画面に戻されてしまう事がよくあります.

Googleが提供するGearsというブラウザの拡張機能を利用すると,JavaScriptからユーザのハードディスクにデータを保存できるようになるので,たとえ途中で接続が途切れても,データを一時的に保存しておいて,後で送信する.というような事が可能になります.

以下はデータを保存する最低限のサンプルです.引数に指定したデータを保存します.

<script type="text/javascript" src="gears_init.js"></script>
<script type="text/javascript">
function save(text) {
  var db = google.gears.factory.create('beta.database');
  db.open('database-test');
  db.execute('create table if not exists Test' +
      ' (Phrase text, Timestamp int)');
  db.execute('insert into Test values (?, ?)', [text, new Date().getTime()]);
}
</script>

Gearsが公開されていから随分たつのにインストールする手間が必要なせいか,積極的に使われている事例を見たことがありませんが,今後はこういったオフラインでも使えるような仕組みが少しずつ増えていくのかもしれません.

プログラマ同士の会話

naoto : 技術全般 2008/12/4 19:16

Blogger's Avatar

なおとです。

今日社内で、興味深い「井戸端談義」がありました。 タブ談義とコーディング規約についてという、プログラマには定番の話題です。 内容に詳しく触れることは致しませんが、私としても有意義でした。

私は与太話として、XOOPS Cube Legacyやホダ塾ディストリビューションでは、パッケージに収録されたファイルの改行コードが、「CR+LF」になってる(ことが多い)と話しました。 すると、誰ということもないのですが社内の熟練プログラマでも、そのことに気づいていなかった(意識していなかった)というのです。

内容はどうあれ、こういったコミュニケーションはとても大切だなと再認識しました

MySQLのストアドプロシージャの使い方

 : 技術全般 2008/12/3 15:52

Blogger's Avatar

satoです。
今回は普段あまり使われないと思うMySQLのストアドプロシージャについて解説したいと思います。

MySQL5.0以降ではストアドプロシージャが使えるようになっています。
通常MySQLでストアドを使うことはないとは思いますが、一連の、CREATE TABLE等とセットでDB処理を書く時などは便利です。

ストアドプロシージャは各RDBMSで独自に実装していることが多いのですが、MySQLは標準SQL準拠で実装されており、それなりに汎用性があるものになっています。とは言っても、PL/SQLとは違うので、どこで汎用的かと言われると難しいです。
PL/SQLとは違いがありますが、大枠としては似ている部分は多いと思います。

■ストアドプロシージャの作成
ストアドプロシージャの作成にはCREATE PROCEDURE命令を使います。
DELIMITER //
CREATE PROCEDURE test_proc(in f int)
BEGIN
  INSERT INTO test_table(val) VALUES(f);
END;
//
DELIMITER ;

DELIMITER命令は、文の区切り文字(デリミタ)を変更します。
わかりづらいのですが、CREATE PROCEDURE命令は、「CREATE PROCEDURE」から「END;//」までが1つの文になり、その中で実行する命令を書くので、例えば、
CREATE PROCEDURE test_proc(in f int)
BEGIN
  INSERT INTO test_table(val) VALUES(f);
END;
;

と、DELIMITER無しにすると、「CREATE PROCEDURE」が「VALUES(f);」で終了してしまい、エラーになってしまいます。これを回避するために一時的にデリミタを//にしています。

これで定義した後に、
CALL test_proc(1);

とすると、INSERT INTOが実行されるのがわかると思います。

■ストアドプロシージャの削除
削除にはDROP PROCEDURE文を使います。DROP TABLE等と同様に、IF EXISTSを付けることができるので、CREATEの前に書いておくと便利かと思われます。

■ストアドファンクション
戻り値が無いものをプロシージャと呼ぶのに対し、戻り値があるものはファンクションと呼びます。
DELIMITER //
CREATE FUNCTION test_func(f int) RETURNS int DETERMINISTIC
BEGIN
  RETURN (f + 2);
END;
//
DELIMITER ;

基本的にはプロシージャと同様ですが、いくつか違う点があります。

・引数にinが不要
プロシージャの引数の先頭のinは、「この値は入力値です」というのを指示するためのもので、プロシージャの場合はoutという指定もできます。これはPHPで言うところのリファレンス渡しに近いものになります。
ファンクションの場合はRETURNで戻り値を指定するので不要です。

・戻り値の型の指定
CREATE FUNCTIONの引数リストの後に、「RETURNS int」というのがあります。ここで戻り値の型を指定します。(この場合はint)

・DETERMINISTIC
これを付けないで定義しようとすると、
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
のようなエラーが発生する場合があります。
入力値が同じ場合に出力値が同じ場合はDETERMINISTIC、そうでない場合はNOT DETERMINISTICを指定します。バイナリログの記録に関わるようです。
SET GLOBAL log_bin_trust_function_creators = 1;
で回避することもできます。

ファンクションはSELECTで呼び出します。
test@localhost[testdb]> select test_func(1);
+--------------+
| test_func(1) |
+--------------+
|            3 |
+--------------+


■変数の定義
DROP FUNCTION IF EXISTS test_func2;
DELIMITER //
CREATE FUNCTION test_func2(f int) RETURNS int DETERMINISTIC
BEGIN
  DECLARE ret int;
  SET ret = f + 2;
  RETURN ret;
END;
//
DELIMITER ;

内部で使う変数の定義にはDECLARE文を使います。
DECLARE文は全てBEGINの直後に書く必要があります。ルーチンの途中に書くことはできません。
...
BEGIN
  DECLARE ret int;
  SET ret = f + 2;
  DECLARE ret2 int;
...

のようなのはエラーになります。
変数に値を代入するにはSET文を使います。

■カーソル
ストアドでよく使う処理として、「SELECTの結果を1行毎に何か処理したい」ということだと思います。PHPのforeach的なものです。
これを実現するにはカーソルというものを使います。
DROP TABLE IF EXISTS test_table;
CREATE TABLE test_table ( a int, b int, c int);
INSERT INTO test_table(a, b, c) VALUES(1, 2, 0);
INSERT INTO test_table(a, b, c) VALUES(2, 3, 0);
INSERT INTO test_table(a, b, c) VALUES(3, 4, 0);

DROP PROCEDURE IF EXISTS test_proc2;

DELIMITER //
CREATE PROCEDURE test_proc2()
BEGIN
    DECLARE eod tinyint;
    DECLARE in_a, in_b int;
    DECLARE out_c int;
    DECLARE cr1 cursor FOR SELECT a, b FROM test_table;
    DECLARE continue handler FOR not found SET eod = 1;
    SET eod = 0;

    OPEN cr1;
    FETCH cr1 INTO in_a, in_b;
    WHILE eod = 0 DO
        SET out_c = in_a * in_b;
        UPDATE test_table SET c = out_c WHERE a = in_a AND b = in_b;

        FETCH cr1 INTO in_a, in_b;
    END WHILE;
    CLOSE cr1;
END
//
DELIMITER ;

カーソルは、SELECTの戻り値のポインタ的なもので、cursor型として定義します。
「DECLARE cr1 cursor FOR」の後に、そのカーソルで呼び出したいSQLを記述します。
「DECLARE continue handler FOR not found SET eod = 1;」は、カーソル呼び出しの際に、データが存在しなくなったら変数eodに1をセットするというhandlerを定義します。これでSELECTが終了したかどうかを判定します。
カーソルのDECLAREは通常変数のDECLAREの後に定義する必要があります。
    DECLARE cr1 cursor FOR SELECT a, b FROM test_table;
    DECLARE out_c int;

のようにしてしまうと、
ERROR 1337 (42000): Variable or condition declaration after cursor or handler declaration

というエラーになります。

後はカーソルをOPENし、FETCHで値を取得するとINTOで指定した変数に代入され、それを処理します。
これを実行すると、

test@localhost[testdb]> SELECT * FROM test_table;
+------+------+------+
| a    | b    | c    |
+------+------+------+
|    1 |    2 |    0 |
|    2 |    3 |    0 |
|    3 |    4 |    0 |
+------+------+------+
3 rows in set (0.01 sec)

test@localhost[testdb]> CALL test_proc2();
Query OK, 1 row affected (0.01 sec)

test@localhost[testdb]> SELECT * FROM test_table;
+------+------+------+
| a    | b    | c    |
+------+------+------+
|    1 |    2 |    2 |
|    2 |    3 |    6 |
|    3 |    4 |   12 |
+------+------+------+
3 rows in set (0.00 sec)

cが反映されているのがわかると思います。


その他、詳しくはMySQLのリファレンスマニュアルを参照してください。

絵文字のユニコード符号化

 : 技術全般 2008/12/2 18:04

Blogger's Avatar

初めまして、またはお久し振りです。
gusagiです。
今月から、縁あってRYUSに戻ってきました。
以前からご存じの方、初めましての方、以後よろしくお願いします。

さて、以前から携帯関連であれこれやっている私ですが、最近気になっている話題があります。
それは、「絵文字のユニコード符号化」の話題です。


すでにご存じの方もいると思いますが、日本の携帯絵文字についてはある程度まではユニコードで一元化することができます。
外字領域にあたる部分を、それぞれの携帯キャリアが利用しており、大部分は重複しない状態のようです。

上記をご存じの方は、「何で今更ユニコード符号化に気になってるの?」と思われるかも知れませんが、先日Google Japanのブログにある記事が掲載されました。
こちらの記事ですが、今の絵文字は(私の知る限りでは)キャリアごとに使用するコードも表示方法も異なっていたりします。
それを、ゲートウェイで変換したり、サーバのプログラムで使い分けたりとしている訳です。
ただ、プログラムで使い分ける方法については、多くの開発者が積み重ねていったノウハウを元にした結果ではあるものの、ルールとして定められている訳ではないので、キャリアが仕様変更を行った場合に動作が保証されているとはいえません。

今回の記事で一番興味深い点は、このノウハウの部分をオープンソースプロジェクトとして公開したというものです。
プロジェクトのサイトはこちらになります。
先日公開されたばかりで、どのような展開になるかわかりませんが、情報は随時チェックして、携帯対応モジュールにも反映していきたいと思います。

ということで(?)、今後ともよろしくお願いします

Favicon!

 : 技術全般 2008/11/18 19:30

Blogger's Avatar

こんばんはargonです。
今回はfavicon.ico(以下favicon)について書こうと思います。
Favicon『ウィキペディア(Wikipedia)』

最近のブラウザですとFirefoxやOperaはもちろん、Internet Explorerでも
バージョン7からタブ機能が実装され、それに伴ったタブのサイト名の左側に
faviconが表示されるようになりました。
ウェブサイトによっては結構、有名なサイトでもこのfaviconを設定してない
ところもあったりします。自分としてはタブブラウザ全盛の今faviconは
結構、重要な要素なのではないかと思っています。
faviconをテーマにしたウェブサイトもあったります。
Favicon Japan!! -16×16の小宇宙ファビコン-

XOOPSですと標準でfaviconがパッケージに含まれているので、そのままで
何も変更しないとサイトにXOOPSのfaviconが表示されるようになります。
例えばGame*SparkなどがXOOPS2のfaviconが表示されるのでXOOPSを使って運営
しているのが一目でわかります。

favicon作り方は専用のアプリケーションを使う方法や、オンラインで
作成できるサイトを使う方法などがあります。
自分はPhotoShopからicoファイルを出力できるプラグインを使って
PhotoShopで16px四方の画像を作成してから、それを出力しています。
やっぱり普段使い慣れたアプリケーションで作成するのが楽ですので・・・
Telegraphics - Free plugins for Photoshop & Illustrator...and other software

Selenium RCでテストを楽にする

 : 技術全般 2008/11/13 13:34

Blogger's Avatar

satoです。

WebアプリケーションのテストといえばSeleniumが有名です。
Seleniumは便利なのですが、HTMLでテストケースを書くのは面倒です。
通常はSelenium IDEを使うと思いますが、そもそもプログラマーはGUIを叩くのが面倒というケースが多いです。

Seleniumのプロダクトの中にSelenium RCというのがあります。
RCはRemote Controlの略で、その名の通りSeleniumをリモートから操作することができます。
操作に使う言語はJava/Perl/PHP/Ruby等多種多様に対応しているので、自分の好きな言語でテストを書くことができます。
これにより、例えばGUIの無い環境から、Selenium RCのサーバを動かしているPCでアプリケーションのテストを行うことが可能になります。
Selenium IDEの出力も、HTMLだけではなく各言語の形式で出力することができるようになっているので、ベースはSelenium IDEで作って、細かい調整は直接編集する、ということもできます。

サーバ側の使い方は簡単で、ダウンロードしたファイルの中の、selenium-server-[バージョン名]/selenium-server.jarを実行する(java -jar [ファイル名])だけです。当然JREが必要になります。
Windows Vistaの場合は管理者権限で動かす必要があります。

クライアント側は、PHPで動かす場合はPHPUnitが必要です。
pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit

さらに、Testing_Seleniumが必要なので、
pear install Testing_Selenium-beta

でインストールします。

実際には以下のようなコードで動かすことになります。(Selenium RCに付属のサンプルを多少変更したものです)
Firefoxでは動かなかったのでIE(7)にしています。
<?php

require_once 'Testing/Selenium.php';
require_once 'PHPUnit/Framework/TestCase.php';

class GoogleTest extends PHPUnit_Framework_TestCase
{
    private $selenium;

    public function setUp()
    {
        $this->selenium = new Testing_Selenium("*iexplore", "http://www.google.com", "192.168.1.1"); // 192.168.1.1はSelenium RCサーバのIPアドレス。同じPC上で行う場合は省略可
        $this->selenium->start();
    }

    public function tearDown()
    {
        $this->selenium->stop();
    }

    public function testGoogle()
    {
        $this->selenium->open("/webhp");
        $this->selenium->type("q", "hello world");
        $this->selenium->click("btnG");
        $this->selenium->waitForPageToLoad(10000);
        $this->assertRegExp("/Google/", $this->selenium->getTitle());
    }

}

これをphpunitで動かすとサーバ上で動作すると思います。
詳しくはドキュメントを参照してください。

テストケースを用意するのも簡単ではないので、できるだけ作りやすい方法で作業できるようにしておくといいと思います。
また個人的には、Selenium RCを使うと、Selenium本体のファイルを置いておかなくてもいい(恐らくjarに全部含まれている)のが好きです。

【BK】インライン要素の幅を指定する【CSSノウハウ】

naoto : 技術全般 2008/11/6 19:23

Blogger's Avatar

こんにちわ。なおとです。朝晩冷えますね。

.fixed-inline {
  display: inline-table;
  width: 2em;
}
<p>
<span class="date fixed-inline">2008-11-1</span>
<span class="title">...
</p>

置換要素ではないインライン要素は、幅や高さは「なり」というのが、CSSの仕様です。 ある部分の幅を固定したいとき、それはブロック要素にして、配置はfloatにするなり、というのがよくやる方法だと思います。

例えば箇条書き的な配置のインラインのテキストがあって、それに何か見出し的な何かを、表組みのような配置で追加したくなったとします。 しかしtable要素にしたくなかったとか、マークアップはspanを使っていたのを変えたくないとします。これはあくまで例えです。

そのときに知ったのが、冒頭の記述です。 inline-tableの存在理由からすると、逸脱した使い方に思えます。よく考えて使ってください。

openpearがリリースされました

 : 技術全般 2008/11/5 13:29

Blogger's Avatar

satoです。

先日、openpearがリリースされました。

PHPのライブラリのサイトといえばPEARがあります。PEARはいいライブラリが揃っていて、pearコマンドで簡単にインストールできるので便利なのですが、自分の作ったライブラリをPEARに登録するのは非常に面倒でした。
openpearは、独自のリポジトリを構築することで、誰でも簡単にPHPのライブラリを公開できるようにしたものです。
nequalのriafさんがメインで開発しております。

ライブラリを使う側からは、トップページに書いてある通り、一度
pear channel-discover openpear.org
すれば、あとは
pear install openpear/パッケージ名

で簡単にインストールすることができます。

ライブラリ開発側も、OpenIDでログインし、Subversionでソースをコミットしてリリース作業をすれば簡単にパッケージをリリースすることができます。
まだサイト自体がリリースした直後なので、登録されているパッケージはそれほど多くないですが、これから順次増えていくと思われます。

ちなみにopenpearのサイト自体はrhacoで作られているようです。

PHP用のCodeReposSpark Project的な存在になっていくと思われるので、まずはライブラリを抱えている方は積極的にコミットしてみてください。

Webアプリを開発するエンジニアは、サーバ管理技術も磨いておいた方がいい

naoto : 技術全般 2008/10/29 18:59

Blogger's Avatar

なおとです。

私がここで記事を書くときに、しばしば「できるエンジニア」ということを話題にしてきましたが、今回もそんな話です。

いろいろできるに越したことはない、ということではあるのですが、その中でもサーバやOSなどは付き合いが深い領域だったりします。 そうでなくとも、開発の現場にある程度いると、否応なしに接する機会がやってくる筈です。

「そのとき」にある程度のスキルと経験が備わっていないと、あたふたしたり、時間がかかりすぎてしまったりします。 日頃から接するような環境でいたり、情報収集的なことをやっていると、それが役に立つのです。

非常に簡単ではありますが、たとえば次のようなものが挙げられます。

  • OSのインストール
  • 開発環境の整備
  • 個々のサーバアプリの定常管理
  • Windowsネットワーク/ファイル共有
  • 小規模なLANの構成(ルータ、ファイアウォール)

今までの経験でも、このあたりの知識は役にたちました。

スタッフブログ最新
カテゴリ一覧

〒104-0061 東京都中央区銀座1丁目3番3号 G1ビル7階
お問い合わせ TEL 03-3524-8860

Copyright(c) 2012 RYUS.All Rights Reserved.