Przeglądaj źródła

Implementing ZF-9693 - patch contributed by Jean-Sebastien HEDDE

Allow using subclasses of Zend_Uri in the factory() method.
Includes unit tests and documentation update.


git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@22081 44c647ce-9c0f-0410-b52a-842ac1e357ba
shahar 15 lat temu
rodzic
commit
cfb98283a9

+ 39 - 3
documentation/manual/en/module_specs/Zend_Uri.xml

@@ -47,9 +47,10 @@ $uri = Zend_Uri::factory('http');
         <para>
             To create a new <acronym>URI</acronym> from scratch, pass only the scheme to
             <methodname>Zend_Uri::factory()</methodname><footnote><para>At the time of writing,
-            <classname>Zend_Uri</classname> only supports the <acronym>HTTP</acronym> and
-            <acronym>HTTPS</acronym> schemes.</para></footnote>. If an unsupported scheme is
-            passed, a <classname>Zend_Uri_Exception</classname> will be thrown.
+            <classname>Zend_Uri</classname> only provides built-in support for the <acronym>HTTP</acronym> 
+            and <acronym>HTTPS</acronym> schemes.</para></footnote>. If an unsupported scheme is
+            passed and no scheme-specific class is specified, a <classname>Zend_Uri_Exception</classname> 
+            will be thrown.
         </para>
 
         <para>
@@ -57,6 +58,41 @@ $uri = Zend_Uri::factory('http');
             <methodname>Zend_Uri::factory()</methodname> will return a subclass of itself that
             specializes in the scheme to be created.
         </para>
+        
+        <sect3>
+            <title>Creating a New Custom-Class URI</title>
+            
+            <para>
+                Starting from Zend Framework 1.10.5, you can specify a custom class to be 
+                used when creating the Zend_Uri instance, as a second parameter to the 
+                <methodname>Zend_Uri::factory()</methodname> method.  
+                This enables you to subclass Zend_Uri and create your own custom URI classes,
+                and instantiate new URI objects based on your own custom classes. 
+            </para>
+            
+            <para>
+                The 2nd parameter passed to <methodname>Zend_Uri::factory()</methodname> must
+                be a string with the name of a class extending <classname>Zend_Uri</classname>. 
+                The class must either be alredy-loaded, or loadable using <methodname>Zend_Loader::loadClass()</methodname> - 
+                that is, it must follow the Zend Framework class and file naming conventions, and 
+                must be in your include_path.   
+            </para>
+            
+            <example id="zend.uri.creation.custom.example-1">
+                <title>Creating a URI using a custom class</title>
+                
+                <programlisting language="php"><![CDATA[
+// Create a new 'ftp' URI based on a custom class
+$ftpUri = Zend_Uri::factory(
+    'ftp://user@ftp.example.com/path/file', 
+    'MyLibrary_Uri_Ftp'
+);
+
+// $ftpUri is an instance of MyLibrary_Uri_Ftp, which is a subclass of Zend_Uri 
+]]></programlisting>
+            </example>
+        </sect3>
+                
     </sect2>
 
     <sect2 id="zend.uri.manipulation">

+ 35 - 20
library/Zend/Uri.php

@@ -79,14 +79,16 @@ abstract class Zend_Uri
      * Create a new Zend_Uri object for a URI.  If building a new URI, then $uri should contain
      * only the scheme (http, ftp, etc).  Otherwise, supply $uri with the complete URI.
      *
-     * @param  string $uri The URI form which a Zend_Uri instance is created
+     * @param  string $uri       The URI form which a Zend_Uri instance is created
+     * @param  string $className The name of the class to use in order to manipulate URI
      * @throws Zend_Uri_Exception When an empty string was supplied for the scheme
      * @throws Zend_Uri_Exception When an illegal scheme is supplied
      * @throws Zend_Uri_Exception When the scheme is not supported
+     * @throws Zend_Uri_Exception When $className doesn't exist or doesn't implements Zend_Uri
      * @return Zend_Uri
      * @link   http://www.faqs.org/rfcs/rfc2396.html
      */
