2 // vim: foldmethod=marker
6 * @author ICHII Takashi <ichii386@schweetheart.jp>
7 * @author Kazuhiro Hosoi <hosoi@gree.co.jp>
8 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
17 * @author ICHII Takashi <ichii386@schweetheart.jp>
18 * @author Kazuhiro Hosoi <hosoi@gree.co.jp>
28 /** @var object Ethna_Controller コントローラオブジェクト */
31 /** @var object Ethna_Controller コントローラオブジェクト($controllerの省略形) */
34 /** @var object Ethna_Logger ログオブジェクト */
37 /** @var array プラグインのオブジェクト(インスタンス)を保存する配列 */
38 var $obj_registry = array();
40 /** @var array プラグインのクラス名、ソースファイル名を保存する配列 */
41 var $src_registry = array();
43 /** @var array 検索対象ディレクトリを,プラグインの優先順に保存する配列 */
44 var $_dirlist = array();
50 * Ethna_Pluginのコンストラクタ
53 * @param object Ethna_Controller $controller コントローラオブジェクト
55 function Ethna_Plugin(&$controller)
57 $this->controller =& $controller;
58 $this->ctl =& $this->controller;
62 $this->_loadPluginDirList();
69 * LogWriterはpluginなので、pluginインスタンス作成時点では
73 * @param object Ethna_Logger $logger ログオブジェクト
75 function setLogger(&$logger)
77 if ($this->logger === null && is_object($logger)) {
78 $this->logger =& $logger;
83 // {{{ プラグイン呼び出しインタフェース
88 * @param string $type プラグインの種類
89 * @param string $name プラグインの名前
90 * @return object プラグインのインスタンス
92 function &getPlugin($type, $name)
94 return $this->_getPlugin($type, $name);
98 * ある種類 ($type) のプラグイン ($name) の全リストを取得
101 * @param string $type プラグインの種類
102 * @return array プラグインオブジェクトの配列
104 function getPluginList($type)
106 $plugin_list = array();
108 $this->searchAllPluginSrc($type);
109 if (isset($this->src_registry[$type]) == false) {
112 foreach ($this->src_registry[$type] as $name => $value) {
113 if (is_null($value)) {
116 $plugin_list[$name] =& $this->getPlugin($type, $name);
122 // {{{ obj_registry のアクセサ
124 * プラグインのインスタンスをレジストリから取得
127 * @param string $type プラグインの種類
128 * @param string $name プラグインの名前
129 * @return object プラグインのインスタンス
131 function &_getPlugin($type, $name)
133 if (isset($this->obj_registry[$type]) == false) {
134 $this->obj_registry[$type] = array();
136 // プラグインの親クラスを(存在すれば)読み込み
137 list($class, $file) = $this->getPluginNaming($type, null);
138 $dir = $this->_searchPluginSrcDir($type, null);
139 if (!Ethna::isError($dir)) {
140 $this->_includePluginSrc($class, $dir, $file, true);
144 // key がないときはプラグインをロードする
145 if (array_key_exists($name, $this->obj_registry[$type]) == false) {
146 $this->_loadPlugin($type, $name);
149 // null のときはロードに失敗している
150 if (is_null($this->obj_registry[$type][$name])) {
151 return Ethna::raiseWarning('plugin [type=%s, name=%s] is not found',
152 E_PLUGIN_NOTFOUND, $type, $name);
156 return $this->obj_registry[$type][$name];
160 * プラグインをincludeしてnewし,レジストリに登録
163 * @param string $type プラグインの種類
164 * @param string $name プラグインの名前
166 function _loadPlugin($type, $name)
169 $plugin_src_registry = $this->_getPluginSrc($type, $name);
170 if (is_null($plugin_src_registry)) {
171 $this->obj_registry[$type][$name] = null;
174 list($plugin_class, $plugin_dir, $plugin_file) = $plugin_src_registry;
177 $r =& $this->_includePluginSrc($plugin_class, $plugin_dir, $plugin_file);
178 if (Ethna::isError($r)) {
179 $this->obj_registry[$type][$name] = null;
184 $instance =& new $plugin_class($this->controller, $type, $name);
185 if (is_object($instance) == false
186 || strcasecmp(get_class($instance), $plugin_class) != 0) {
188 if ($this->logger !== null) {
189 $this->logger->log(LOG_WARNING, 'plugin [%s::%s] instantiation failed', $type, $name);
192 $this->obj_registry[$type][$name] = null;
195 $this->obj_registry[$type][$name] =& $instance;
199 * プラグインのインスタンスをレジストリから消す
202 * @param string $type プラグインの種類
203 * @param string $name プラグインの名前
205 function _unloadPlugin($type, $name)
207 unset($this->obj_registry[$type][$name]);
212 * プラグインのインスタンスをレジストリから消す
215 * @param string $type プラグインの種類
216 * @param string $name プラグインの名前
218 function _loadPluginDirList()
220 $this->_dirlist[] = $this->controller->getDirectory('plugin');
223 $include_path_list = explode(PATH_SEPARATOR, get_include_path());
225 // Communiy based libraries
226 $extlib_dir = implode(DIRECTORY_SEPARATOR, array('Ethna', 'extlib', 'Plugin'));
228 $class_dir = implode(DIRECTORY_SEPARATOR, array('Ethna', 'class', 'Plugin'));
229 foreach ($include_path_list as $include_path) {
230 if (is_dir($include_path . DIRECTORY_SEPARATOR . $extlib_dir)) {
231 $this->_dirlist[] = $include_path . DIRECTORY_SEPARATOR . $extlib_dir;
233 if (is_dir($include_path . DIRECTORY_SEPARATOR . $class_dir)) {
234 $this->_dirlist[] = $include_path . DIRECTORY_SEPARATOR . $class_dir;
239 // {{{ src_registry のアクセサ
241 * プラグインのソースファイル名とクラス名をレジストリから取得
244 * @param string $type プラグインの種類
245 * @param string $name プラグインの名前
246 * @return array ソースファイル名とクラス名からなる配列
248 function _getPluginSrc($type, $name)
250 if (isset($this->src_registry[$type]) == false) {
251 $this->src_registry[$type] = array();
254 // key がないときはプラグインの検索をする
255 if (array_key_exists($name, $this->src_registry[$type]) == false) {
256 $this->_searchPluginSrc($type, $name);
260 return $this->src_registry[$type][$name];
266 * プラグインのクラス名、ディレクトリ、ファイル名を決定
269 * @param string $type プラグインの種類
270 * @param string $name プラグインの名前 (nullのときは親クラス)
271 * @param string $appid アプリケーションID (廃止予定)
272 * @return array プラグインのクラス名、ファイル名の配列
274 function getPluginNaming($type, $name = null, $appid = 'Ethna')
276 $ext = $this->ctl->getExt('php');
278 $plugin_class_name = array(
284 if ($name !== null) {
285 $plugin_class_name[] = $name;
291 $class = implode('_', $plugin_class_name);
292 $file = "{$name}.{$ext}";
294 return array($class, $file);
298 * プラグインのソースを include する
301 * @param string $class クラス名
302 * @param string $dir ディレクトリ名
303 * @param string $file ファイル名
304 * @param bool $parent 親クラスかどうかのフラグ
305 * @return true|Ethna_Error
307 function &_includePluginSrc($class, $dir, $file, $parent = false)
310 if (class_exists($class)) {
314 $file = $dir . '/' . $file;
315 if (file_exists_ex($file) === false) {
316 if ($parent === false) {
317 return Ethna::raiseWarning('plugin file is not found: [%s]',
318 E_PLUGIN_NOTFOUND, $file);
326 if (class_exists($class) === false) {
327 if ($parent === false) {
328 return Ethna::raiseWarning('plugin class [%s] is not defined',
329 E_PLUGIN_NOTFOUND, $class);
335 if ($parent === false) {
336 if ($this->logger !== null) {
337 $this->logger->log(LOG_DEBUG, 'plugin class [%s] is defined', $class);
344 * プラグインのソースディレクトリを決定する
346 * @param string $type プラグインの種類
347 * @param string $name プラグインの名前 (nullのときは親クラス)
348 * @retur string directory
350 function _searchPluginSrcDir($type, $name)
352 list(, $file) = $this->getPluginNaming($type, $name);
355 if ($name !== null) {
356 $dir_prefix = DIRECTORY_SEPARATOR . $type;
360 foreach ($this->_dirlist as $dir) {
363 if (file_exists($dir . DIRECTORY_SEPARATOR . $file)) {
368 return Ethna::raiseWarning('plugin file is not found in search directories: [%s]',
369 E_PLUGIN_NOTFOUND, $file);
373 * アプリケーション, extlib, Ethna の順でプラグインのソースを検索する
376 * @param string $type プラグインの種類
377 * @param string $name プラグインの名前
378 * @return array class, dir, file
380 function _searchPluginSrc($type, $name)
382 list($class, $file) = $this->getPluginNaming($type, $name);
384 // 古いバージョンのプラグインの命名規則にしたがったファイルは無視
385 if (strpos($name, "_") !== false) {
389 if (class_exists($class)) {
390 // すでにクラスが存在する場合は特別にスキップ
391 if (isset($this->src_registry[$type]) == false) {
392 $this->src_registry[$type] = array();
396 $dir = $this->_searchPluginSrcDir($type, $name);
398 if (Ethna::isError($dir)) {
399 $this->src_registry[$type][$name] = null;
403 if (file_exists("{$dir}/{$file}")) {
404 $this->logger->log(LOG_DEBUG, 'plugin file is found in search: [%s/%s]',
406 if (isset($this->src_registry[$type]) == false) {
407 $this->src_registry[$type] = array();
409 $this->src_registry[$type][$name] = array($class, $dir, $file);
413 // 見つからなかった場合 (nullで記憶しておく)
414 $this->logger->log(LOG_WARNING, 'plugin file for [type=%s, name=%s] is not found in search', $type, $name);
415 $this->src_registry[$type][$name] = null;
419 * プラグインの種類 ($type) をすべて検索する
424 function searchAllPluginType()
426 $type_list = array();
427 foreach($this->_dirlist as $dir) {
428 $type_dir= glob($dir . DIRECTORY_SEPARATOR . "*", GLOB_ONLYDIR);
432 foreach ($type_dir as $dir) {
433 if ($type_dir{0} != '.') {
434 $type_list[basename($dir)] = 0;
438 return array_keys($type_list);
442 * 指定された $type のプラグイン (のソース) をすべて検索する
445 * @param string $type プラグインの種類
447 function searchAllPluginSrc($type)
449 // 後で見付かったもので上書きするので $this->appid_list の逆順とする
450 $name_list = array();
451 $ext = $this->ctl->getExt('php');
453 foreach($this->_dirlist as $dir) {
454 $files = glob($dir . DIRECTORY_SEPARATOR . $type . DIRECTORY_SEPARATOR . "/*." . $ext);
456 $this->logger->log(LOG_DEBUG, 'cannot open plugin directory: [%s/%s]', $dir, $type);
459 $this->logger->log(LOG_DEBUG, 'plugin directory opened: [%s]', $dir);
460 foreach ($files as $plugin_file) {
461 $plugin_name = substr(basename($plugin_file), 0, - strlen($ext) - 1);
462 $name_list[$plugin_name] = 0;
466 foreach (array_keys($name_list) as $name) {
468 $this->_searchPluginSrc($type, $name);
473 // {{{ static な include メソッド
475 * Ethna 本体付属のプラグインのソースを include する
476 * (B.C.) Ethna 2.5.0 perview 5 以降,このメソッドには意味がありません.Ethna_Plugin::import を使ってください
479 * @param string $type プラグインの種類
480 * @param string $name プラグインの名前
483 function includeEthnaPlugin($type, $name)
485 Ethna_Plugin::import($type, $name);
489 * プラグインのソースを include する
492 * @param string $type プラグインの種類
493 * @param string $name プラグインの名前
494 * @param string $appid アプリケーションID
496 function includePlugin($type, $name = null)
498 list($class, $file) = $this->getPluginNaming($type, $name);
499 $dir = $this->_searchPluginSrcDir($type, $name);
500 $this->_includePluginSrc($class, $dir, $file);
505 * プラグインのソースを include する
508 * @param string $type プラグインの種類
509 * @param string $name プラグインの名前
510 * @param string $appid アプリケーションID
513 // static function import($type, $name)
514 function import($type, $name = null)
516 $ctl =& Ethna_Controller::getInstance();
517 $plugin =& $ctl->getPlugin();
519 if ($appid === null) {
520 $appid = $ctl->getAppId();
523 $plugin->includePlugin($type, $name);