Browse Source

ZF-6543: allow registering resources by class name; allow specifying explicit resource name to register with bootstrap

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@15439 44c647ce-9c0f-0410-b52a-842ac1e357ba
matthew 16 years ago
parent
commit
78d6ada1f5

+ 110 - 0
documentation/manual/en/module_specs/Zend_Application-CoreFunctionality-Resource_ResourceAbstract.xml

@@ -95,4 +95,114 @@
             </tbody>
         </tgroup>
     </table>
+
+    <sect3 id="zend.application.core-functionality.resource-resourceabstract.names">
+        <title>Resource Names</title>
+
+        <para>
+            When registering plugin resources, one issue that arises is how you
+            should refer to them from the parent bootstrap class. There are
+            three different mechanisms that may be used, depending on how you
+            have configured the bootstrap and its plugin resources.
+        </para>
+
+        <para>
+            First, if your plugins are defined within a defined prefix path, you
+            may refer to them simply by their "short name" -- i.e., the portion
+            of the class name following the class prefix. As an example, the
+            class "Zend_Application_Resource_View" may be referenced as simply
+            "View", as the prefix path "ZenD_Application_Resource" is already
+            registered. You may register them using the full class name or the
+            short name:
+        </para>
+
+        <programlisting role="php"><![CDATA[
+$app = new Zend_Application(APPLICATION_ENV, array(
+    'pluginPaths' => array(
+        'My_Resource' => 'My/Resource/',
+    ),
+    'resources' => array(
+        // if the following class exists:
+        'My_Resource_View' => array(),
+
+        // then this is equivalent:
+        'View' => array(),
+    ),
+));
+]]></programlisting>
+
+        <para>
+            In each case, you can then bootstrap the resource and retrieve it
+            later using the short name:
+        </para>
+
+        <programlisting role="php"><![CDATA[
+$bootstrap->bootstrap('view');
+$view = $bootstrap->getResource('view');
+]]></programlisting>
+
+        <para>
+            Second, if no matching plugin path is defined, you may still pass a
+            resource by the full class name. In this case, you can reference it
+            using the resource's full class name:
+        </para>
+
+        <programlisting role="php"><![CDATA[
+$app = new Zend_Application(APPLICATION_ENV, array(
+    'resources' => array(
+        // This will load the standard 'View' resource:
+        'View' => array(),
+
+        // While this loads a resource with a specific class name:
+        'My_Resource_View' => array(),
+    ),
+));
+]]></programlisting>
+
+        <para>
+            Obviously, this makes referencing the resource much more verbose:
+        </para>
+
+        <programlisting role="php"><![CDATA[
+$bootstrap->bootstrap('My_Resource_View');
+$view = $bootstrap->getResource('My_Resource_View');
+]]></programlisting>
+
+        <para>
+            This brings us to the third option. You can specify an explicit name
+            that a given resource class will register as. This can be done by
+            adding a public <code>$_explicitType</code> property to the resource
+            plugin class, with a string value; that value will then be used
+            whenever you wish to reference the plugin resource via the
+            bootstrap. As an example, let's define our own view class:
+        </para>
+
+        <programlisting role="php"><![CDATA[
+class My_Resource_View extends Zend_Application_Resource_ResourceAbstract
+{
+    public $_explicitType = 'My_View';
+
+    public function init()
+    {
+        // do some initialization...
+    }
+}
+]]></programlisting>
+
+        <para>
+            We can then bootstrap that resource or retrieve it by the name
+            "My_View":
+        </para>
+
+        <programlisting role="php"><![CDATA[
+$bootstrap->bootstrap('My_View');
+$view = $bootstrap->getResource('My_View');
+]]></programlisting>
+
+        <para>
+            Using these various naming approaches, you can override existing
+            resources, add your own, mix multiple resources to achieve complex
+            initialization, and more.
+        </para>
+    </sect3>
 </sect2>

+ 22 - 2
library/Zend/Application/Bootstrap/BootstrapAbstract.php

