Browse Source

Promoted RESTful route/PUT support to trunk; fixed issue in TestConfiguration

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

+ 45 - 0
documentation/manual/en/module_specs/Zend_Controller-Plugins-PutHandler.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect3 id="zend.controller.plugins.standard.puthandler">
+    <title>Zend_Controller_Plugin_PutHandler</title>
+
+    <para>
+        <classname>Zend_Controller_Plugin_PutHandler</classname> provides a drop-in
+        plugin for marshalling PUT request bodies into request parameters, just
+        like POST request bodies. It will inspect the request and, if PUT, will 
+        use parse_str to to parse the raw PUT body into an array of params 
+        which is then set on the request. E.g.,
+    </para>
+
+    <programlisting><![CDATA[
+PUT /notes/5.xml HTTP/1.1
+    
+title=Hello&body=World]]>
+    </programlisting>
+
+    <para>
+        To receive the 'title' and 'body' params as regular request params, 
+        register the plugin:
+    </para>
+    
+    <programlisting language="php"><![CDATA[
+$front = Zend_Controller_Front::getInstance();
+$front->registerPlugin(new Zend_Controller_Plugin_PutHandler());]]>
+    </programlisting>
+            
+    <para>
+        Then you can access the PUT body params by name from the request inside
+        your controller:
+    </para>
+    
+    <programlisting language="php"><![CDATA[
+    ...
+    public function putAction()
+    {
+        $title = $this->getRequest()->getParam('title'); // $title = "Hello"
+        $body = $this->getRequest()->getParam('body'); // $body = "World"
+    }
+    ...]]>
+    </programlisting>
+
+</sect3>

+ 1 - 0
documentation/manual/en/module_specs/Zend_Controller-Plugins.xml

@@ -233,6 +233,7 @@ $front->dispatch();
 
         <xi:include href="Zend_Controller-Plugins-ActionStack.xml" />
         <xi:include href="Zend_Controller-Plugins-ErrorHandler.xml" />
+        <xi:include href="Zend_Controller-Plugins-PutHandler.xml" />
     </sect2>
 </sect1>
 <!--

+ 156 - 0
documentation/manual/en/module_specs/Zend_Controller-Router-Route-Rest.xml

@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect3 id="zend.controller.router.routes.rest">
+    <title>Zend_Rest_Route</title>
+
+    <para>
+        The <classname>Zend_Rest</classname> component contains a RESTful route
+        for <classname>Zend_Controller_Router_Rewrite</classname>.  This route
+        offers a standardized routing scheme that routes requests by translating
+        the HTTP method and the URI to a module, controller, and action.  The
+        table below provides an overview of how request methods and URI's are
+        routed.
+    </para>
+    
+    <table frame="all">
+        <title>Zend_Rest_Route Behavior</title>
+
+        <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+            <colspec colname='method' />
+            <colspec colname='URI' />
+            <colspec colname='route' />
+            <thead>
+                <row>
+                    <entry>Method</entry>
+                    <entry>URI</entry>
+                    <entry>Module_Controller::action</entry>
+                </row>
+            </thead>
+            <tbody>
+                <row>
+                    <entry>GET</entry>
+                    <entry>/product/ratings/</entry>
+                    <entry>Product_RatingsController::indexAction()</entry>
+                </row>
+                <row>
+                    <entry>GET</entry>
+                    <entry>/product/ratings/:id</entry>
+                    <entry>Product_RatingsController::getAction()</entry>
+                </row>
+                <row>
+                    <entry>POST</entry>
+                    <entry>/product/ratings</entry>
+                    <entry>Product_RatingsController::postAction()</entry>
+                </row>
+                <row>
+                    <entry>PUT</entry>
+                    <entry>/product/ratings/:id</entry>
+                    <entry>Product_RatingsController::putAction()</entry>
+                </row>
+                <row>
+                    <entry>DELETE</entry>
+                    <entry>/product/ratings/:id</entry>
+                    <entry>Product_RatingsController::deleteAction()</entry>
+                </row>
+                <row>
+                    <entry>POST</entry>
+                    <entry><literallayout>/product/ratings/:id?_method="PUT"</literallayout></entry>
+                    <entry>Product_RatingsController::putAction()</entry>
+                </row>
+                <row>
+                    <entry>POST</entry>
+                    <entry><literallayout>/product/ratings/:id?_method="DELETE"</literallayout></entry>
+                    <entry>Product_RatingsController::deleteAction()</entry>
+                </row>
+            </tbody>
+        </tgroup>
+    </table>
+
+    <para>
+        To enable <classname>Zend_Rest_Route</classname> for an entire
+        application, construct it with no config params and add it as the
+        default route on the front controller:
+    </para> 
+
+    <programlisting language="php"><![CDATA[
+$front     = Zend_Controller_Front::getInstance();
+$restRoute = new Zend_Rest_Route($front);
+$front->getRouter()->addRoute('default', $restRoute);
+]]></programlisting>
+
+    <note>
+        <para>
+            If <classname>Zend_Rest_Route</classname> cannot match a valid
+            module, controller, or action, it will return false and the router
+            will attempt to match using the next route in the router.
+        </para>
+    </note>
+
+    <para>
+        To enable <classname>Zend_Rest_Route</classname> for specific modules,
+        construct it with an array of module names as the 3rd constructor
+        argument:
+    </para> 
+
+    <programlisting language="php"><![CDATA[
+$front     = Zend_Controller_Front::getInstance();
+$restRoute = new Zend_Rest_Route($front, array(), array('product'));
+$front->getRouter()->addRoute('rest', $restRoute);
+]]></programlisting>
+
+    <para>
+        To enable <classname>Zend_Rest_Route</classname> for specific
+        controllers, add an array of controller names as the value of each
+        module array element.
+    </para> 
+
+    <programlisting language="php"><![CDATA[
+$front     = Zend_Controller_Front::getInstance();
+$restRoute = new Zend_Rest_Route($front, array(), array(
+    'product' => array('ratings')
+));
+$front->getRouter()->addRoute('rest', $restRoute);
+]]></programlisting>
+
+    <sect4 id="zend.rest.controller">
+        <title>Zend_Rest_Controller</title>
+
+        <para>
+            To help guide development of Controllers for use with 
+            <classname>Zend_Rest_Route</classname>, extend your Controllers from
+            <classname>Zend_Rest_Controller</classname>.
+            <classname>Zend_Rest_Controller</classname> defines the 5 most-commonly
+            needed operations for RESTful resources in the form of abstract action
+            methods.
+        </para>
+    
+        <itemizedlist>
+            <listitem>
+                <emphasis><methodname>indexAction</methodname></emphasis> - 
+                Should retrieve an index of resources and assign it to view.
+            </listitem>
+            <listitem>
+                <emphasis><methodname>getAction</methodname></emphasis> - 
+                Should retrieve a single resource identified by URI and assign
+                it to view.
+            </listitem>
+            <listitem>
+                <emphasis><methodname>postAction</methodname></emphasis> - 
+                Should accept a new single resource and persist its state.
+            </listitem>
+            <listitem>
+                <emphasis><methodname>putAction</methodname></emphasis> - 
+                Should accept a single resource idenitifed by URI and persist
+                its state.
+            </listitem>
+            <listitem>
+                <emphasis><methodname>deleteAction</methodname></emphasis> - 
+                Should delete a single resource identified by URI.
+            </listitem>
+        </itemizedlist>
+
+    </sect4>
+</sect3>
+<!--
+vim:se ts=4 sw=4 et:
+-->

