JSEclipse 導入でエラー

JavaScript 用 Eclipse プラグインは JSEclipse がよさそう、ということで
Eclipse 3.3.1 に JSEclipse 1.5.3 を下の更新サイト

http://www.interaktonline.com/

からいれてみたのですが、Eclipse を再起動して早速 *.js ファイルを開いてみたところ、次のようなエラーが…

Error opening the editor

 
とりあえず ソフトウェア更新→構成の管理→JSEclipse 1.5.3を選択し、更新をスキャンしてみたところ、Adobe Labs に JSEclipse 1.5.5 があるよ、と言われたのでそれをインストールし、無事動作しました。
最初から Adobe Labs からインストールすればよかったのですね。
 
Update site: Adobe Labs

http://download.macromedia.com/pub/labs/jseclipse/autoinstall/

 
ちなみに、InterAKT と Adobe の関係については FAQを参照するとわかるのですが、InterAKT が Adobe に買収され、その結果 JSEclipse を含む一部の製品が Adobe Labs に移ったようです。

PHP4 と PHP5 の Sigleton Pattern

PHP4 での Singleton

error_reporting(E_ALL);
class Foo {
    function &getInstance(){
        static $_singleton;
        if(empty($_singleton)){
            $_singleton = new Foo();
        }
        return $_singleton;
    }
    var $_n;
    function add(){
        echo (++$_n).”\n”;
    }
}
$o1 =& Foo::getInstance();
$o1->add(); // 1
$o2 =& Foo::getInstance();
$o1->add(); // 2
$o2->add(); // 3
$o1->add(); // 4

 & と static の使い方が肝です。
static キーワードは、指定したローカル変数のライフサイクルを延長するためのキーワードです(注1)。
 メソッド定義とメソッド呼び出しの両方に & を付けないと、参照でなくコピーになってしまい、個別のインスタンスになるために結果が 1,2,1,3 になってしまいます。
 
PHP5 の場合も上のコードを変更なしで Singleton Pattern として動作させることが可能です。
さらに、メソッドの戻り値が標準で参照になるため、& を外しても singleton を実現することができ、クライアントコードが誤用する可能性がなくなったといえます(注2)。
 
このように PHP4 ではクライアントに特殊なメソッド呼び出し方をしないと意図しない結果になるため、Singleton な動作が必要な箇所については極力非公開にして内部利用にとどめるほうが賢明かも、です。
 
注1:
static キーワードには、スコープ(可用範囲)を広げる効果はありません。
ローカル変数がフィールドになるわけではないため、異なるメソッドで同じ名前の変数を指定しても、別個の変数になります。
注2:
ただし、クライアントコードで

$o1 = clone Foo::getInstance();

のように clone を使って意図的にコピーを行った場合、PHP4 で & を付けなかったときと同様の結果になります。
この場合はクライアント側で結果が予測できるため、問題にはならないでしょう。
 
参考:
– PHP4 でデザインパターン(Do You PHP?)

Eclipse で SVN 利用時 JavaHL にすると強制終了する時のトラブルシューティング

Eclipse 3.3, Subversive または Subclipse を利用し、Apache2.2 用 Subversion 1.4.5 をインストールした環境でローカルで使っていたところ、SVN リポジトリへのアクセスが発生すると、黙って Eclipse が落ちる、という現象が発生しました。プライマリなパースペクティブが SVN リポジトリにアクセスするものだと Eclipse が全く起動しなくなったり…
 