-    public static function factory($uri = 'http')
+    public static function factory($uri = 'http', $className = null)
     {
         // Separate the scheme from the scheme-specific parts
         $uri            = explode(':', $uri, 2);
@@ -104,31 +106,44 @@ abstract class Zend_Uri
             throw new Zend_Uri_Exception('Illegal scheme supplied, only alphanumeric characters are permitted');
         }
 
-        /**
-         * Create a new Zend_Uri object for the $uri. If a subclass of Zend_Uri exists for the
-         * scheme, return an instance of that class. Otherwise, a Zend_Uri_Exception is thrown.
-         */
-        switch ($scheme) {
-            case 'http':
-                // Break intentionally omitted
-            case 'https':
-                $className = 'Zend_Uri_Http';
-                break;
-
-            case 'mailto':
-                // TODO
-            default:
-                require_once 'Zend/Uri/Exception.php';
-                throw new Zend_Uri_Exception("Scheme \"$scheme\" is not supported");
-                break;
+        if ($className === null) {
+            /**
+             * Create a new Zend_Uri object for the $uri. If a subclass of Zend_Uri exists for the
+             * scheme, return an instance of that class. Otherwise, a Zend_Uri_Exception is thrown.
+             */
+            switch ($scheme) {
+                case 'http':
+                    // Break intentionally omitted
+                case 'https':
+                    $className = 'Zend_Uri_Http';
+                    break;
+
+                case 'mailto':
+                    // TODO
+                default:
+                    require_once 'Zend/Uri/Exception.php';
+                    throw new Zend_Uri_Exception("Scheme \"$scheme\" is not supported");
+                    break;
+            }
         }
 
         if (!class_exists($className)) {
             require_once 'Zend/Loader.php';
-            Zend_Loader::loadClass($className);
+            try {
+                Zend_Loader::loadClass($className);
+            } catch (Exception $e) {
+                require_once 'Zend/Uri/Exception.php';
+                throw new Zend_Uri_Exception("\"$className\" not found");
+            }
         }
+
         $schemeHandler = new $className($scheme, $schemeSpecific);
 
+        if (! $schemeHandler instanceof Zend_Uri) {
+            require_once 'Zend/Uri/Exception.php';
+            throw new Zend_Uri_Exception("\"$className\" is not an instance of Zend_Uri");
+        }
+
         return $schemeHandler;
     }
 

+ 30 - 2
tests/Zend/UriTest.php

@@ -157,12 +157,40 @@ class Zend_UriTest extends PHPUnit_Framework_TestCase
      *
      * @param string $uri
      */
-    protected function _testValidUri($uri)
+    protected function _testValidUri($uri, $className = null)
     {
-        $uri = Zend_Uri::factory($uri);
+        $uri = Zend_Uri::factory($uri, $className);
         $this->assertTrue($uri instanceof Zend_Uri, 'Zend_Uri object not returned.');
+        return $uri;
     }
 
+    public function testFactoryWithUnExistingClassThrowException()
+    {
+        $this->setExpectedException('Zend_Uri_Exception', '"This_Is_An_Unknown_Class" not found');
+        Zend_Uri::factory('http://example.net', 'This_Is_An_Unknown_Class');
+    }
+
+    public function testFactoryWithExistingClassButNotImplementingZendUriThrowException()
+    {
+        $this->setExpectedException('Zend_Uri_Exception', '"Fake_Zend_Uri" is not an instance of Zend_Uri');
+        Zend_Uri::factory('http://example.net', 'Fake_Zend_Uri');
+    }
+
+    public function testFactoryWithExistingClassReturnObject()
+    {
+        $uri = $this->_testValidUri('http://example.net', 'Zend_Uri_Mock');
+        $this->assertTrue($uri instanceof Zend_Uri_Mock, 'Zend_Uri_Mock object not returned.');
+    }
+
+}
+class Zend_Uri_Mock extends Zend_Uri
+{
+    protected function __construct($scheme, $schemeSpecific = '') { }
+    public function getUri() { }
+    public function valid() { }
+}
+class Fake_Zend_Uri
+{
 }
 
 // Call Zend_UriTest::main() if this source file is executed directly.