OSDN Git Service

- now Ethna_ClassFactory#getManger first parameter is CASE-INSENSITIVE, because PHP...
authormumumu-org <mumumu-org@2ef88817-412d-0410-a32c-8029a115e976>
Tue, 24 Jun 2008 23:23:30 +0000 (23:23 +0000)
committermumumu-org <mumumu-org@2ef88817-412d-0410-a32c-8029a115e976>
Tue, 24 Jun 2008 23:23:30 +0000 (23:23 +0000)
class/Ethna_ClassFactory.php
class/Ethna_Controller.php
test/Ethna_ClassFactory_Test.php [new file with mode: 0644]
test/Ethna_MocktestManager.php [new file with mode: 0644]
test/Ethna_UnitTestBase.php

index bdc2e51..ea586a6 100644 (file)
@@ -64,33 +64,37 @@ class Ethna_ClassFactory
 
     /**
      *  typeに対応するアプリケーションマネージャオブジェクトを返す
+     *  注意: typeは大文字小文字を区別しない
+     *         (PHP自体が、クラス名の大文字小文字を区別しないため)
      *
      *  @access public
-     *  @param  string  $type   ã\82¯ã\83©ã\82¹ã\82­ã\83¼
+     *  @param  string  $type   ã\82¢ã\83\97ã\83ªã\82±ã\83¼ã\82·ã\83§ã\83³ã\83\9eã\83\8dã\83¼ã\82¸ã\83£ã\83¼å\90\8d
      *  @param  bool    $weak   オブジェクトが未生成の場合の強制生成フラグ(default: false)
      *  @return object  Ethna_AppManager    マネージャオブジェクト
-     *
-     *  TODO: 現状の実装では、typeを名前として扱っているのに、
-     *        大文字小文字を区別して違うインスタンスを返しているのを修正する
      */
     function &getManager($type, $weak = false)
     {
         $obj = null;
 
-        // check if object class exists
+        //  すでにincludeされていなければ、includeを試みる
+        //  ここで返されるクラス名は、AppObjectの命名規約によるもの
+        //
+        //  これは、AppObject のファイル中にAppManagerが含まれる場合が
+        //  あるため必要なルーチンである
         $obj_class_name = $this->controller->getObjectClassName($type);
         if (class_exists($obj_class_name) === false) {
-            // try include.
             $this->_include($obj_class_name);
         }
 
-        // check if manager class exists
+        //  すでにincludeされていなければ、includeを試みる
+        //  ここで返されるクラス名は、AppManagerの命名規約によるもの
         $class_name = $this->controller->getManagerClassName($type);
         if (class_exists($class_name) === false
             && $this->_include($class_name) === false) {
-            return $obj;
+            return $obj;  //  include 失敗。戻り値はNULL。
         }
 
+        //  メソッド情報を集める 
         if (isset($this->method_list[$class_name]) == false) {
             $this->method_list[$class_name] = get_class_methods($class_name);
             for ($i = 0; $i < count($this->method_list[$class_name]); $i++) {
@@ -98,14 +102,25 @@ class Ethna_ClassFactory
             }
         }
 
-        // see if this should be singlton or not
+        //  PHPのクラス名は大文字小文字を区別しないので、
+        //  同じクラス名と見做されるものを指定した場合には
+        //  同じインスタンスが返るようにする
+        $type = strtolower($type);
+
+        //  以下のルールに従って、キャッシュが利用可能かを判定する
+        //  利用可能と判断した場合、キャッシュされていればそれを返す
+        //
+        //  1. メソッドに getInstance があればキャッシュを利用可能と判断する
+        //     この場合、シングルトンかどうかは getInstance 次第
+        //  2. weak が true であれば、キャッシュは利用不能と判断してオブジェクトを再生成
+        //  3. weak が false であれば、キャッシュは利用可能と判断する(デフォルト) 
         if ($this->_isCacheAvailable($class_name, $this->method_list[$class_name], $weak)) {
             if (isset($this->manager[$type]) && is_object($this->manager[$type])) {
                 return $this->manager[$type];
             }
         }
 
-        // see if we have helper methods
+        //  インスタンス化のヘルパ(getInstance)があればそれを使う
         if (in_array("getinstance", $this->method_list[$class_name])) {
             $obj = call_user_func(array($class_name, 'getInstance'));
         } else {
@@ -113,6 +128,7 @@ class Ethna_ClassFactory
             $obj =& new $class_name($backend);
         }
 
+        //  生成したオブジェクトはとりあえずキャッシュする
         if (isset($this->manager[$type]) == false || is_object($this->manager[$type]) == false) {
             $this->manager[$type] =& $obj;
         }
@@ -122,14 +138,14 @@ class Ethna_ClassFactory
 
     /**
      *  クラスキーに対応するオブジェクトを返す/クラスキーが未定義の場合はAppObjectを探す
+     *  クラスキーとは、[Appid]_Controller#class に定められたもの。
      *
      *  @access public
-     *  @param  string  $key    クラスキー
-     *  @param  bool    $weak   オブジェクトが未生成の場合の強制生成フラグ(default: false)
+     *  @param  string  $key    [Appid]_Controller#class に定められたクラスキー
+     *                          このキーは大文字小文字を区別する 
+     *                          (配列のキーとして使われているため)
+     *  @param  bool    $ext    オブジェクトが未生成の場合の強制生成フラグ(default: false)
      *  @return object  生成されたオブジェクト(エラーならnull)
-     *
-     *  TODO: 現状の実装では、typeを名前として扱っているのに、
-     *        大文字小文字を区別して違うインスタンスを返しているのを修正する
      */
     function &getObject($key, $ext = false)
     {
@@ -148,20 +164,23 @@ class Ethna_ClassFactory
             list($weak) = $ext;
         }
 
-        // try to include if not defined
+        //  すでにincludeされていなければ、includeを試みる
         if (class_exists($class_name) == false) {
             if ($this->_include($class_name) == false) {
-                return $object;
+                return $object;  //  include 失敗。返り値はnull
             }
         }
 
-        // handle app object first
+        //  AppObject をはじめに扱う 
+        //  AppObject はキャッシュされないことに注意
         if (isset($this->class[$key]) == false) {
             $backend =& $this->controller->getBackend();
             $object =& new $class_name($backend, $key_type, $key_value, $prop);
             return $object;
         }
 
+        //  Ethna_Controllerで定義されたクラスキーの場合
+        //  はメソッド情報を集める 
         if (isset($this->method_list[$class_name]) == false) {
             $this->method_list[$class_name] = get_class_methods($class_name);
             for ($i = 0; $i < count($this->method_list[$class_name]); $i++) {
@@ -169,14 +188,20 @@ class Ethna_ClassFactory
             }
         }
 
-        // see if this should be singlton or not
+        //  以下のルールに従って、キャッシュが利用可能かを判定する
+        //  利用可能と判断した場合、キャッシュされていればそれを返す
+        //
+        //  1. メソッドに getInstance があればキャッシュを利用可能と判断する
+        //     この場合、シングルトンかどうかは getInstance 次第
+        //  2. weak が true であれば、キャッシュは利用不能と判断してオブジェクトを再生成
+        //  3. weak が false であれば、キャッシュは利用可能と判断する(デフォルト) 
         if ($this->_isCacheAvailable($class_name, $this->method_list[$class_name], $weak)) {
             if (isset($this->object[$key]) && is_object($this->object[$key])) {
                 return $this->object[$key];
             }
         }
 
-        // see if we have helper methods
+        //  インスタンス化のヘルパがあればそれを使う
         $method = sprintf('_getObject_%s', ucfirst($key));
         if (method_exists($this, $method)) {
             $object =& $this->$method($class_name);
@@ -186,6 +211,8 @@ class Ethna_ClassFactory
             $object =& new $class_name();
         }
 
+        //  クラスキーに定められたクラスのインスタンスは
+        //  とりあえずキャッシュする
         if (isset($this->object[$key]) == false || is_object($this->object[$key]) == false) {
             $this->object[$key] =& $object;
         }
index fbe133b..de880f3 100644 (file)
@@ -1881,6 +1881,8 @@ class Ethna_Controller
      */
     function getManagerClassName($name)
     {
+        //   アプリケーションIDと、渡された名前のはじめを大文字にして、
+        //   組み合わせたものが返される 
         return sprintf('%s_%sManager', $this->getAppId(), ucfirst($name));
     }
 
@@ -1893,7 +1895,12 @@ class Ethna_Controller
      */
     function getObjectClassName($name)
     {
+        //  引数のはじめの一文字目と、アンダーバー直後の
+        //  1文字を必ず大文字にする。アンダーバーは削除される。
         $name = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($name));
+        
+        //  $name に foo_bar を渡し、AppID が Hogeの場合
+        //  [Appid]_FooBar が返される
         return sprintf('%s_%s', $this->getAppId(), $name);
     }
 
