Source for file Ethna_Plugin.php

Documentation is available at Ethna_Plugin.php

  1. <?php
  2. // vim: foldmethod=marker
  3. /**
  4.  *  Ethna_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$
  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.     /** @var    object  Ethna_Controller    コントローラオブジェクト */
  28.     var $controller;
  29.  
  30.     /** @var    object  Ethna_Controller    コントローラオブジェクト($controllerの省略形) */
  31.     var $ctl;
  32.  
  33.     /** @var    object  Ethna_Logger        ログオブジェクト */
  34.     var $logger;
  35.  
  36.     /** @var    array   プラグインのオブジェクト(インスタンス)を保存する配列 */
  37.     var $obj_registry array();
  38.  
  39.     /** @var    array   プラグインのクラス名、ソースファイル名を保存する配列 */
  40.     var $src_registry array();
  41.  
  42.     /** @var    array       検索対象となるプラグインのアプリケーションIDのリスト */
  43.     var $appid_list;
  44.  
  45.     /**#@-*/
  46.  
  47.     // {{{ コンストラクタ
  48.     /**
  49.      *  Ethna_Pluginのコンストラクタ
  50.      *
  51.      *  @access public
  52.      *  @param  object  Ethna_Controller    $controller コントローラオブジェクト
  53.      */
  54.     function Ethna_Plugin(&$controller)
  55.     {
  56.         $this->controller =$controller;
  57.         $this->ctl =$this->controller;
  58.         $this->logger null;
  59.         if (isset($this->controller->plugin_search_appids)
  60.             && is_array($this->controller->plugin_search_appids)) {
  61.             $this->appid_list =$this->controller->plugin_search_appids;
  62.         else {
  63.             $this->appid_list array($this->controller->getAppId()'Ethna');
  64.         }
  65.     }
  66.  
  67.     /**
  68.      *  loggerをsetする。
  69.      *
  70.      *  LogWriterはpluginなので、pluginインスタンス作成時点では
  71.      *  loggerに依存しないようにする。
  72.      *
  73.      *  @access public
  74.      *  @param  object  Ethna_Logger    $logger ログオブジェクト
  75.      */
  76.     function setLogger(&$logger)
  77.     {
  78.         if ($this->logger === null && is_object($logger)) {
  79.             $this->logger =$logger;
  80.         }
  81.     }
  82.     // }}}
  83.  
  84.     // {{{ プラグイン呼び出しインタフェース
  85.     /**
  86.      *  プラグインのインスタンスを取得
  87.      *
  88.      *  @access public
  89.      *  @param  string  $type   プラグインの種類
  90.      *  @param  string  $name   プラグインの名前
  91.      *  @return object  プラグインのインスタンス 
  92.      */
  93.     function &getPlugin($type$name)
  94.     {
  95.         return $this->_getPlugin($type$name);
  96.     }
  97.  
  98.     /**
  99.      *  ある種類 ($type) のプラグイン ($name) の全リストを取得
  100.      *
  101.      *  @access public
  102.      *  @param  string  $type   プラグインの種類
  103.      *  @return array   プラグインオブジェクトの配列
  104.      */
  105.     function getPluginList($type)
  106.     {
  107.         $plugin_list array();
  108.  
  109.         $this->searchAllPluginSrc($type);
  110.         if (isset($this->src_registry[$type]== false{
  111.             return $plugin_list;
  112.         }
  113.         foreach ($this->src_registry[$typeas $name => $value{
  114.             if (is_null($value)) {
  115.                 continue;
  116.             }
  117.             $plugin_list[$name=$this->getPlugin($type$name);
  118.         }
  119.         return $plugin_list;
  120.     }
  121.     // }}}
  122.  
  123.     // {{{ obj_registry のアクセサ
  124.     /**
  125.      *  プラグインのインスタンスをレジストリから取得
  126.      *
  127.      *  @access private
  128.      *  @param  string  $type   プラグインの種類
  129.      *  @param  string  $name   プラグインの名前
  130.      *  @return object  プラグインのインスタンス 
  131.      */
  132.     function &_getPlugin($type$name)
  133.     {
  134.         if (isset($this->obj_registry[$type]== false{
  135.             $this->obj_registry[$typearray();
  136.  
  137.             // プラグインの親クラスを(存在すれば)読み込み
  138.             foreach ($this->appid_list as $appid{
  139.                 list($class$dir$file$this->getPluginNaming($typenull$appid);
  140.                 $this->_includePluginSrc($class$dir$filetrue);
  141.             }
  142.         }
  143.  
  144.         // key がないときはプラグインをロードする
  145.         if (array_key_exists($name$this->obj_registry[$type]== false{
  146.             $this->_loadPlugin($type$name);
  147.         }
  148.  
  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);
  153.         }
  154.  
  155.         // プラグインのインスタンスを返す
  156.         return $this->obj_registry[$type][$name];
  157.     }
  158.  
  159.     /**
  160.      *  プラグインをincludeしてnewし,レジストリに登録
  161.      *
  162.      *  @access private
  163.      *  @param  string  $type   プラグインの種類
  164.      *  @param  string  $name   プラグインの名前
  165.      */
  166.     function _loadPlugin($type$name)
  167.     {
  168.         // プラグインのファイル名を取得
  169.         $plugin_src $this->_getPluginSrc($type$name);
  170.         if (is_null($plugin_src)) {
  171.             $this->obj_registry[$type][$namenull;
  172.             return;
  173.         }
  174.         list($plugin_class$plugin_dir$plugin_file$plugin_src;
  175.  
  176.         // プラグインのファイルを読み込み
  177.         $r =$this->_includePluginSrc($plugin_class$plugin_dir$plugin_file);
  178.         if (Ethna::isError($r)) {
  179.             $this->obj_registry[$type][$namenull;
  180.             return;
  181.         }
  182.  
  183.         // プラグイン作成
  184.         $instance =new $plugin_class($this->controller$type$name);
  185.         if (is_object($instance== false
  186.             || strcasecmp(get_class($instance)$plugin_class!= 0{
  187.             $this->logger->log(LOG_WARNING'plugin [%s::%s] instantiation failed'$type$name);
  188.             $this->obj_registry[$type][$namenull;
  189.             return;
  190.         }
  191.         $this->obj_registry[$type][$name=$instance;
  192.     }
  193.  
  194.     /**
  195.      *  プラグインのインスタンスをレジストリから消す
  196.      *
  197.      *  @access private
  198.      *  @param  string  $type   プラグインの種類
  199.      *  @param  string  $name   プラグインの名前
  200.      */
  201.     function _unloadPlugin($type$name)
  202.     {
  203.         unset($this->obj_registry[$type][$name]);
  204.     }
  205.     // }}}
  206.  
  207.     // {{{ src_registry のアクセサ
  208.     /**
  209.      *  プラグインのソースファイル名とクラス名をレジストリから取得
  210.      *
  211.      *  @access private
  212.      *  @param  string  $type   プラグインの種類
  213.      *  @param  string  $name   プラグインの名前
  214.      *  @return array   ソースファイル名とクラス名からなる配列
  215.      */
  216.     function _getPluginSrc($type$name)
  217.     {
  218.         if (isset($this->src_registry[$type]== false{
  219.             $this->src_registry[$typearray();
  220.         }
  221.  
  222.         // key がないときはプラグインの検索をする
  223.         if (array_key_exists($name$this->src_registry[$type]== false{
  224.             $this->_searchPluginSrc($type$name);
  225.         }
  226.  
  227.         // プラグインのソースを返す
  228.         return $this->src_registry[$type][$name];
  229.     }
  230.     // }}}
  231.  
  232.     // {{{ プラグインファイル検索部分
  233.     /**
  234.      *  プラグインのクラス名、ディレクトリ、ファイル名を決定
  235.      *
  236.      *  @access public
  237.      *  @param  string  $type   プラグインの種類
  238.      *  @param  string  $name   プラグインの名前 (nullのときは親クラス)
  239.      *  @param  string  $appid  アプリケーションID
  240.      *  @return array   プラグインのクラス名、ディレクトリ、ファイル名の配列
  241.      *  @todo   class factoryのnaming ruleと整合させる
  242.      */
  243.     function getPluginNaming($type$name$appid)
  244.     {
  245.         if ($appid == 'Ethna'{
  246.             if ($name === null{
  247.                 $ext 'php';
  248.                 $dir ETHNA_BASE "/class/Plugin";
  249.                 $class "Ethna_Plugin_{$type}";
  250.             else {
  251.                 $ext 'php';
  252.                 $dir ETHNA_BASE "/class/Plugin/{$type}";
  253.                 $class "Ethna_Plugin_{$type}_{$name}";
  254.             }
  255.         else {
  256.             if ($name === null{
  257.                 $ext $this->controller->getExt('php');
  258.                 $dir $this->controller->getDirectory('plugin');
  259.                 $class "{$appid}_Plugin_{$type}";
  260.             else {
  261.                 $ext $this->controller->getExt('php');
  262.                 $dir $this->controller->getDirectory('plugin'"/{$type}";
  263.                 $class "{$appid}_Plugin_{$type}_{$name}";
  264.             }
  265.         }
  266.  
  267.         $file  "{$class}.{$ext}";
  268.         return array($class$dir$file);
  269.     }
  270.  
  271.     /**
  272.      *  プラグインのソースを include する
  273.      *
  274.      *  @access private
  275.      *  @param  string  $class  クラス名
  276.      *  @param  string  $dir    ディレクトリ名
  277.      *  @param  string  $file   ファイル名
  278.      *  @param  bool    $parent 親クラスかどうかのフラグ
  279.      *  @return true|Ethna_Error
  280.      */
  281.     function &_includePluginSrc($class$dir$file$parent false)
  282.     {
  283.         $true true;
  284.         if (class_exists($class)) {
  285.             return $true;
  286.         }
  287.  
  288.         $file $dir '/' $file;
  289.         if (file_exists($file=== false{
  290.             if ($parent === false{
  291.                 return Ethna::raiseWarning('plugin file is not found: [%s]',
  292.                                            E_PLUGIN_NOTFOUND$file);
  293.             else {
  294.                 return $true;
  295.             }
  296.         }
  297.  
  298.         include_once $file;
  299.  
  300.         if (class_exists($class=== false{
  301.             if ($parent === false{
  302.                 return Ethna::raiseWarning('plugin class [%s] is not defined',
  303.                     E_PLUGIN_NOTFOUND$class);
  304.             else {
  305.                 return $true;
  306.             }
  307.         }
  308.  
  309.         if ($parent === false{
  310.             $this->logger->log(LOG_DEBUG'plugin class [%s] is defined'$class);
  311.         }
  312.         return $true;
  313.     }
  314.  
  315.     /**
  316.      *  アプリケーション, Ethna の順でプラグインのソースを検索する
  317.      *
  318.      *  @access private
  319.      *  @param  string  $type   プラグインの種類
  320.      *  @param  string  $name   プラグインの名前
  321.      */
  322.     function _searchPluginSrc($type$name)
  323.     {
  324.         // コントローラで指定されたアプリケーションIDの順に検索
  325.         foreach ($this->appid_list as $appid{
  326.             list($class$dir$file$this->getPluginNaming($type$name$appid);
  327.             if (class_exists($class)) {
  328.                 // すでにクラスが存在する場合は特別にスキップ
  329.                 if (isset($this->src_registry[$type]== false{
  330.                     $this->src_registry[$typearray();
  331.                 }
  332.                 $this->src_registry[$type][$namearray($classnullnull);
  333.                 return;
  334.             }
  335.             if (file_exists("{$dir}/{$file}")) {
  336.                 $this->logger->log(LOG_DEBUG'plugin file is found in search: [%s]',
  337.                                    "{$dir}/{$file}");
  338.                 if (isset($this->src_registry[$type]== false{
  339.                     $this->src_registry[$typearray();
  340.                 }
  341.                 $this->src_registry[$type][$namearray($class$dir$file);
  342.                 return;
  343.             }
  344.         }
  345.  
  346.         // 見つからなかった場合 (nullで記憶しておく)
  347.         $this->logger->log(LOG_WARNING'plugin file for [type=%s, name=%s] is not found in search'$type$name);
  348.         $this->src_registry[$type][$namenull;
  349.     }
  350.  
  351.     /**
  352.      *  プラグインの種類 ($type) をすべて検索する
  353.      *
  354.      *  @access public
  355.      *  @return array 
  356.      */
  357.     function searchAllPluginType()
  358.     {
  359.         $type_list array();
  360.         foreach (array_reverse($this->appid_listas $appid{
  361.             list($dir$this->getPluginNaming(''null$appid);
  362.             if (is_dir($dir== false{
  363.                 continue;
  364.             }
  365.             $dh opendir($dir);
  366.             if (is_resource($dh== false{
  367.                 continue;
  368.             }
  369.             while (($type_dir readdir($dh)) !== false{
  370.                 if ($type_dir{0!= '.' && is_dir("{$dir}/{$type_dir}")) {
  371.                     $type_list[$type_dir0;
  372.                 }
  373.             }
  374.             closedir($dh);
  375.         }
  376.         return array_keys($type_list);
  377.     }
  378.  
  379.     /**
  380.      *  指定された $type のプラグイン (のソース) をすべて検索する
  381.      *
  382.      *  @access public
  383.      *  @param  string  $type   プラグインの種類
  384.      */
  385.     function searchAllPluginSrc($type)
  386.     {
  387.         // 後で見付かったもので上書きするので $this->appid_list の逆順とする
  388.         $name_list array();
  389.         foreach (array_reverse($this->appid_listas $appid{
  390.             //  クラス名として許可された文字であればOKとする
  391.             //  アンダーバーを拒む理由はないし、命名規約からも禁止されていない
  392.             //  @see http://ethna.jp/ethna-document-dev_guide-plugin.html
  393.             //  @see http://www.php.net/manual/en/language.variables.php
  394.             list($class_regexp$dir$file_regexp$this->getPluginNaming($type'([a-zA-Z0-9_\x7f-\xff]+)'$appid);
  395.  
  396.             //ディレクトリの存在のチェック
  397.             if (is_dir($dir== false{
  398.                 // アプリ側で見付からないのは正常
  399.                 continue;
  400.             }
  401.  
  402.             // ディレクトリを開く
  403.             $dh opendir($dir);
  404.             if (is_resource($dh== false{
  405.                 $this->logger->log(LOG_DEBUG'cannot open plugin directory: [%s]'$dir);
  406.                 continue;
  407.             }
  408.             $this->logger->log(LOG_DEBUG'plugin directory opened: [%s]'$dir);
  409.  
  410.             // 条件にあう $name をリストに追加
  411.             while (($file readdir($dh)) !== false{
  412.                 if (preg_match('#^'.$file_regexp.'$#'$file$matches)
  413.                     && file_exists("{$dir}/{$file}")) {
  414.                     $name_list[$matches[1]] true;
  415.                 }
  416.             }
  417.  
  418.             closedir($dh);
  419.         }
  420.  
  421.         foreach (array_keys($name_listas $name{
  422.             // 冗長だがもう一度探しなおす
  423.             $this->_searchPluginSrc($type$name);
  424.         }
  425.     }
  426.     // }}}
  427.  
  428.     // {{{ static な include メソッド
  429.     /**
  430.      *  Ethna 本体付属のプラグインのソースを include する
  431.      *
  432.      *  @access public
  433.      *  @param  string  $type   プラグインの種類
  434.      *  @param  string  $name   プラグインの名前
  435.      *  @static
  436.      */
  437.     function includeEthnaPlugin($type$name)
  438.     {
  439.         Ethna_Plugin::includePlugin($type$name'Ethna');
  440.     }
  441.  
  442.     /**
  443.      *  プラグインのソースを include する
  444.      *
  445.      *  @access public
  446.      *  @param  string  $type   プラグインの種類
  447.      *  @param  string  $name   プラグインの名前
  448.      *  @param  string  $appid  アプリケーションID
  449.      *  @static
  450.      */
  451.     function includePlugin($type$name$appid null)
  452.     {
  453.         $ctl =Ethna_Controller::getInstance();
  454.         $plugin =$ctl->getPlugin();
  455.  
  456.         if ($appid === null{
  457.             $appid $ctl->getAppId();
  458.         }
  459.         list($class$dir$file$plugin->getPluginNaming($type$name$appid);
  460.         $plugin->_includePluginSrc($class$dir$file);
  461.     }
  462.     // }}}
  463. }
  464. // }}}
  465. ?>

Documentation generated on Fri, 11 Nov 2011 04:00:02 +0900 by phpDocumentor 1.4.3