Source for file Plugin.php

Documentation is available at Plugin.php

  1. <?php
  2. // vim: foldmethod=marker
  3. /**
  4.  *  Plugin.php
  5.  *
  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
  9.  *  @package    Ethna
  10.  *  @version    $Id: dfb2c925eed3ab9e28c1135fa97ee80b9fc4c4d7 $
  11.  */
  12.  
  13. // {{{ Ethna_Plugin
  14. /**
  15.  *  プラグインクラス
  16.  *  
  17.  *  @author     ICHII Takashi <ichii386@schweetheart.jp>
  18.  *  @author     Kazuhiro Hosoi <hosoi@gree.co.jp>
  19.  *  @access     public
  20.  *  @package    Ethna
  21.  */
  22. {
  23.     /**#@+
  24.      *  @access private
  25.      */
  26.  
  27.     /** @protected    object  Ethna_Controller    コントローラオブジェクト */
  28.     protected $controller;
  29.  
  30.     /** @protected    object  Ethna_Controller    コントローラオブジェクト($controllerの省略形) */
  31.     protected $ctl;
  32.  
  33.     /** @protected    object  Ethna_Logger        ログオブジェクト */
  34.     protected $logger;
  35.  
  36.     /** @public    array   プラグインのオブジェクト(インスタンス)を保存する配列 */
  37.     public $obj_registry = array();
  38.  
  39.     /** @protected    array   プラグインのクラス名、ソースファイル名を保存する配列 */
  40.     protected $src_registry = array();
  41.  
  42.     /** @protected    array   検索対象ディレクトリを,プラグインの優先順に保存する配列 */
  43.     protected $_dirlist = array();
  44.  
  45.     /**#@-*/
  46.  
  47.     // {{{ コンストラクタ
  48.     /**
  49.      *  Ethna_Pluginのコンストラクタ
  50.      *
  51.      *  @access public
  52.      *  @param  object  Ethna_Controller    $controller コントローラオブジェクト
  53.      */
  54.     public function __construct($controller)
  55.     {
  56.         $this->controller = $controller;
  57.         $this->ctl = $this->controller;
  58.         $this->logger = null;
  59.  
  60.         // load dir_registry
  61.         $this->_loadPluginDirList();
  62.  
  63.     }
  64.  
  65.     /**
  66.      *  loggerをsetする。
  67.      *
  68.      *  LogWriterはpluginなので、pluginインスタンス作成時点では
  69.      *  loggerに依存しないようにする。
  70.      *
  71.      *  @access public
  72.      *  @param  object  Ethna_Logger    $logger ログオブジェクト
  73.      */
  74.     public function setLogger($logger)
  75.     {
  76.         if ($this->logger === null && is_object($logger)) {
  77.             $this->logger = $logger;
  78.         }
  79.     }
  80.     // }}}
  81.  
  82.     // {{{ プラグイン呼び出しインタフェース
  83.     /**
  84.      *  プラグインのインスタンスを取得
  85.      *
  86.      *  @access public
  87.      *  @param  string  $type   プラグインの種類
  88.      *  @param  string  $name   プラグインの名前
  89.      *  @return object  プラグインのインスタンス 
  90.      */
  91.     public function getPlugin($type$name)
  92.     {
  93.         return $this->_getPlugin($type$name);
  94.     }
  95.  
  96.     /**
  97.      *  ある種類 ($type) のプラグイン ($name) の全リストを取得
  98.      *
  99.      *  @access public
  100.      *  @param  string  $type   プラグインの種類
  101.      *  @return array   プラグインオブジェクトの配列
  102.      */
  103.     public function getPluginList($type)
  104.     {
  105.         $plugin_list array();
  106.  
  107.         $this->searchAllPluginSrc($type);
  108.         if (isset($this->src_registry[$type]== false{
  109.             return $plugin_list;
  110.         }
  111.         foreach ($this->src_registry[$typeas $name => $value{
  112.             if (is_null($value)) {
  113.                 continue;
  114.             }
  115.             $plugin_list[$name$this->getPlugin($type$name);
  116.         }
  117.         return $plugin_list;
  118.     }
  119.     // }}}
  120.  
  121.     // {{{ obj_registry のアクセサ
  122.     /**
  123.      *  プラグインのインスタンスをレジストリから取得
  124.      *
  125.      *  @access private
  126.      *  @param  string  $type   プラグインの種類
  127.      *  @param  string  $name   プラグインの名前
  128.      *  @return object  プラグインのインスタンス 
  129.      */
  130.     private function _getPlugin($type$name)
  131.     {
  132.         if (isset($this->obj_registry[$type]== false{
  133.             $this->obj_registry[$typearray();
  134.  
  135.             // プラグインの親クラスを(存在すれば)読み込み
  136.             list($class$file$this->getPluginNaming($typenull);
  137.             $dir $this->_searchPluginSrcDir($typenull);
  138.             if (!Ethna::isError($dir)) {
  139.                 $this->_includePluginSrc($class$dir$filetrue);
  140.             }
  141.         }
  142.  
  143.         // key がないときはプラグインをロードする
  144.         if (array_key_exists($name$this->obj_registry[$type]== false{
  145.             $this->_loadPlugin($type$name);
  146.         }
  147.  
  148.         // null のときはロードに失敗している
  149.         if (is_null($this->obj_registry[$type][$name])) {
  150.             return Ethna::raiseWarning('plugin [type=%s, name=%s] is not found',
  151.                 E_PLUGIN_NOTFOUND$type$name);
  152.         }
  153.  
  154.         // プラグインのインスタンスを返す
  155.         return $this->obj_registry[$type][$name];
  156.     }
  157.  
  158.     /**
  159.      *  get plugin obejct and set to property
  160.      *
  161.      *  @access public
  162.      *  @param  string  $plugin_alias_name  property name to set
  163.      *  @param  array   $plugin             array(type, name)
  164.      */
  165.     public function setPlugin($plugin_alias_name$plugin)
  166.     {
  167.         if (isset($this->{$plugin_alias_name})) {
  168.             return Ethna::raiseWarning('preload plugin alias name is conflicted [alias=%s], It doesn\'t loaded.',
  169.                 E_PLUGIN_GENERAL$plugin_alias_name);
  170.         }
  171.  
  172.         $this->{$plugin_alias_name$this->getPlugin($plugin[0]$plugin[1]);
  173.     }
  174.  
  175.     /**
  176.      *  プラグインをincludeしてnewし,レジストリに登録
  177.      *
  178.      *  @access private
  179.      *  @param  string  $type   プラグインの種類
  180.      *  @param  string  $name   プラグインの名前
  181.      */
  182.     private function _loadPlugin($type$name)
  183.     {
  184.         // プラグインのファイル名を取得
  185.         $plugin_src_registry $this->_getPluginSrc($type$name);
  186.         if (is_null($plugin_src_registry)) {
  187.             $this->obj_registry[$type][$namenull;
  188.             return;
  189.         }
  190.         list($plugin_class$plugin_dir$plugin_file$plugin_src_registry;
  191.  
  192.         // プラグインのファイルを読み込み
  193.         $r $this->_includePluginSrc($plugin_class$plugin_dir$plugin_file);
  194.         if (Ethna::isError($r)) {
  195.             $this->obj_registry[$type][$namenull;
  196.             return;
  197.         }
  198.  
  199.         // プラグイン作成
  200.         $instance new $plugin_class($this->controller$type$name);
  201.         if (is_object($instance== false
  202.             || strcasecmp(get_class($instance)$plugin_class!= 0{
  203.  
  204.             if ($this->logger !== null{
  205.                 $this->logger->log(LOG_WARNING'plugin [%s::%s] instantiation failed'$type$name);
  206.             }
  207.  
  208.             $this->obj_registry[$type][$namenull;
  209.             return;
  210.         }
  211.         $this->obj_registry[$type][$name$instance;
  212.     }
  213.  
  214.     /**
  215.      *  プラグインのインスタンスをレジストリから消す
  216.      *
  217.      *  @access private
  218.      *  @param  string  $type   プラグインの種類
  219.      *  @param  string  $name   プラグインの名前
  220.      */
  221.     public function _unloadPlugin($type$name)
  222.     {
  223.         unset($this->obj_registry[$type][$name]);
  224.     }
  225.     // }}}
  226.  
  227.     /**
  228.      *  プラグインのインスタンスをレジストリから消す
  229.      *
  230.      *  @access private
  231.      *  @param  string  $type   プラグインの種類
  232.      *  @param  string  $name   プラグインの名前
  233.      */
  234.     private function _loadPluginDirList()
  235.     {
  236.         $this->_dirlist[$this->controller->getDirectory('plugin');
  237.  
  238.         // include_path から検索
  239.         $include_path_list explode(PATH_SEPARATORget_include_path());
  240.  
  241.         // Communiy based libraries
  242.         $extlib_dir implode(DIRECTORY_SEPARATORarray('Ethna''extlib''Plugin'));
  243.         // Ethna bandle
  244.         $class_dir implode(DIRECTORY_SEPARATORarray('Ethna''class''Plugin'));
  245.         foreach ($include_path_list as $include_path{
  246.             if (is_dir($include_path DIRECTORY_SEPARATOR $extlib_dir)) {
  247.                 $this->_dirlist[$include_path DIRECTORY_SEPARATOR $extlib_dir;
  248.             }
  249.             if (is_dir($include_path DIRECTORY_SEPARATOR $class_dir)) {
  250.                 $this->_dirlist[$include_path DIRECTORY_SEPARATOR $class_dir;
  251.             }
  252.         }
  253.     }
  254.  
  255.     // {{{ src_registry のアクセサ
  256.     /**
  257.      *  プラグインのソースファイル名とクラス名をレジストリから取得
  258.      *
  259.      *  @access private
  260.      *  @param  string  $type   プラグインの種類
  261.      *  @param  string  $name   プラグインの名前
  262.      *  @return array   ソースファイル名とクラス名からなる配列
  263.      */
  264.     private function _getPluginSrc($type$name)
  265.     {
  266.         if (isset($this->src_registry[$type]== false{
  267.             $this->src_registry[$typearray();
  268.         }
  269.  
  270.         // key がないときはプラグインの検索をする
  271.         if (array_key_exists($name$this->src_registry[$type]== false{
  272.             $this->_searchPluginSrc($type$name);
  273.         }
  274.  
  275.         // プラグインのソースを返す
  276.         return $this->src_registry[$type][$name];
  277.     }
  278.     // }}}
  279.  
  280.     // {{{ プラグインファイル検索部分
  281.     /**
  282.      *  プラグインのクラス名、ディレクトリ、ファイル名を決定
  283.      *
  284.      *  @access public
  285.      *  @param  string  $type   プラグインの種類
  286.      *  @param  string  $name   プラグインの名前 (nullのときは親クラス)
  287.      *  @param  string  $appid  アプリケーションID (廃止予定)
  288.      *  @return array   プラグインのクラス名、ファイル名の配列
  289.      */
  290.     public function getPluginNaming($type$name null$appid 'Ethna')
  291.     {
  292.         $ext $this->ctl->getExt('php');
  293.  
  294.         $plugin_class_name array(
  295.             $appid,
  296.             'Plugin',
  297.             $type,
  298.         );
  299.  
  300.         if ($name !== null{
  301.             $plugin_class_name[$name;
  302.         }
  303.         else {
  304.             $name $type;
  305.         }
  306.  
  307.         $class implode('_'$plugin_class_name);
  308.         $file  "{$name}.{$ext}";
  309.  
  310.         return array($class$file);
  311.     }
  312.  
  313.     /**
  314.      *  プラグインのソースを include する
  315.      *
  316.      *  @access private
  317.      *  @param  string  $class  クラス名
  318.      *  @param  string  $dir    ディレクトリ名
  319.      *  @param  string  $file   ファイル名
  320.      *  @param  bool    $parent 親クラスかどうかのフラグ
  321.      *  @return true|Ethna_Error
  322.      */
  323.     private function _includePluginSrc($class$dir$file$parent false)
  324.     {
  325.         $true true;
  326.         if (class_exists($class)) {
  327.             return $true;
  328.         }
  329.  
  330.         $file $dir '/' $file;
  331.         if (file_exists_ex($file=== false{
  332.             if ($parent === false{
  333.                 return Ethna::raiseWarning('plugin file is not found: [%s]',
  334.                                            E_PLUGIN_NOTFOUND$file);
  335.             else {
  336.                 return $true;
  337.             }
  338.         }
  339.  
  340.         include_once $file;
  341.  
  342.         if (class_exists($class=== false{
  343.             if ($parent === false{
  344.                 return Ethna::raiseWarning('plugin class [%s] is not defined',
  345.                     E_PLUGIN_NOTFOUND$class);
  346.             else {
  347.                 return $true;
  348.             }
  349.         }
  350.  
  351.         if ($parent === false{
  352.             if ($this->logger !== null{
  353.                 $this->logger->log(LOG_DEBUG'plugin class [%s] is defined'$class);
  354.             }
  355.         }
  356.         return $true;
  357.     }
  358.  
  359.     /**
  360.      *  プラグインのソースディレクトリを決定する
  361.      *
  362.      *  @param  string  $type   プラグインの種類
  363.      *  @param  string  $name   プラグインの名前 (nullのときは親クラス)
  364.      *  @retur  string  directory
  365.      */
  366.     public function _searchPluginSrcDir($type$name null)
  367.     {
  368.         list($file$this->getPluginNaming($type$name);
  369.  
  370.         $dir_prefix "";
  371.         if ($name !== null{
  372.             $dir_prefix DIRECTORY_SEPARATOR $type;
  373.         }
  374.  
  375.         // dirlist にしたがって検索
  376.         foreach ($this->_dirlist as $dir{
  377.             $dir .= $dir_prefix;
  378.  
  379.             if (file_exists($dir DIRECTORY_SEPARATOR $file)) {
  380.                 return $dir;
  381.             }
  382.         }
  383.  
  384.         return Ethna::raiseWarning('plugin file is not found in search directories: [%s]',
  385.                                    E_PLUGIN_NOTFOUND$file);
  386.     }
  387.  
  388.     /**
  389.      *  アプリケーション, extlib, Ethna の順でプラグインのソースを検索する
  390.      *
  391.      *  @access private
  392.      *  @param  string  $type   プラグインの種類
  393.      *  @param  string  $name   プラグインの名前
  394.      *  @return array   class, dir, file
  395.      */
  396.     private function _searchPluginSrc($type$name)
  397.     {
  398.         list($class$file$this->getPluginNaming($type$name);
  399.  
  400.         // 古いバージョンのプラグインの命名規則にしたがったファイルは無視
  401.         if (strpos($name"_"!== false{
  402.             return;
  403.         }
  404.  
  405.         if (class_exists($class)) {
  406.             // すでにクラスが存在する場合は特別にスキップ
  407.             if (isset($this->src_registry[$type]== false{
  408.                 $this->src_registry[$typearray();
  409.             }
  410.         }
  411.  
  412.         $dir $this->_searchPluginSrcDir($type$name);
  413.  
  414.         if (Ethna::isError($dir)) {
  415.             $this->src_registry[$type][$namenull;
  416.             return ;
  417.         }
  418.  
  419.         if (file_exists("{$dir}/{$file}")) {
  420.             $this->logger->log(LOG_DEBUG'plugin file is found in search: [%s/%s]',
  421.                                $dir$file);
  422.             if (isset($this->src_registry[$type]== false{
  423.                 $this->src_registry[$typearray();
  424.             }
  425.             $this->src_registry[$type][$namearray($class$dir$file);
  426.             return;
  427.         }
  428.  
  429.         // 見つからなかった場合 (nullで記憶しておく)
  430.         $this->logger->log(LOG_WARNING'plugin file for [type=%s, name=%s] is not found in search'$type$name);
  431.         $this->src_registry[$type][$namenull;
  432.     }
  433.  
  434.     /**
  435.      *  プラグインの種類 ($type) をすべて検索する
  436.      *
  437.      *  @access public
  438.      *  @return array 
  439.      */
  440.     public function searchAllPluginType()
  441.     {
  442.         $type_list array();
  443.         foreach($this->_dirlist as $dir{
  444.             $type_dirglob($dir DIRECTORY_SEPARATOR "*"GLOB_ONLYDIR);
  445.             if (!$type_dir{
  446.                 continue;
  447.             }
  448.             foreach ($type_dir as $dir{
  449.                 if ($type_dir{0!= '.'{
  450.                     $type_list[basename($dir)0;
  451.                 }
  452.             }
  453.         }
  454.         return array_keys($type_list);
  455.     }
  456.  
  457.     /**
  458.      *  指定された $type のプラグイン (のソース) をすべて検索する
  459.      *
  460.      *  @access public
  461.      *  @param  string  $type   プラグインの種類
  462.      */
  463.     public function searchAllPluginSrc($type)
  464.     {
  465.         // 後で見付かったもので上書きするので $this->appid_list の逆順とする
  466.         $name_list array();
  467.         $ext $this->ctl->getExt('php');
  468.  
  469.         foreach($this->_dirlist as $dir{
  470.             $files glob($dir DIRECTORY_SEPARATOR $type DIRECTORY_SEPARATOR "/*." $ext);
  471.             if (!$files{
  472.                 $this->logger->log(LOG_DEBUG'cannot open plugin directory: [%s/%s]'$dir$type);
  473.                 continue;
  474.             }
  475.             $this->logger->log(LOG_DEBUG'plugin directory opened: [%s]'$dir);
  476.             foreach ($files as $plugin_file{
  477.                 $plugin_name substr(basename($plugin_file)0strlen($ext1);
  478.                 $name_list[$plugin_name0;
  479.             }
  480.         }
  481.  
  482.         foreach (array_keys($name_listas $name{
  483.             // 冗長だがもう一度探しなおす
  484.             $this->_searchPluginSrc($type$name);
  485.         }
  486.     }
  487.     // }}}
  488.  
  489.     // {{{ static な include メソッド
  490.     /**
  491.      *  Ethna 本体付属のプラグインのソースを include する
  492.      *  (B.C.) Ethna 2.5.0 perview 5 以降,このメソッドには意味がありません.Ethna_Plugin::import を使ってください
  493.      *
  494.      *  @access public
  495.      *  @param  string  $type   プラグインの種類
  496.      *  @param  string  $name   プラグインの名前
  497.      *  @static
  498.      */
  499.     public static function includeEthnaPlugin($type$name)
  500.     {
  501.         Ethna_Plugin::import($type$name);
  502.     }
  503.  
  504.     /**
  505.      *  プラグインのソースを include する
  506.      *
  507.      *  @access public
  508.      *  @param  string  $type   プラグインの種類
  509.      *  @param  string  $name   プラグインの名前
  510.      */
  511.     public function includePlugin($type$name null)
  512.     {
  513.         if ($name !== null{
  514.             list($class$file$this->getPluginNaming($type);
  515.             $dir $this->_searchPluginSrcDir($type);
  516.             $this->_includePluginSrc($class$dir$file);
  517.         }
  518.  
  519.         list($class$file$this->getPluginNaming($type$name);
  520.         $dir $this->_searchPluginSrcDir($type$name);
  521.         $this->_includePluginSrc($class$dir$file);
  522.     }
  523.     // }}}
  524.  
  525.     /**
  526.      *  プラグインのソースを include する
  527.      *
  528.      *  @access public
  529.      *  @param  string  $type   プラグインの種類
  530.      *  @param  string  $name   プラグインの名前
  531.      *  @static
  532.      */
  533.     // static function import($type, $name = null)
  534.     public static function import($type$name null)
  535.     {
  536.         $ctl Ethna_Controller::getInstance();
  537.         $plugin $ctl->getPlugin();
  538.  
  539.         $plugin->includePlugin($type$name);
  540.     }
  541. }
  542. // }}}

Documentation generated on Fri, 11 Nov 2011 03:58:57 +0900 by phpDocumentor 1.4.3