@@ -226,9 +226,29 @@ abstract class Zend_Application_Bootstrap_BootstrapAbstract
      */
     public function registerPluginResource($resource, $options = null)
     {
+        if (is_string($resource) && class_exists($resource)) {
+            $options = (array) $options;
+            $options['bootstrap'] = $this;
+            $resource = new $resource($options);
+        }
         if ($resource instanceof Zend_Application_Resource_Resource) {
-            $className  = get_class($resource);
-            $pluginName = strtolower(substr(strrchr($className, '_'), 1)); 
+            $resource->setBootstrap($this);
+
+            $vars = get_object_vars($resource);
+            if (isset($vars['_explicitType'])) {
+                $pluginName = strtolower($vars['_explicitType']);
+            } else  {
+                $className  = get_class($resource);
+                $pluginName = strtolower($className);
+                $loader     = $this->getPluginLoader();
+                foreach ($loader->getPaths() as $prefix => $paths) {
+                    if (0 === strpos($className, $prefix)) {
+                        $pluginName = substr($className, strlen($prefix));
+                        $pluginName = strtolower(trim($pluginName, '_'));
+                    }
+                }
+            }
+
             $this->_pluginResources[$pluginName] = $resource;
             return $this;
         }

+ 114 - 0
tests/Zend/Application/Bootstrap/BootstrapAbstractTest.php

@@ -35,6 +35,11 @@ require_once dirname(__FILE__) . '/../../../TestHelper.php';
 require_once 'Zend/Loader/Autoloader.php';
 
 /**
+ * Zend_Application_Resource_ResourceAbstract
+ */
+require_once 'Zend/Application/Resource/ResourceAbstract.php';
+
+/**
  * @category   Zend
  * @package    Zend_Application
  * @subpackage UnitTests
@@ -488,6 +493,115 @@ class Zend_Application_Bootstrap_BootstrapAbstractTest extends PHPUnit_Framework
         $resource = $bootstrap->getResource('baz');
         $this->assertEquals('Baz', $resource->baz);
     }
+
+    /**
+     * @group ZF-6543
+     */
+    public function testPassingPluginResourcesByFullClassNameWithMatchingPluginPathShouldRegisterAsShortName()
+    {
+        $this->application->setOptions(array(
+            'resources' => array(
+                'Zend_Application_Bootstrap_BootstrapAbstractTest_View' => array(),
+            ),
+            'pluginPaths' => array(
+                'Zend_Application_Bootstrap_BootstrapAbstractTest' => dirname(__FILE__),
+            ),
+        ));
+        $bootstrap = new Zend_Application_Bootstrap_Bootstrap($this->application);
+        $this->assertTrue($bootstrap->hasPluginResource('View'), var_export(array_keys($bootstrap->getPluginResources()), 1));
+    }
+
+    /**
+     * @group ZF-6543
+     */
+    public function testPassingFullViewClassNameNotMatchingARegisteredPrefixShouldRegisterAsTheClassName()
+    {
+        $this->application->setOptions(array(
+            'resources' => array(
+                'Zend_Application_Bootstrap_BootstrapAbstractTest_View' => array(),
+            ),
+        ));
+        $bootstrap = new Zend_Application_Bootstrap_Bootstrap($this->application);
+        $this->assertTrue($bootstrap->hasPluginResource('Zend_Application_Bootstrap_BootstrapAbstractTest_View'));
+    }
+
+    /**
+     * @group ZF-6543
+     */
+    public function testPassingFullViewClassNameNotMatchingARegisteredPrefixShouldReturnAppropriateResource()
+    {
+        $this->application->setOptions(array(
+            'resources' => array(
+                'Zend_Application_Bootstrap_BootstrapAbstractTest_View' => array(),
+            ),
+        ));
+        $bootstrap = new Zend_Application_Bootstrap_Bootstrap($this->application);
+        $bootstrap->bootstrap('Zend_Application_Bootstrap_BootstrapAbstractTest_View');
+        $resource = $bootstrap->getResource('Zend_Application_Bootstrap_BootstrapAbstractTest_View');
+        $this->assertTrue($resource instanceof Zend_Application_Bootstrap_BootstrapAbstractTest_View, var_export(array_keys($bootstrap->getPluginResources()), 1));
+    }
+
+    /**
+     * @group ZF-6543
+     */
+    public function testCanMixAndMatchPluginResourcesAndFullClassNames()
+    {
+        $this->application->setOptions(array(
+            'resources' => array(
+                'Zend_Application_Bootstrap_BootstrapAbstractTest_View' => array(),
+                'view' => array(),
+            ),
+        ));
+        $bootstrap = new Zend_Application_Bootstrap_Bootstrap($this->application);
+        $bootstrap->bootstrap('Zend_Application_Bootstrap_BootstrapAbstractTest_View');
+        $resource1 = $bootstrap->getResource('Zend_Application_Bootstrap_BootstrapAbstractTest_View');
+        $bootstrap->bootstrap('view');
+        $resource2 = $bootstrap->getResource('view');
+        $this->assertNotSame($resource1, $resource2);
+        $this->assertTrue($resource1 instanceof Zend_Application_Bootstrap_BootstrapAbstractTest_View, var_export(array_keys($bootstrap->getPluginResources()), 1));
+        $this->assertTrue($resource2 instanceof Zend_View);
+    }
+
+    /**
+     * @group ZF-6543
+     */
+    public function testPluginClassesDefiningExplicitTypeWillBeRegisteredWithThatValue()
+    {
+        $this->application->setOptions(array(
+            'resources' => array(
+                'Zend_Application_Bootstrap_BootstrapAbstractTest_Layout' => array(),
+                'layout' => array(),
+            ),
+        ));
+        $bootstrap = new Zend_Application_Bootstrap_Bootstrap($this->application);
+        $bootstrap->bootstrap('BootstrapAbstractTestLayout');
+        $resource1 = $bootstrap->getResource('BootstrapAbstractTestLayout');
+        $bootstrap->bootstrap('layout');
+        $resource2 = $bootstrap->getResource('layout');
+        $this->assertNotSame($resource1, $resource2);
+        $this->assertTrue($resource1 instanceof Zend_Application_Bootstrap_BootstrapAbstractTest_Layout, var_export(array_keys($bootstrap->getPluginResources()), 1));
+        $this->assertTrue($resource2 instanceof Zend_Layout);
+    }
+}
+
+class Zend_Application_Bootstrap_BootstrapAbstractTest_View
+    extends Zend_Application_Resource_ResourceAbstract
+{
+    public function init()
+    {
+        return $this;
+    }
+}
+
+class Zend_Application_Bootstrap_BootstrapAbstractTest_Layout
+    extends Zend_Application_Resource_ResourceAbstract
+{
+    public $_explicitType = 'BootstrapAbstractTestLayout';
+
+    public function init()
+    {
+        return $this;
+    }
 }
 
 if (PHPUnit_MAIN_METHOD == 'Zend_Application_Bootstrap_BootstrapAbstractTest::main') {