+ 1 - 0
documentation/manual/en/module_specs/Zend_Controller-Router.xml

@@ -393,6 +393,7 @@ $router->setGlobalParam('lang', 'en');
         <xi:include href="Zend_Controller-Router-Route-Regex.xml" />
         <xi:include href="Zend_Controller-Router-Route-Hostname.xml" />
         <xi:include href="Zend_Controller-Router-Route-Chain.xml" />
+        <xi:include href="Zend_Controller-Router-Route-Rest.xml" />
     </sect2>
 
     <sect2 id="zend.controller.router.add-config">

+ 60 - 0
library/Zend/Controller/Plugin/PutHandler.php

@@ -0,0 +1,60 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Controller
+ * @subpackage Zend_Controller_Plugin
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Controller_Plugin_Abstract
+ */
+require_once 'Zend/Controller/Plugin/Abstract.php';
+
+/**
+ * @see Zend_Controller_Request_Http
+ */
+require_once 'Zend/Controller/Request/Http.php';
+
+/**
+ * Plugin to digest PUT request body and make params available just like POST
+ *
+ * @package    Zend_Controller
+ * @subpackage Zend_Controller_Plugin
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Controller_Plugin_PutHandler extends Zend_Controller_Plugin_Abstract
+{
+    /**
+     * Before dispatching, digest PUT request body and set params
+     *
+     * @param Zend_Controller_Request_Abstract $request
+     */
+    public function preDispatch(Zend_Controller_Request_Abstract $request)
+    {
+        if (!$request instanceof Zend_Controller_Request_Http) {
+            return;
+        }
+
+        if ($this->_request->isPut()) {
+            $putParams = array();
+            parse_str($this->_request->getRawBody(), $putParams);
+            $request->setParams($putParams);
+        }
+    }
+}

+ 68 - 0
library/Zend/Rest/Controller.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @package    Zend_Rest
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/** Zend_Controller_Action */
+require_once 'Zend/Controller/Action.php';
+
+/**
+ * An abstract class to guide implementation of action controllers for use with
+ * Zend_Rest_Route.
+ * 
+ * @package Zend_Rest
+ * @see Zend_Rest_Route
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License 
+ */
+abstract class Zend_Rest_Controller extends Zend_Controller_Action
+{
+    /**
+     * The index action handles index/list requests; it should respond with a
+     * list of the requested resources.
+     */  
+    abstract public function indexAction();
+
+    /**
+     * The get action handles GET requests and receives an 'id' parameter; it 
+     * should respond with the server resource state of the resource identified
+     * by the 'id' value.
+     */  
+    abstract public function getAction();
+    
+    /**
+     * The post action handles POST requests; it should accept and digest a
+     * POSTed resource representation and persist the resource state.
+     */  
+    abstract public function postAction();
+    
+    /**
+     * The put action handles PUT requests and receives an 'id' parameter; it 
+     * should update the server resource state of the resource identified by 
+     * the 'id' value.
+     */  
+    abstract public function putAction();
+    
+    /**
+     * The delete action handles DELETE requests and receives an 'id' 
+     * parameter; it should update the server resource state of the resource
+     * identified by the 'id' value.
+     */  
+    abstract public function deleteAction();
+    
+}