diff --git a/test/Ethna_ClassFactory_Test.php b/test/Ethna_ClassFactory_Test.php
new file mode 100644 (file)
index 0000000..3344700
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+// vim: foldmethod=marker
+/**
+ *  Ethna_ClassFactory_Test.php
+ *
+ *  @author     Yoshinari Takaoka <takaoka@beatcraft.com>
+ *  @version    $Id$
+ */
+
+require_once ETHNA_BASE . '/test/Ethna_MocktestManager.php';
+
+//{{{    Ethna_ClassFactory_Test
+/**
+ *  Test Case For Ethna_ClassFactory_Test 
+ *
+ *  @access public
+ */
+class Ethna_ClassFactory_Test extends Ethna_UnitTestBase
+{
+    var $cf;
+
+    function setUp()
+    {
+        $ctl =& new Ethna_Controller();
+        $this->cf =& $ctl->getClassFactory();
+    }
+
+    //    Ethna_Controller と Ethna_ClassFactory は
+    //    循環参照している。PHP4では、循環参照しているオブジェクト同士を
+    //    比較しようとすると延々再帰的にプロパティと値を比較しようとする
+    //    ため Fatal Error を起こす。よって、PHP5以降でのみ以下はテストする
+    //    @see http://www.php.net/manual/en/language.oop.object-comparison.php
+    //    @see http://www.php.net/manual/en/language.oop5.object-comparison.php
+
+    function test_getManager()
+    {
+        //    大文字小文字を区別されても、
+        //    同じインスタンスを返さなければ
+        //    ならない
+        if (version_compare(phpversion(), '5', '>=')) {
+            $manager = $this->cf->getManager('mocktest');
+            $manager_alt = $this->cf->getManager('Mocktest');
+            $this->assertTrue($manager === $manager_alt);
+    
+            //    weakパラメータが指定された場合は 
+            //    強制的に違うオブジェクトを返さなければならない
+            $manager = $this->cf->getManager('mocktest');
+            $manager_alt = $this->cf->getManager('Mocktest', true);
+            $this->assertFalse($manager === $manager_alt);
+        }
+    }
+}
+// }}}
+
+?>
diff --git a/test/Ethna_MocktestManager.php b/test/Ethna_MocktestManager.php
new file mode 100644 (file)
index 0000000..23eff6c
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/**
+ *  Ethna_MocktestManager.php
+ *
+ *  @author     Yoshinari Takaoka <takaoka@beatcraft.com> 
+ *  @package    Ethna 
+ *  @version    $Id$
+ */
+
+/**
+ *  Ethna_MocktestManager
+ *  アプリケーションマネージャーテスト用のダミークラス
+ */
+class Ethna_MocktestManager extends Ethna_AppManager
+{
+    //  何も定義しない 
+}
+
+/**
+ *  Ethna_Mocktest
+ *  アプリケーションオブジェクトテスト用のダミークラス
+ */
+class Ethna_Mocktest extends Ethna_AppObject
+{
+    /**
+     *  property display name getter.
+     *
+     *  @access public
+     */
+    function getName($key)
+    {
+        return $this->get($key);
+    }
+}
+
+?>
index 3ab7240..c4161ee 100644 (file)
@@ -33,7 +33,7 @@ class Ethna_UnitTestBase extends UnitTestCase
         // controller
         $this->ctl =& Ethna_Controller::getInstance();
         if ($this->ctl === null) {
-            $this->ctl =&  new Ethna_Controller();
+            $this->ctl =& new Ethna_Controller();
         }
         $this->controller =& $this->ctl;