調べてみたところ、結論として、パスが通る場所(PATH で指定されている場所)に libapr-1.dll があり、libapr-1.dll と eclipse/plugin/*javahl* にある libjavahl-1.dll の(Apache の)バージョンが異なる場合に JavaHL を呼び出した瞬間に Eclipse が落ちるようです。
 
以下のいずれかの方法で対策できます。
(A) Subversion をアンインストールするか、PATH から <Subversion ホームディレクトリ>/bin を外す
(B) Apache2.2 用でなく Apache 2.0 用 Subversion (1.4.x) をインストールする
(C) plugin/*javahl*_X.X.X にあるすべての DLL を、使いたい Subversion の DLL にまるごと置き換える
(D) JavaHL でなく SVNKit など PureJava 実装の SVN コネクタを使う。
 
C の案を採用する場合、Subversive なら

eclipse\plugins\org.polarion.team.svn.client.javahl_1.1.*

Subclipse なら

eclipse\plugins\org.tigris.subversion.javahl.win32_1.2.*

に、それぞれのプラグインで使われている JavaHL の DLL があります。
 
また、置き換える DLL は Subversion ダウンロードページからダウンロードした svn-win32-1.4.*_javahl.zip の中の

javahl/libsvnjavahl-1.dll
bin/*.dll

です。
 
追記:
– 2007-10-26: (C)の案でSubversive についてのみ書いていましたが、本日 Subclipse にして再発したため、再調査の上加筆修正しました。
 
参考:
久しぶりにJavaHL(気の向くままに…)

Windows で SVN – 環境準備から Web 公開、利用までの手順

OS: Windows XP SP2
サーバ環境: Apache 2.2.6 + Subversion 1.4.5 + TortoiseSVN 1.4.5
クライアント環境: Eclipse 3.3 + Subclipse 1.2.x
 
という構成で、SVN 環境を構築したのでその手順を残しておきます。
参考にしたサイトについては後述。
 
– Apache 2.2 をダウンロード、インストール
  詳細は省略
– Subversion インストール
  Apache 2.2 用 zip 版(svn-win32-*.zip)をダウンロード(インストーラが必要なら Apache 2.0 用 exe 版(svn-*-setup.exe)をインストール後、zip 版を上書きする)
 コマンドラインから利用するため、 Subversion インストールフォルダの bin にパスを通しておく。
 
– コマンドラインで SVN リポジトリ作成
引用: http://terai.xrea.jp/Subversion/Apache2.html#uc9cfee4

mkdir c:\svn
svnadmin create c:\svn\hoge
svn mkdir file://localhost/c:/svn/hoge/trunk -m “mkdir trunk”
svn mkdir file://localhost/c:/svn/hoge/tags -m “mkdir tags”
svn mkdir file://localhost/c:/svn/hoge/branches -m “mkdir branches”

– Apache の httpd.conf で SVN リポジトリが見られるように設定
以下の行がコメントアウトされていれば、コメントアウトをはずして有効にします。

LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so

以下の行がなければ、LoadModule の最後に追加します。

LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so

最後に、以下のように、Location や VirtualHost タグで DAV, SVNParentPath を設定します。

<Location /svn>
  DAV svn
  SVNParentPath “c:/svn”
</Location>

これで、Apache を再起動すればブラウザで

http://localhost/svn/hoge

とアクセスして接続を確認することができます。
 
– TortoiseSVN インストール
 これは任意。インストールするとエクスプローラで右クリックでSVNリポジトリが作成できるようになります。
 http://tortoisesvn.net/downloads から、自分の環境用の msi をダウンロード
 インストールし、マシンを再起動したあとに同ページの下にある Language Packs の Japanese をダウンロードして実行すると、設定から日本語が選択できるようになります。
設定方法は、エクスプローラを開いて適当な場所で右クリック→ TortoiseSVN → Settings → General の Language を日本語して OK 、です。
 
 
– Eclipse 3.3 インストール
 詳細は省略。
 
– Subclipse インストール
 Eclipse のインストール/更新メニューで新規リモートサイトとして

http://subclipse.tigris.org/update_1.2.x

を指定すればインストールできます。
 
– Elicpse で SVN 対応
SVN リポジトリーエクスプローラーを開き、SVN リポジトリビューで右クリック、新規→リポジトリーロケーションで以下のように入力します。

http://localhost/svn/hoge

パッケージエクスプローラで既存のプロジェクトを右クリック→チーム→プロジェクト共用→SVN
で、あとはそのままウィザードを進めれば SVN を利用することができます。
 
参考:
Apache2 で Subversion をネットワークに対応(てんぷらメモ)
 SVN リポジトリの作成と Apache での公開手順。
Subversion を Windows で GUI 中心に使う(Landscape – エンジニアのメモ)
 Subversion + TortoiseSVN の導入手順。

Plugin – 言語パックが出ていないバージョンを日本語化する / 他機能ファイル検索

 
Pleiades
EclipseWiki の説明ページ
このプラグインを適用すると、公式 Language Package が出ていない Eclipse 3.3 を日本語化することができます。
 
– GotoFile Eclipse Plugin
EclipseWiki の説明ページ
このプラグインを適用すると、編集メニューに「クイック検索(Ctrl+Alt+N)」の機能が追加され、頭文字だけのキャメルケース検索や、曖昧検索ができるようになります。
思ったほどもたつきも感じませんし、標準のファイル検索機能(Ctrl+Alt+R, Ctrl+Shift+R)よりもだいぶ便利です。
GotoFile update site:

http://www.muermann.org/gotofile/update

 
2007-10-09 現在、GotoFile Plugin をインストールする時に「この環境に適当でないフィーチャーを無視する」にチェックが入っていると、対応バージョンを検出してくれませんでしたが、チェックを外してインストールしても問題なく動作します。

symfony – Propel を仲介せずに databases.yml に書かれた設定や DB接続インスタンスを得る

sfDatabaseManager クラスを使うことで Propel より低いレイヤーでデータベースの情報を得たり、(Creaole による)データベース接続を行うことができます。
この方法を使うと databases.yml の設定を一時的に変更した上でデータベースアクセスができるようになります。

$manager = new sfDatabaseManager();
$manager->initialize(); // インスタンスに database.yml ファイルを読み込んで初期化する。
$db = $manager->getDatabase(“propel”); // “propel:” 以下を参照し、sfDatabase のインスタンスを得る。 引数を省略すると default: を参照する
 
// database.yml の設定を参照する例:
echo $db->getParameter(“phptype”).”\n”; // propel: param: phptype: を参照(“mysql” など)
echo $db->getParameter(“host”).”\n”; // propel: param: host: を参照(localhost など)
echo $db->getParameter(“database”).”\n”; // propel: param: database: を参照
echo $db->getParameter(“username”).”\n”; // propel: param: username: を参照
 
// databases.yml の設定を一時的に上書きする例:
$db->setParameter(“database”, null); // 特定のデータベースに接続しない。
                                     // (データベースが存在しなくてもエラーにならないため
                                     // CREATE DATABASE したい場合やテーブルを一切利用
                                     // しない場合などに有用)
 
// データベース接続の例:
// databases.yml の設定をもとに Creole のデータベース接続インスタンスを得る
// (vendor/creole/Connelction.php で定義される Connection 抽象クラスのインスタンス)
$con = $db->getConnection();
 
$rs = $con->executeQuery(“SELECT CURRENT_TIMESTAMP AS time”); // クエリを発行。
while($rs->next()){ // ポインタを進める(複数レコード対応)
    $row = $rs->getRow(); // レコードを連想配列で取得
    echo $row[“time”];
}

 
参考:
Class sfDatabaseManager(symfony API)
 sfDatabaseManager のクラス定義。
 
Class sfDatabase(symfony API)
 sfDatabaseManager::getDatabase() で得られるインスタンスの定義。
 
– SymfonyAPI – Connection Interface Reference(cpr.in-berlin.de による symfony の phpdoc)
 sfDatabase::getConnection() で得られるインスタンスの定義。
 
– SymfonyAPI – ResultSet Interface Reference(同上)
 Connection::executeQuery() で得られるインスタンスの定義。

symfony – 単体テストで propel を使う方法

機能テスト(functional test) やバッチスクリプト(batch)で Propel を使う方法については以前こちらの記事

sfContext::getInstance();

を最初に実行すれば動作する、と書きました。
 
しかし単体テストで Propel を使う際は、単純に

require_once(dirname(__FILE__).’/../bootstrap/unit.php’);
sfContext::getInstance();

とするだけでは

Fatal error: Class ‘sfContext’ not found in …

のように、sfContext クラスが見付からずエラーになります。
ここで単純に sfContext を include しても、sfCore や myUser などが存在しないと言われたり、様々なエラーがでて動作しません。
前述の記事の参考URLにあるように、次のようなコードが必要になります(注: 参考元の投稿コードから僅かに手を加えています)。

// TODO: 要変更 – テスト対象のアプリケーション名
$app_name = “frontend”;
 
//begin initialise database code
include(dirname(__FILE__).’/../bootstrap/unit.php’);
include(dirname(__FILE__).’/../../config/config.php’);

require_once($sf_symfony_lib_dir.’/util/sfCore.class.php’);
sfCore::initSimpleAutoload(array(SF_ROOT_DIR.’/lib/model’ // DB model classes
                                ,$sf_symfony_lib_dir // Symfony itself
                                ,dirname(__FILE__).’/../../apps/stageselect/lib’ // Location app lib
                                ,SF_ROOT_DIR.’/plugins’)); // Location plugins
set_include_path($sf_symfony_lib_dir . ‘/vendor’ . PATH_SEPARATOR . SF_ROOT_DIR . PATH_SEPARATOR . get_include_path());
 
define(‘SF_ENVIRONMENT’, ‘test’);
define(‘SF_APP’, $app_name);
define(‘SF_DEBUG’, true);
 
sfCore::bootstrap($sf_symfony_lib_dir, $sf_symfony_data_dir);
sfContext::getInstance();
Propel::setConfiguration(sfPropelDatabase::getConfiguration());
Propel::initialize();
// end initialise database code
 
// 初期化終わり、以下テストコードが続く…
 
$lime = new lime_test();
 
// :

 
原因についてはエラーや対策のコードを見れば想像がつくと思いますが、単体テストでは機能テストと違い bootstrap (unit.php, functional.php)を include するだけで symfony プロジェクトをまるごと読み込んだり初期化しないようになっているためです。

symfony – propel でのリレーションの仕方

schema.yml:

Author:
  name: varchar(255)
Article:
  title: varchar(255)
  author_id:

のように、カラム名に <主テーブル名>_id という名前を付けると、参照テーブル(Article) には,主テーブル名(Author)への foreign key が作られ、 propel のモデルクラスでそれぞれのリレーションに対する専用のメソッドが提供されて簡単にリレーションができるようになります。
 
前述の Author, Article ならばモデル生成時に次のようなメソッドが自動生成されます。

class BaseAuthor {
    public function getArticles();
    public function addArticle($article);
}
class BaseArticle{
    public funtcion getAuthor();
    public function setAuthor($author);
}

この場合, addArticle() という名前のメソッドを呼び出すと、外部キーが適切に設定されるだけでなく、メソッドを呼んだオブジェクトが save() された場合に、このメソッドで引数にしてあるオブジェクト全てに対して save() を要求してくれます。複数指定可能なので set でなく add になっているわけです。
また、getArticles() メソッドを使うと、実行インスタンス(の元になるレコード)を参照している、 Article テーブルの全てのレコードの Article クラスインスタンスを取得できます。
 
逆に、参照元のテーブルである Article クラスのインスタンスから getAuthor() を呼ぶことで、そのインスタンスが参照している Author クラスのインスタンスを得ることができます。
 
add メソッドの利用例:

// 著者登録
$author = new Author();
$author->setName(“Ernest Miller Hemingway”);
 
// $author への作品登録
$article = new Article();
$article->setTitle(“The Old Man and the Sea”);
$author->addArticle($article);
 
// $autho への作品登録その2
$article = new Article();
$article->setTitle(“For Whom the Bell Tolls”);
$author->addArticle($article);
 
// 全て書き込み
$author->save();

結果:

Author:
id | name
1 | Ernest Miller Hemingway
Article:
id | name | author_id
1 | The Old Man and the Sea | 1
2 | For Whom the Bell Tolls | 1

参照例:

 
参照時には
参考:
-Relationships(propel.phpdb.org)

symfony – sfTestBrowser の使い方(目的別)

■ フォワード(forward()) のテスト

object isForwardedTo(string $moduleName, string $actionName [, string $position])

モジュール $ModuleName のアクション $actionName に遷移したかをテストします
例: foo/index が boo/index にフォワードしたかを確認する

$t->get(“foo/index”)->isForwardedTo(“boo”, “index”);

 
■ リダイレクト(redirect()) のテスト

object isRedirected([boolean $boolean])

リダイレクトの要求があったかどうかをテストする。$boolean に false が指定された場合、失敗を期待する。

object followRedirect()

要求するリダイレクト先に遷移する。リダイレクト要求がないのに行った場合、例外が投げられる。
 
例: foo/index が boo/index にリダイレクト要求するかを確認する

$browser->get(“foo/index”)->
  isRedirected()->followRedirect()->
  isRequestParameter(‘module’, ‘boo’)->
  isRequestParameter(‘action’, ‘index’);

 
間違ったリダイレクトテスト方法:

object isResponseHeader($key, $value)

を使って

$browser->isResponseHeader(“Location”, “/module/action”)

とするのは間違いです。Location ヘッダは http://frontend-test/index.php/module/action のような絶対 URL になっている上、action が index の場合 action の指定が省略されるため、完全一致チェックの isResponseHeader() メソッドは不適です。

PHP Xdebug を Windows で使う

Xcache は pecl に登録されているのですが, windows だと

pecl install xdebug

としてもビルドできませんし、PHP 公式サイトの pecl モジュールのバイナリ版パッケージダウンロードにも含まれていません。
 
配布サイトを探したところ、Xdebug 公式サイトにはちゃんと Windows 版バイナリが配布されていました。
 
参考:
Xdebug Instration(xdebug.org)
Re: xdebug install error(xdebug-general ML)