+ 346 - 0
library/Zend/Rest/Route.php

@@ -0,0 +1,346 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @package    Zend_Rest
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/** 
+ * @see Zend_Controller_Router_Route_Interface 
+ */
+require_once 'Zend/Controller/Router/Route/Interface.php';
+
+/** 
+ * @see Zend_Controller_Router_Route_Module
+ */
+require_once 'Zend/Controller/Router/Route/Module.php';
+
+/** 
+ * @see Zend_Controller_Dispatcher_Interface
+ */
+require_once 'Zend/Controller/Dispatcher/Interface.php';
+
+/** 
+ * @see Zend_Controller_Request_Abstract
+ */
+require_once 'Zend/Controller/Request/Abstract.php';
+
+/**
+ * Rest Route
+ *
+ * Request-aware route for RESTful modular routing
+ *
+ * @package    Zend_Rest
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Rest_Route extends Zend_Controller_Router_Route_Module
+{
+    /**
+     * Specific Modules to receive RESTful routes
+     * @var array
+     */ 
+    protected $_restfulModules = null; 
+ 
+    /**
+     * Specific Modules=>Controllers to receive RESTful routes
+     * @var array
+     */ 
+    protected $_restfulControllers = null; 
+     
+    /**
+     * Constructor
+     *
+     * @param array $defaults Defaults for map variables with keys as variable names
+     * @param Zend_Controller_Front $front Front Controller object
+     */ 
+    public function __construct(Zend_Controller_Front $front, 
+        array $defaults = array(),  
+        array $responders = array()) 
+    { 
+        $this->_defaults = $defaults; 
+ 
+        if($responders) 
+            $this->_parseResponders($responders); 
+ 
+        if (isset($front)) { 
+            $this->_request = $front->getRequest(); 
+            $this->_dispatcher = $front->getDispatcher(); 
+        } 
+    } 
+ 
+    /**
+     * Matches a user submitted request. Assigns and returns an array of variables
+     * on a successful match.
+     *
+     * If a request object is registered, it uses its setModuleName(),
+     * setControllerName(), and setActionName() accessors to set those values.
+     * Always returns the values as an array.
+     *
+     * @param Zend_Controller_Request_Http $request Request used to match against this routing ruleset
+     * @return array An array of assigned values or a false on a mismatch
+     */  
+    public function match($request) 
+    {  
+        $this->_setRequestKeys(); 
+ 
+        $path = $request->getPathInfo(); 
+        $values = array();  
+        $params = array();  
+        $path   = trim($path, self::URI_DELIMITER);  
+  
+        if ($path != '') {  
+              
+            $path = explode(self::URI_DELIMITER, $path);  
+             
+            // Determine Module 
+            $moduleName = $this->_defaults[$this->_moduleKey]; 
+            if ($this->_dispatcher && $this->_dispatcher->isValidModule($path[0])) { 
+                $moduleName = $path[0]; 
+                if ($this->_checkRestfulModule($moduleName)) { 
+                    $values[$this->_moduleKey] = array_shift($path);  
+                    $this->_moduleValid = true;                          
+                } 
+            }  
+              
+            // Determine Controller 
+            $controllerName = $this->_defaults[$this->_controllerKey]; 
+            if (count($path) && !empty($path[0])) { 
+                if ($this->_checkRestfulController($moduleName, $path[0])) { 
+                    $controllerName = $path[0]; 
+                    $values[$this->_controllerKey] = array_shift($path); 
+                    $values[$this->_actionKey] = 'get'; 
+                } else { 
+                    // If Controller in URI is not found to be a RESTful 
+                    // Controller, return false to fall back to other routes 
+                    return false; 
+                } 
+            } 
+            
+            //Store path count for method mapping
+            $pathElementCount = count($path);
+            
+            // Check for leading "special get" URI's 
+            $specialGetTarget = false;
+            if ($pathElementCount && array_search($path[0], array('index', 'new')) > -1) { 
+                $specialGetTarget = array_shift($path);
+            } elseif ($pathElementCount == 1) {
+                 $params['id'] = array_shift($path);
+            } elseif ($pathElementCount == 0 || $pathElementCount > 1) {
+                $specialGetTarget = 'list';
+            }
+ 
+            // Digest URI params 
+            if ($numSegs = count($path)) {  
+                for ($i = 0; $i < $numSegs; $i = $i + 2) {  
+                    $key = urldecode($path[$i]);  
+                    $val = isset($path[$i + 1]) ? urldecode($path[$i + 1]) : null;  
+                    $params[$key] = $val;  
+                }  
+            } 
+             
+            // Check for trailing "special get" URI 
+            if (array_key_exists('edit', $params)) 
+                $specialGetTarget = 'edit'; 
+ 
+            // Determine Action 
+            $requestMethod = strtolower($request->getMethod()); 
+            if ($requestMethod != 'get') { 
+                if ($request->getParam('_method')) { 
+                    $values[$this->_actionKey] = strtolower($request->getParam('_method')); 
+                } elseif ( $this->_request->getHeader('X-HTTP-Method-Override') ) {
+                    $values[$this->_actionKey] = strtolower($this->_request->getHeader('X-HTTP-Method-Override'));
+                } else { 
+                    $values[$this->_actionKey] = $requestMethod; 
+                }
+
+                //Map PUT and POST to actual create/update actions
+                //based on parameter count (posting to resource or collection)
+                switch( $values[$this->_actionKey] ){
+                    case 'post':
+                        if ($pathElementCount > 0) {
+                            $values[$this->_actionKey] = 'put';
+                        } else {
+                            $values[$this->_actionKey] = 'post';
+                        }
+                        break;
+                    case 'put':
+                        $values[$this->_actionKey] = 'put';
+                        break;
+                }
+                
+            } elseif ($specialGetTarget) {  
+                $values[$this->_actionKey] = $specialGetTarget; 
+            } 
+              
+        }  
+        $this->_values = $values + $params;
+         
+        return $this->_values + $this->_defaults;  
+    } 
+  
+    /**
+     * Assembles user submitted parameters forming a URL path defined by this route
+     *
+     * @param array $data An array of variable and value pairs used as parameters
+     * @param bool $reset Weither to reset the current params
+     * @return string Route path with user submitted parameters
+     */  
+    public function assemble($data = array(), $reset = false, $encode = true)  
+    {  
+        if (!$this->_keysSet) {  
+            $this->_setRequestKeys();  
+        }  
+  
+        $params = (!$reset) ? $this->_values : array();  
+  
+        foreach ($data as $key => $value) {  
+            if ($value !== null) {  
+                $params[$key] = $value;  
+            } elseif (isset($params[$key])) {  
+                unset($params[$key]);  
+            }  
+        }  
+  
+        $params += $this->_defaults;  
+  
+        $url = '';  
+  
+        if ($this->_moduleValid || array_key_exists($this->_moduleKey, $data)) {  
+            if ($params[$this->_moduleKey] != $this->_defaults[$this->_moduleKey]) {  
+                $module = $params[$this->_moduleKey];  
+            }  
+        }  
+        unset($params[$this->_moduleKey]);  
+  
+        $controller = $params[$this->_controllerKey];  
+        unset($params[$this->_controllerKey]);
+
+        unset($params[$this->_actionKey]);
+        
+        if (isset($params['index']) && $params['index']) {
+            unset($params['index']);
+            $url .= '/index';
+            foreach ($params as $key => $value) {  
+                $url .= '/' . $key;  
+                $url .= '/' . $value;  
+            }
+        } else {
+            if (isset($params['id']))
+                $url .= '/' . $params['id'];        	
+        }
+  
+        if (!empty($url) || $controller !== $this->_defaults[$this->_controllerKey]) {  
+            $url = '/' . $controller . $url;  
+        }  
+  
+        if (isset($module)) {  
+            $url = '/' . $module . $url;  
+        }  
+  
+        return ltrim($url, self::URI_DELIMITER);  
+    } 
+     
+    /**
+     * Tells Rewrite Router which version this Route is
+     *
+     * @return int Route "version"
+     */ 
+    public function getVersion() 
+    { 
+        return 2; 
+    } 
+
+    /**
+     * Parses the responders array sent to constructor to know
+     * which modules and/or controllers are RESTful
+     *
+     * @param array $responders
+     */
+    private function _parseResponders($responders) 
+    { 
+        $modulesOnly = true; 
+        foreach ($responders as $responder) { 
+            if(is_array($responder)) 
+                $modulesOnly = false; 
+        } 
+        if ($modulesOnly) { 
+            $this->_restfulModules = $responders; 
+        } else { 
+            $this->_restfulControllers = $responders; 
+        } 
+    } 
+
+    /**
+     * Determine if a specified module supports RESTful routing
+     *
+     * @param string $moduleName
+     * @return bool
+     */
+    private function _checkRestfulModule($moduleName) 
+    { 
+        if ($this->_allRestful()) 
+            return true; 
+        if ($this->_fullRestfulModule($moduleName)) 
+            return true; 
+        if ($this->_restfulControllers && array_key_exists($moduleName, $this->_restfulControllers)) 
+            return true; 
+        return false; 
+    } 
+
+    /**
+     * Determine if a specified module + controller combination supports
+     * RESTful routing
+     *
+     * @param string $moduleName
+     * @param string $controllerName
+     * @return bool
+     */
+    private function _checkRestfulController($moduleName, $controllerName) 
+    { 
+        if ($this->_allRestful()) 
+            return true; 
+        if ($this->_fullRestfulModule($moduleName)) 
+            return true; 
+        if ($this->_checkRestfulModule($moduleName) 
+            && $this->_restfulControllers 
+            && array_search($controllerName, $this->_restfulControllers[$moduleName]) !== false) 
+            return true; 
+        return false; 
+    } 
+
+    /**
+     * Determines if RESTful routing applies to the entire app
+     *
+     * @return bool
+     */
+    private function _allRestful() 
+    { 
+        return (!$this->_restfulModules && !$this->_restfulControllers); 
+    } 
+
+    /**
+     * Determines if RESTful routing applies to an entire module
+     *
+     * @param string $moduleName
+     * @return bool
+     */
+    private function _fullRestfulModule($moduleName) 
+    { 
+        return ($this->_restfulModules && array_search($moduleName, $this->_restfulModules) !== false); 
+    } 
+ 
+} 

