symfonyの外部でsymfony関連クラスをautoloadする
先日の第2回設計勉強会でも出てきましたが、現在、LimeではなくPHPUnit3を使ってテストをしてます。フレームワーク非依存になるように作っているためです。
とはいえ、データベースアクセスはPropel/Creoleに依存せざる得ない状況(この辺は割り切りw)なので、テスト時にPropel/Creole関連のクラスは必要になります。しかし、symfonyはrequire_once/include_onceではなくautoloadするようになっているので、テスト時に「クラスがない」と怒られまくります。
そこで、次のようにしてautoload機能をでっち上げ、このファイルをそれぞれの*Test.phpでrequire_onceしてテストを実行してます。今のところ、うまく動いてくれてます。
<?php $files = array(); function getList($path) { $iter = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST); foreach ($iter as $elem) { if ($elem->isFile() && ereg('^.*\.php$', $elem->getFilename())) { $files[ereg_replace('(\.class)?\.php', '', $elem->getFilename())] = $elem->getPathname(); } } return $files; } $files = array_merge($files, getList('/usr/local/lib/php/symfony')); $files = array_merge($files, getList('/path/to/webapp/lib')); $files = array_merge($files, getList('/path/to/webapp/apps/frontend/lib')); file_put_contents('/tmp/.class_list', serialize($files)); function __autoload($class_name) { $files = unserialize(file_get_contents('/tmp/.class_list')); if ($class_name === '') { return; } if (isset($files[$class_name])) { include_once $files[$class_name]; } else { foreach ($files as $key => $value) { if (ereg($class_name . '$', $value)) { include_once $value; return; } } } if (preg_match('/^(.*)Peer$/', $class_name, $matches)) { BasePeer::getMapBuilder('lib.model.map.' . $matches[1] . 'MapBuilder'); } } ini_set('include_path', ini_get('include_path') . ':/usr/local/lib/php/symfony/vendor/'); Propel::setConfiguration( array ( 'propel' => array ( 'datasources' => array ( 'propel' => array ( 'adapter' => 'pgsql', 'connection' => array ( 'phptype' => 'pgsql', 'hostspec' => 'localhost', 'database' => 'database_server', 'username' => 'dbuser', 'password' => 'dbpassword', 'port' => 5432, 'encoding' => 'utf8', 'persistent' => true, 'protocol' => NULL, 'socket' => NULL, 'compat_assoc_lower' => NULL, 'compat_rtrim_string' => NULL, ), ), 'default' => 'propel', ), ), )); Propel::initialize();
クラスが必要になった際に__autoload関数が呼び出されるので、当該クラスファイルをinclude_onceすれば問題ないはず。なので、
キー:クラス名 値 :ファイル名
となるような配列を作り、それを__autoload関数で使う、という寸法です。
また、Propelで作ったmodelクラスは、getMapBuilderメソッドを呼び出しています。こうしないと、単独で使えませんでした。元ネタは。。。あれ?どこかにあったはず。。。
バッドノウハウの固まりみたいなものですが、晒しておきます。