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 * get plugin obejct and set to property
163 * @param string $plugin_alias_name property name to set
164 * @param array $plugin array(type, name)
166 function setPlugin($plugin_alias_name, $plugin)
168 if (isset($this->{$plugin_alias_name})) {
169 return Ethna::raiseWarning('preload plugin alias name is conflicted [alias=%s], It doesn\'t loaded.',
170 E_PLUGIN_GENERAL, $plugin_alias_name);
173 $this->{$plugin_alias_name} = $this->getPlugin($plugin[0], $plugin[1]);
177 * プラグインをincludeしてnewし,レジストリに登録
180 * @param string $type プラグインの種類
181 * @param string $name プラグインの名前
183 function _loadPlugin($type, $name)
186 $plugin_src_registry = $this->_getPluginSrc($type, $name);
187 if (is_null($plugin_src_registry)) {
188 $this->obj_registry[$type][$name] = null;
191 list($plugin_class, $plugin_dir, $plugin_file) = $plugin_src_registry;
194 $r =& $this->_includePluginSrc($plugin_class, $plugin_dir, $plugin_file);
195 if (Ethna::isError($r)) {
196 $this->obj_registry[$type][$name] = null;
201 $instance =& new $plugin_class($this->controller, $type, $name);
202 if (is_object($instance) == false
203 || strcasecmp(get_class($instance), $plugin_class) != 0) {
205 if ($this->logger !== null) {
206 $this->logger->log(LOG_WARNING, 'plugin [%s::%s] instantiation failed', $type, $name);
209 $this->obj_registry[$type][$name] = null;
212 $this->obj_registry[$type][$name] =& $instance;
216 * プラグインのインスタンスをレジストリから消す
219 * @param string $type プラグインの種類
220 * @param string $name プラグインの名前
222 function _unloadPlugin($type, $name)
224 unset($this->obj_registry[$type][$name]);
229 * プラグインのインスタンスをレジストリから消す
232 * @param string $type プラグインの種類
233 * @param string $name プラグインの名前
235 function _loadPluginDirList()
237 $this->_dirlist[] = $this->controller->getDirectory('plugin');
240 $include_path_list = explode(PATH_SEPARATOR, get_include_path());
242 // Communiy based libraries
243 $extlib_dir = implode(DIRECTORY_SEPARATOR, array('Ethna', 'extlib', 'Plugin'));
245 $class_dir = implode(DIRECTORY_SEPARATOR, array('Ethna', 'class', 'Plugin'));
246 foreach ($include_path_list as $include_path) {
247 if (is_dir($include_path . DIRECTORY_SEPARATOR . $extlib_dir)) {
248 $this->_dirlist[] = $include_path . DIRECTORY_SEPARATOR . $extlib_dir;
250 if (is_dir($include_path . DIRECTORY_SEPARATOR . $class_dir)) {
251 $this->_dirlist[] = $include_path . DIRECTORY_SEPARATOR . $class_dir;
256 // {{{ src_registry のアクセサ
258 * プラグインのソースファイル名とクラス名をレジストリから取得
261 * @param string $type プラグインの種類
262 * @param string $name プラグインの名前
263 * @return array ソースファイル名とクラス名からなる配列
265 function _getPluginSrc($type, $name)
267 if (isset($this->src_registry[$type]) == false) {
268 $this->src_registry[$type] = array();
271 // key がないときはプラグインの検索をする
272 if (array_key_exists($name, $this->src_registry[$type]) == false) {
273 $this->_searchPluginSrc($type, $name);
277 return $this->src_registry[$type][$name];
283 * プラグインのクラス名、ディレクトリ、ファイル名を決定
286 * @param string $type プラグインの種類
287 * @param string $name プラグインの名前 (nullのときは親クラス)
288 * @param string $appid アプリケーションID (廃止予定)
289 * @return array プラグインのクラス名、ファイル名の配列
291 function getPluginNaming($type, $name = null, $appid = 'Ethna')
293 $ext = $this->ctl->getExt('php');
295 $plugin_class_name = array(
301 if ($name !== null) {
302 $plugin_class_name[] = $name;
308 $class = implode('_', $plugin_class_name);
309 $file = "{$name}.{$ext}";
311 return array($class, $file);
315 * プラグインのソースを include する
318 * @param string $class クラス名
319 * @param string $dir ディレクトリ名
320 * @param string $file ファイル名
321 * @param bool $parent 親クラスかどうかのフラグ
322 * @return true|Ethna_Error
324 function &_includePluginSrc($class, $dir, $file, $parent = false)
327 if (class_exists($class)) {
331 $file = $dir . '/' . $file;
332 if (file_exists_ex($file) === false) {
333 if ($parent === false) {
334 return Ethna::raiseWarning('plugin file is not found: [%s]',
335 E_PLUGIN_NOTFOUND, $file);
343 if (class_exists($class) === false) {
344 if ($parent === false) {
345 return Ethna::raiseWarning('plugin class [%s] is not defined',
346 E_PLUGIN_NOTFOUND, $class);
352 if ($parent === false) {
353 if ($this->logger !== null) {
354 $this->logger->log(LOG_DEBUG, 'plugin class [%s] is defined', $class);
361 * プラグインのソースディレクトリを決定する
363 * @param string $type プラグインの種類
364 * @param string $name プラグインの名前 (nullのときは親クラス)
365 * @retur string directory
367 function _searchPluginSrcDir($type, $name = null)
369 list(, $file) = $this->getPluginNaming($type, $name);
372 if ($name !== null) {
373 $dir_prefix = DIRECTORY_SEPARATOR . $type;
377 foreach ($this->_dirlist as $dir) {
380 if (file_exists($dir . DIRECTORY_SEPARATOR . $file)) {
385 return Ethna::raiseWarning('plugin file is not found in search directories: [%s]',
386 E_PLUGIN_NOTFOUND, $file);
390 * アプリケーション, extlib, Ethna の順でプラグインのソースを検索する
393 * @param string $type プラグインの種類
394 * @param string $name プラグインの名前
395 * @return array class, dir, file
397 function _searchPluginSrc($type, $name)
399 list($class, $file) = $this->getPluginNaming($type, $name);
401 // 古いバージョンのプラグインの命名規則にしたがったファイルは無視
402 if (strpos($name, "_") !== false) {
406 if (class_exists($class)) {
407 // すでにクラスが存在する場合は特別にスキップ
408 if (isset($this->src_registry[$type]) == false) {
409 $this->src_registry[$type] = array();
413 $dir = $this->_searchPluginSrcDir($type, $name);
415 if (Ethna::isError($dir)) {
416 $this->src_registry[$type][$name] = null;
420 if (file_exists("{$dir}/{$file}")) {
421 $this->logger->log(LOG_DEBUG, 'plugin file is found in search: [%s/%s]',
423 if (isset($this->src_registry[$type]) == false) {
424 $this->src_registry[$type] = array();
426 $this->src_registry[$type][$name] = array($class, $dir, $file);
430 // 見つからなかった場合 (nullで記憶しておく)
431 $this->logger->log(LOG_WARNING, 'plugin file for [type=%s, name=%s] is not found in search', $type, $name);
432 $this->src_registry[$type][$name] = null;
436 * プラグインの種類 ($type) をすべて検索する
441 function searchAllPluginType()
443 $type_list = array();
444 foreach($this->_dirlist as $dir) {
445 $type_dir= glob($dir . DIRECTORY_SEPARATOR . "*", GLOB_ONLYDIR);
449 foreach ($type_dir as $dir) {
450 if ($type_dir{0} != '.') {
451 $type_list[basename($dir)] = 0;
455 return array_keys($type_list);
459 * 指定された $type のプラグイン (のソース) をすべて検索する
462 * @param string $type プラグインの種類
464 function searchAllPluginSrc($type)
466 // 後で見付かったもので上書きするので $this->appid_list の逆順とする
467 $name_list = array();
468 $ext = $this->ctl->getExt('php');
470 foreach($this->_dirlist as $dir) {
471 $files = glob($dir . DIRECTORY_SEPARATOR . $type . DIRECTORY_SEPARATOR . "/*." . $ext);
473 $this->logger->log(LOG_DEBUG, 'cannot open plugin directory: [%s/%s]', $dir, $type);
476 $this->logger->log(LOG_DEBUG, 'plugin directory opened: [%s]', $dir);
477 foreach ($files as $plugin_file) {
478 $plugin_name = substr(basename($plugin_file), 0, - strlen($ext) - 1);
479 $name_list[$plugin_name] = 0;
483 foreach (array_keys($name_list) as $name) {
485 $this->_searchPluginSrc($type, $name);
490 // {{{ static な include メソッド
492 * Ethna 本体付属のプラグインのソースを include する
493 * (B.C.) Ethna 2.5.0 perview 5 以降,このメソッドには意味がありません.Ethna_Plugin::import を使ってください
496 * @param string $type プラグインの種類
497 * @param string $name プラグインの名前
500 function includeEthnaPlugin($type, $name)
502 Ethna_Plugin::import($type, $name);
506 * プラグインのソースを include する
509 * @param string $type プラグインの種類
510 * @param string $name プラグインの名前
512 function includePlugin($type, $name = null)
514 if ($name !== null) {
515 list($class, $file) = $this->getPluginNaming($type);
516 $dir = $this->_searchPluginSrcDir($type);
517 $this->_includePluginSrc($class, $dir, $file);
520 list($class, $file) = $this->getPluginNaming($type, $name);
521 $dir = $this->_searchPluginSrcDir($type, $name);
522 $this->_includePluginSrc($class, $dir, $file);
527 * プラグインのソースを include する
530 * @param string $type プラグインの種類
531 * @param string $name プラグインの名前
534 // static function import($type, $name = null)
535 function import($type, $name = null)
537 $ctl =& Ethna_Controller::getInstance();
538 $plugin =& $ctl->getPlugin();
540 $plugin->includePlugin($type, $name);