+ 1 - 1
tests/TestConfiguration.php.dist

@@ -463,7 +463,7 @@ define('TESTS_ZEND_MAIL_SMTP_AUTH', false);
  */
 define('TESTS_ZEND_QUEUE_APACHEMQ_HOST', false);
 define('TESTS_ZEND_QUEUE_APACHEMQ_PORT', false);
-define('TESTS_ZEND_QUEUE_DB', false)
+define('TESTS_ZEND_QUEUE_DB', false);
 define('TESTS_ZEND_QUEUE_MEMCACHEQ_SCHEME', false);
 define('TESTS_ZEND_QUEUE_MEMCACHEQ_HOST', false);
 define('TESTS_ZEND_QUEUE_MEMCACHEQ_PORT', false);

+ 2 - 0
tests/Zend/Controller/AllTests.php

@@ -36,6 +36,7 @@ require_once 'FrontTest.php';
 require_once 'Plugin/ActionStackTest.php';
 require_once 'Plugin/BrokerTest.php';
 require_once 'Plugin/ErrorHandlerTest.php';
+require_once 'Plugin/PutHandlerTest.php';
 require_once 'Request/Apache404Test.php';
 require_once 'Request/HttpTest.php';
 require_once 'Request/HttpTestCaseTest.php';
@@ -76,6 +77,7 @@ class Zend_Controller_AllTests
         $suite->addTestSuite('Zend_Controller_Plugin_ActionStackTest');
         $suite->addTestSuite('Zend_Controller_Plugin_BrokerTest');
         $suite->addTestSuite('Zend_Controller_Plugin_ErrorHandlerTest');
+        $suite->addTestSuite('Zend_Controller_Plugin_PutHandlerTest');
         $suite->addTestSuite('Zend_Controller_Request_Apache404Test');
         $suite->addTestSuite('Zend_Controller_Request_HttpTest');
         $suite->addTestSuite('Zend_Controller_Request_HttpTestCaseTest');

+ 73 - 0
tests/Zend/Controller/Plugin/PutHandlerTest.php

@@ -0,0 +1,73 @@
+<?php
+// Call Zend_Controller_Plugin_PutHandlerTest::main() if this source file is executed directly.
+if (!defined("PHPUnit_MAIN_METHOD")) {
+    define("PHPUnit_MAIN_METHOD", "Zend_Controller_Plugin_PutHandlerTest::main");
+}
+
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+require_once 'Zend/Controller/Plugin/PutHandler.php';
+require_once 'Zend/Controller/Request/HttpTestCase.php';
+require_once 'Zend/Controller/Front.php';
+
+/**
+ * Test class for Zend_Controller_Plugin_PutHandler.
+ */
+class Zend_Controller_Plugin_PutHandlerTest extends PHPUnit_Framework_TestCase 
+{
+    /**
+     * Request object
+     * @var Zend_Controller_Request_Http
+     */
+    public $request;
+
+    /**
+     * Error handler plugin
+     * @var Zend_Controller_Plugin_PutHandler
+     */
+    public $plugin;
+
+    /**
+     * Runs the test methods of this class.
+     *
+     * @access public
+     * @static
+     */
+    public static function main() 
+    {
+        require_once "PHPUnit/TextUI/TestRunner.php";
+
+        $suite  = new PHPUnit_Framework_TestSuite("Zend_Controller_Plugin_PutHandlerTest");
+        $result = PHPUnit_TextUI_TestRunner::run($suite);
+    }
+
+    /**
+     * Sets up the fixture, for example, open a network connection.
+     * This method is called before a test is executed.
+     *
+     * @access protected
+     */
+    protected function setUp() 
+    {
+        Zend_Controller_Front::getInstance()->resetInstance();
+        $this->request  = new Zend_Controller_Request_HttpTestCase();
+        $this->plugin   = new Zend_Controller_Plugin_PutHandler();
+
+        $this->plugin->setRequest($this->request);
+    }
+
+    public function test_marshall_PUT_body_as_params() 
+    {
+        $this->request->setMethod('PUT');
+        $this->request->setRawBody('param1=value1&param2=value2');
+        $this->plugin->preDispatch($this->request);
+
+        $this->assertEquals('value1', $this->request->getParam('param1'));
+        $this->assertEquals('value2', $this->request->getParam('param2'));
+    }
+}
+
+// Call Zend_Controller_Plugin_PutHandlerTest::main() if this source file is executed directly.
+if (PHPUnit_MAIN_METHOD == "Zend_Controller_Plugin_PutHandlerTest::main") {
+    Zend_Controller_Plugin_PutHandlerTest::main();
+}
+

+ 5 - 5
tests/Zend/Rest/AllTests.php

@@ -1,14 +1,12 @@
 <?php
 if (!defined('PHPUnit_MAIN_METHOD')) {
     define('PHPUnit_MAIN_METHOD', 'Zend_Rest_AllTests::main');
-
-    set_include_path(dirname(dirname(dirname(dirname(__FILE__)))) . DIRECTORY_SEPARATOR . 'library' . PATH_SEPARATOR
-                 . get_include_path());
 }
 
-require_once 'PHPUnit/Framework/TestSuite.php';
-require_once 'PHPUnit/TextUI/TestRunner.php';
+require_once dirname(__FILE__) . '/../../TestHelper.php';
 
+require_once 'Zend/Rest/ControllerTest.php';
+require_once 'Zend/Rest/RouteTest.php';
 require_once 'Zend/Rest/ServerTest.php';
 require_once 'Zend/Rest/ClientTest.php';
 require_once 'Zend/Rest/ResultTest.php';
@@ -24,6 +22,8 @@ class Zend_Rest_AllTests
     {
         $suite = new PHPUnit_Framework_TestSuite('Zend Framework - Zend_Rest');
 
+        $suite->addTestSuite('Zend_Rest_ControllerTest');
+        $suite->addTestSuite('Zend_Rest_RouteTest');
         $suite->addTestSuite('Zend_Rest_ServerTest');
         $suite->addTestSuite('Zend_Rest_ClientTest');
         $suite->addTestSuite('Zend_Rest_ResultTest');

+ 125 - 0
tests/Zend/Rest/ControllerTest.php

@@ -0,0 +1,125 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @package    Zend_Rest
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/** Test helper */
+require_once dirname(__FILE__) . '/../../TestHelper.php';
+
+require_once "PHPUnit/Framework/TestCase.php";
+require_once "PHPUnit/Framework/TestSuite.php";
+/**
+ * @category   Zend
+ * @package    Zend_Rest
+ * @subpackage UnitTests
+ */
+
+/** Zend_Rest_Controller */
+require_once 'Zend/Rest/Controller.php';
+
+/** Zend_Controller_Request_HttpTestCase */
+require_once 'Zend/Controller/Request/HttpTestCase.php';
+
+/** Zend_Controller_Response_HttpTestCase */
+require_once 'Zend/Controller/Response/HttpTestCase.php';
+
+// Call Zend_Rest_ControllerTest::main() if this source file is executed directly.
+if (!defined("PHPUnit_MAIN_METHOD")) {
+    define("PHPUnit_MAIN_METHOD", "Zend_Rest_ControllerTest::main");
+}
+
+class Zend_Rest_TestController extends Zend_Rest_Controller
+{
+    public $testValue = '';
+    public function __construct(Zend_Controller_Request_Abstract $request,
+                                Zend_Controller_Response_Abstract $response,
+                                array $invokeArgs = array())
+    {
+        $this->testValue = '';
+    }
+    public function indexAction()
+    {
+        $this->testValue = 'indexAction';
+    }
+    public function getAction()
+    {
+        $this->testValue = 'getAction';
+    }
+    public function postAction()
+    {
+        $this->testValue = 'postAction';
+    }
+    public function putAction()
+    {
+        $this->testValue = 'putAction';
+    }
+    public function deleteAction()
+    {
+        $this->testValue = 'deleteAction';
+    }
+    
+}
+/**
+ * @category   Zend
+ * @package    Zend_Rest
+ * @subpackage UnitTests
+ */
+class Zend_Rest_ControllerTest extends PHPUnit_Framework_TestCase
+{
+    protected $_testController;
+
+    /**
+     * Runs the test methods of this class.
+     *
+     * @access public
+     * @static
+     */
+    public static function main()
+    {
+        require_once "PHPUnit/TextUI/TestRunner.php";
+
+        $suite  = new PHPUnit_Framework_TestSuite("Zend_Rest_ControllerTest");
+        $result = PHPUnit_TextUI_TestRunner::run($suite);
+    }
+
+    public function setUp()
+    {
+        $request = new Zend_Controller_Request_HttpTestCase();
+        $response = new Zend_Controller_Response_HttpTestCase();
+        $this->_testController = new Zend_Rest_TestController($request, $response);
+    }
+
+    public function test_action_methods()
+    {
+        $this->_testController->indexAction();
+        $this->assertEquals('indexAction', $this->_testController->testValue);
+        $this->_testController->getAction();
+        $this->assertEquals('getAction', $this->_testController->testValue);
+        $this->_testController->postAction();
+        $this->assertEquals('postAction', $this->_testController->testValue);
+        $this->_testController->putAction();
+        $this->assertEquals('putAction', $this->_testController->testValue);
+        $this->_testController->deleteAction();
+        $this->assertEquals('deleteAction', $this->_testController->testValue);
+    }
+}
+
+// Call Zend_Rest_ControllerTest::main() if this source file is executed directly.
+if (PHPUnit_MAIN_METHOD == "Zend_Rest_ControllerTest::main") {
+    Zend_Rest_ControllerTest::main();
+}

+ 433 - 0
tests/Zend/Rest/RouteTest.php

@@ -0,0 +1,433 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @package    Zend_Rest
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/** Test helper */
+require_once dirname(__FILE__) . '/../../TestHelper.php';
+
+require_once "PHPUnit/Framework/TestCase.php";
+require_once "PHPUnit/Framework/TestSuite.php";
+/**
+ * @category   Zend
+ * @package    Zend_Rest
+ * @subpackage UnitTests
+ */
+
+/** Zend_Rest_Route */
+require_once 'Zend/Rest/Route.php';
+
+/** Zend_Controller_Front */
+require_once 'Zend/Controller/Front.php';
+
+/** Zend_Controller_Request_HttpTestCase */
+require_once 'Zend/Controller/Request/HttpTestCase.php';
+
+// Call Zend_Rest_RouteTest::main() if this source file is executed directly.
+if (!defined("PHPUnit_MAIN_METHOD")) {
+    define("PHPUnit_MAIN_METHOD", "Zend_Rest_RouteTest::main");
+}
+
+/**
+ * @category   Zend
+ * @package    Zend_Rest
+ * @subpackage UnitTests
+ */
+class Zend_Rest_RouteTest extends PHPUnit_Framework_TestCase
+{
+
+    protected $_front;
+    protected $_request;
+    protected $_dispatcher;
+
+    /**
+     * Runs the test methods of this class.
+     *
+     * @access public
+     * @static
+     */
+    public static function main()
+    {
+        require_once "PHPUnit/TextUI/TestRunner.php";
+
+        $suite  = new PHPUnit_Framework_TestSuite("Zend_Rest_RouteTest");
+        $result = PHPUnit_TextUI_TestRunner::run($suite);
+    }
+
+    public function setUp()
+    {
+        $this->_front = Zend_Controller_Front::getInstance();
+        $this->_front->resetInstance();
+        $this->_front->setParam('noErrorHandler', true)
+        ->setParam('noViewRenderer', true);
+
+        $this->_dispatcher = $this->_front->getDispatcher();
+
+        $this->_dispatcher->setControllerDirectory(array(
+            'default' => dirname(__FILE__) . DIRECTORY_SEPARATOR . 
+                '..' . DIRECTORY_SEPARATOR . 
+                'Controller' . DIRECTORY_SEPARATOR . 
+                '_files',
+            'mod'     => dirname(__FILE__) . DIRECTORY_SEPARATOR . 
+                '..' . DIRECTORY_SEPARATOR . 
+                'Controller' . DIRECTORY_SEPARATOR . 
+                '_files' . DIRECTORY_SEPARATOR . 
+                'Admin',
+        ));
+    }
+
+    public function test_getVersion()
+    {
+        $route = new Zend_Rest_Route($this->_front);
+        $this->assertEquals(2, $route->getVersion());
+    }
+
+    public function test_RESTfulApp_defaults()
+    {
+        $request = $this->_buildRequest('GET', '/');
+        $values = $this->_invokeRouteMatch($request);
+
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('default', $values['module']);
+        $this->assertEquals('index', $values['controller']);
+        $this->assertEquals('index', $values['action']);
+    }
+
+    public function test_RESTfulApp_GET_user_index()
+    {
+        $request = $this->_buildRequest('GET', '/user/index');
+        $values = $this->_invokeRouteMatch($request);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('default', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('index', $values['action']);
+    }
+
+    public function test_RESTfulApp_GET_user_index_withParams()
+    {
+        $request = $this->_buildRequest('GET', '/user/index/changedSince/123456789/status/active');
+        $values = $this->_invokeRouteMatch($request);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('default', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('index', $values['action']);
+        $this->assertEquals(123456789, $values['changedSince']);
+        $this->assertEquals('active', $values['status']);
+    }
+
+    public function test_RESTfulApp_GET_project_byIdentifier()
+    {
+        $request = $this->_buildRequest('GET', '/project/zendframework');
+        $values = $this->_invokeRouteMatch($request);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('default', $values['module']);
+        $this->assertEquals('project', $values['controller']);
+        $this->assertEquals('get', $values['action']);
+        $this->assertEquals('zendframework', $values['id']);
+    }
+
+    public function test_RESTfulApp_PUT_user_byIdentifier()
+    {
+        $request = $this->_buildRequest('PUT', '/mod/user/lcrouch');
+        $values = $this->_invokeRouteMatch($request);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('put', $values['action']);
+        $this->assertEquals('lcrouch', $values['id']);
+    }
+
+    public function test_RESTfulApp_POST_user()
+    {
+        $request = $this->_buildRequest('POST', '/mod/user');
+        $values = $this->_invokeRouteMatch($request);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('post', $values['action']);
+    }
+
+    public function test_RESTfulApp_DELETE_user_byIdentifier()
+    {
+        $request = $this->_buildRequest('DELETE', '/mod/user/lcrouch');
+        $values = $this->_invokeRouteMatch($request);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('delete', $values['action']);
+        $this->assertEquals('lcrouch', $values['id']);
+    }
+
+    public function test_RESTfulApp_POST_user_with_identifier_doesPUT()
+    {
+        $request = $this->_buildRequest('POST', '/mod/user/lcrouch');
+        $values = $this->_invokeRouteMatch($request);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('put', $values['action']);
+        $this->assertEquals('lcrouch', $values['id']);
+    }
+
+    public function test_RESTfulApp_overload_POST_with_method_param_PUT()
+    {
+        $request = $this->_buildRequest('POST', '/mod/user');
+        $request->setParam('_method', 'PUT');
+        $values = $this->_invokeRouteMatch($request);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('put', $values['action']);
+    }
+
+    public function test_RESTfulApp_overload_POST_with_http_header_DELETE()
+    {
+        $request = $this->_buildRequest('POST', '/mod/user/lcrouch');
+        $request->setHeader('X-HTTP-Method-Override', 'DELETE');
+        $values = $this->_invokeRouteMatch($request);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('delete', $values['action']);
+        $this->assertEquals('lcrouch', $values['id']);
+    }
+
+    public function test_RESTfulModule_GET_user_index()
+    {
+        $request = $this->_buildRequest('GET', '/mod/user/index');
+        $config = array('mod');
+        $values = $this->_invokeRouteMatch($request, $config);
+
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('index', $values['action']);
+    }
+
+    public function test_RESTfulModule_GET_user()
+    {
+        $request = $this->_buildRequest('GET', '/mod/user/1234');
+        $config = array('mod');
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('get', $values['action']);
+    }
+
+    public function test_RESTfulModule_POST_user()
+    {
+        $request = $this->_buildRequest('POST', '/mod/user');
+        $config = array('mod');
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('post', $values['action']);
+    }
+
+    public function test_RESTfulModule_POST_user_inNonRESTModule_returnsFalse()
+    {
+        $request = $this->_buildRequest('POST', '/default/user');
+        $config = array('mod');
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertFalse($values);
+    }
+
+    public function test_RESTfulModule_PUT_user_byIdentifier()
+    {
+        $request = $this->_buildRequest('PUT', '/mod/user/lcrouch');
+        $config = array('mod');
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('put', $values['action']);
+        $this->assertEquals('lcrouch', $values['id']);
+    }
+
+    public function test_RESTfulModule_DELETE_user_byIdentifier()
+    {
+        $request = $this->_buildRequest('DELETE', '/mod/user/lcrouch');
+        $config = array('mod');
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('delete', $values['action']);
+        $this->assertEquals('lcrouch', $values['id']);
+    }
+
+    public function test_RESTfulController_GET_user_index()
+    {
+        $request = $this->_buildRequest('GET', '/mod/user/index');
+        $config = array('mod'=>array('user'));
+        $values = $this->_invokeRouteMatch($request, $config);
+
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('index', $values['action']);
+    }
+
+    public function test_RESTfulController_GET_other_index_returns_false()
+    {
+        $request = $this->_buildRequest('GET', '/mod/project/index');
+        $config = array('mod'=>array('user'));
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertFalse($values);
+    }
+
+    public function test_RESTfulController_GET_user()
+    {
+        $request = $this->_buildRequest('GET', '/mod/user/1234');
+        $config = array('mod'=>array('user'));
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('get', $values['action']);
+    }
+
+    public function test_RESTfulController_POST_user()
+    {
+        $request = $this->_buildRequest('POST', '/mod/user');
+        $config = array('mod'=>array('user'));
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('post', $values['action']);
+    }
+
+    public function test_RESTfulController_POST_user_inNonRESTModule_returnsFalse()
+    {
+        $request = $this->_buildRequest('POST', '/default/user');
+        $config = array('mod'=>array('user'));
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertFalse($values);
+    }
+
+    public function test_RESTfulController_PUT_user_byIdentifier()
+    {
+        $request = $this->_buildRequest('PUT', '/mod/user/lcrouch');
+        $config = array('mod'=>array('user'));
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('put', $values['action']);
+        $this->assertEquals('lcrouch', $values['id']);
+    }
+
+    public function test_RESTfulController_DELETE_user_byIdentifier()
+    {
+        $request = $this->_buildRequest('DELETE', '/mod/user/lcrouch');
+        $config = array('mod');
+        $values = $this->_invokeRouteMatch($request, $config);
+         
+        $this->assertType('array', $values);
+        $this->assertTrue(isset($values['module']));
+        $this->assertEquals('mod', $values['module']);
+        $this->assertEquals('user', $values['controller']);
+        $this->assertEquals('delete', $values['action']);
+        $this->assertEquals('lcrouch', $values['id']);
+    }
+
+    public function test_assemble_plain_ignores_action()
+    {
+        $route = new Zend_Rest_Route($this->_front, array(), array());
+        $params = array('module'=>'mod', 'controller'=>'user', 'action'=>'get');
+        $url = $route->assemble($params);
+        $this->assertEquals('mod/user', $url);
+    }
+
+    public function test_assemble_id_after_controller()
+    {
+        $route = new Zend_Rest_Route($this->_front, array(), array());
+        $params = array('module'=>'mod', 'controller'=>'user', 'id'=>'lcrouch');
+        $url = $route->assemble($params);
+        $this->assertEquals('mod/user/lcrouch', $url);
+    }
+
+    public function test_assemble_index_after_controller_with_params()
+    {
+        $route = new Zend_Rest_Route($this->_front, array(), array());
+        $params = array('module'=>'mod', 'controller'=>'user', 'index'=>true, 'foo'=>'bar');
+        $url = $route->assemble($params);
+        $this->assertEquals('mod/user/index/foo/bar', $url);
+    }
+
+    private function _buildRequest($method, $uri)
+    {
+        $request = new Zend_Controller_Request_HttpTestCase();
+        $request->setMethod($method)->setRequestUri($uri);
+        return $request;
+    }
+
+    private function _invokeRouteMatch($request, $config = array())
+    {
+        $this->_front->setRequest($request);
+        $route = new Zend_Rest_Route($this->_front, array(), $config);
+        $values = $route->match($request);
+        return $values;
+    }
+}
+
+// Call Zend_Rest_RouteTest::main() if this source file is executed directly.
+if (PHPUnit_MAIN_METHOD == "Zend_Rest_RouteTest::main") {
+    Zend_Rest_RouteTest::main();
+}