<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[
<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[
Zend_Rest_Route is a route that uses URI to route the module & controller and HTTP request method to route to the action of a Zend_Controller_Action_Rest controller.
Zend_Rest_Controller is an abstract action controller designating the action methods to implement for use with Zend_Controller_Router_Route_Rest. Zend_Rest_PutHandler is a controller plugin to improve PUT body handling - enables controllers to access x-www-form-urlencoded PUT bodies via getParams().Zend Framework: Zend_Controller_Router_Route_Rest Component Proposal
Proposed Component Name
Zend_Controller_Router_Route_Rest
Developer Notes
http://framework.zend.com/wiki/display/ZFDEV/Zend_Controller_Router_Route_Rest
Proposers
luke.crouch@gmail.com
Matthew Weier O'Phinney - Zend Liaison
Revision
1.0 - 23 Feb 2008: Started.
1.0 - 15 May 2008: changed from Route class to full-on Router class.
1.0 - 15 May 2008: changed back to Route class
2.0 - 01 Jan 2009: updated Route class for ZF 1.7 compatibility
2.0 - 30 Jun 2009: development started under ZF-7109 (wiki revision: 46)Table of Contents
1. Overview
2. References
3. Component Requirements, Constraints, and Acceptance Criteria
- This component will operate as a Route class of the Rewrite Router.
- This component will route to Modules and Controllers based on URI tokens.
- This component will route to specific Actions based on HTTP request types.
- This component will support overloaded-POST-based routing for PUT and DELETE request types.
- This component will route to some special Actions based on URI tokens.
- This component will include an abstract Zend_Controller_Action class for implementation reference.
- This component will allow for designating specific REST Modules and/or Controllers
4. Dependencies on Other Framework Components
- Zend_Controller
5. Theory of Operation
A RESTful routing paradigm for Zend_Controller should behave as follows:
| Request method | URI | Module_Controller::action |
|---|---|---|
| GET | /product/ratings/ | Product_RatingsController::indexAction() |
| GET | /product/ratings/id/:id | Product_RatingsController::getAction() |
| GET | /product/ratings/new | Product_RatingsController::newAction() |
| GET | /product/ratings/id/:id/edit | Product_RatingsController::editAction() |
| POST | /product/ratings | Product_RatingsController::postAction() |
| PUT | /product/ratings/id/:id | Product_RatingsController::putAction() |
| DELETE | /product/ratings/id/:id | Product_RatingsController::deleteAction() |
| POST | /product/ratings/id/:id _method=PUT |
Product_RatingsController::putAction() |
| POST | /product/ratings/id/:id _method=DELETE |
Product_RatingsController::deleteAction() |
6. Milestones / Tasks
- Milestone 1: Working prototype checked into the incubator supporting use cases #1
- Milestone 2: Unit tests exist, work, and are checked into SVN.
- Milestone 3: Initial documentation exists.
7. Class Index
- Zend_Rest_Route
- Zend_Rest_Controller
- Zend_Rest_PutHandler
39 Comments
comments.show.hideMay 15, 2008
Michal Minicki
<blockquote>
<p>Martel,</p>
<p>I actually started working on this again recently for a project and I ended up writing a Zend_Controller_Router_Rest class instead of a specific Route class. I updated my proposal in the wiki and would appreciate some feedback from you before I announce it to the mailing list. It actually works for me, but I'm sure it could use some cleanup and such ...</p></blockquote>
<p>Luke, I don't really see anything in there that couldn't be used in the route class instead of a router. While overriding the router you're basically removing support for chaining different types of routing. And you render the URL view helper useless. And that's all. That's what you get by doing it in the router instead of a route class. </p>
<p>If you leave automatic module detection out, you don't even need the dispatcher instance (and router in fact shouldn't be aware of the dispatcher). All you need is the request object which will be passed to route instances in a very near future. </p>
May 15, 2008
Luke Crouch
<p>yeah, that's the best design, but RESTful routing needs the full request object and it's not currently available to Route classes, as you mentioned. I have this same code in a Route class as well, but it couldn't access the request object, so it's impossible to get the request method in a Route.</p>
<p>I'll just use this Router class in my project for now, but I will change this back into a Route and I think it will just have to wait until the request object is passed into Route instances. please keep me posted on how and when that advances. thanks.</p>
May 15, 2008
Michal Minicki
<p>Luke, pay attention to this issue:
<a class="external-link" href="http://framework.zend.com/issues/browse/ZF-777">http://framework.zend.com/issues/browse/ZF-777</a></p>
<p>As Matthew mentioned it in the last comment, I have a patch that keeps backwards compatibility intact. Basically this means you will just have to implement an additional interface (with setRequest method). And that's it - the request will be available for you on match().</p>
Aug 04, 2008
Michal Minicki
<p>As I have mentioned before, you now have a Request object passed as a first parameter to match() method on version 2 routes. Just extend abstract class to get this behavior by default.</p>
Aug 04, 2008
Luke Crouch
<p>Michal,</p>
<p>cool, thanks! I saw the issue update. is this presently only in trunk? is it slated to go out with next release?</p>
Dec 03, 2008
Steve Wilhelm
<p>What is the status of this class? What is the preferred method of implementing a RESTful Web Service?</p>
Dec 04, 2008
Luke Crouch
<p>I haven't done much with it. But, I have some free time now so maybe I can wrap it up this weekend.</p>
<p>I'll also be submitting another class or two to aid RESTful design. Watch this page for updates.</p>
Jan 01, 2009
Luke Crouch
<p>I've updated the use-case and class code of this proposal to match Route behavior of ZF 1.7.2. What are next steps for moving it into incubator?</p>
Jan 01, 2009
Matthew Weier O'Phinney
<p>Mark the proposal as ready for recommendation, and we'll pick it up on our next round of reviews.</p>
Jan 08, 2009
Matthew Weier O'Phinney
<p>I'm not sure I agree with the URI/request method mappings you outlined under "Theory of Operation". Traditional REST would do the following:</p>
<table><tbody>
<tr>
<th><p>Request Method</p></th>
<th><p>URI</p></th>
<th><p>Module_Controller::action</p></th>
</tr>
<tr>
<td><p>GET</p></td>
<td><p>/product/ratings</p></td>
<td><p>Product_Ratings::listAction()</p></td>
</tr>
<tr>
<td><p>GET</p></td>
<td><p>/product/ratings/:id</p></td>
<td><p>Product_Ratings::getAction()</p></td>
</tr>
<tr>
<td><p>POST</p></td>
<td><p>/product/ratings</p></td>
<td><p>Product_Ratings::newAction()</p></td>
</tr>
<tr>
<td><p>PUT</p></td>
<td><p>/product/ratings/:id</p></td>
<td><p>Product_Ratings::updateAction()</p></td>
</tr>
<tr>
<td><p>DELETE</p></td>
<td><p>/product/ratings/:id</p></td>
<td><p>Product_Ratings::deleteAction()</p></td>
</tr>
<tr>
<td><p>POST</p></td>
<td><p>/product/ratings/:id</p></td>
<td><p>Product_Ratings::updateAction()</p></td>
</tr>
<tr>
<td><p>POST</p></td>
<td><p>/product/ratings/:id?delete</p></td>
<td><p>Product_Ratings::deleteAction()</p></td>
</tr>
</tbody></table>
<p>The differences are around how get/new/update/delete work. When you POST with an identifier, it acts as an update; without an identifier, it attempts to create a new item. </p>
<p>Otherwise, the proposed solution makes sense.</p>
<p>One other item: It seems like this should include an extension to Zend_Controller_Action – perhaps Zend_Controller_Action_Rest and/or Zend_Controller_Action_Rest_Interface? That would simplify the creation of REST controllers, and ensure that they would work with the route.</p>
Jan 08, 2009
Luke Crouch
<p>Hmm ... I was going by behavior described in RESTful Web Services by Leonard Richardson & Sam Ruby. The spec seems to support it:</p>
<p>"The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request"
<a class="external-link" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6">http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6</a></p>
<p>I don't mind changing the names of the action methods, but the reason I have a separate newAction vs. a postAction is to allow the route to choose a controller action that serves a representation that will instruct the user agent how to compose the POST request that creates a new resource - e.g., an HTML form so /product/ratings/new returns an HTML form that POSTs to /product/ratings</p>
<p>The reason I didn't include query params in the URI for over-loaded POSTs is because the request method for over-loaded POST is still POST which means the params will be in the request body, not in the URI like that. It's effectively the same but I think the POST body params are more indicative of what's really happening.</p>
<p>I actually have an abstract Zend_Controller_Action_Rest class as well, but I'm not as sure of it, and I thought I'd submit them as separate proposals so users could use them separately. I wouldn't mind writing a Zend_Controller_Action_Rest_Interface to include with this proposal so we have an idea what the controller implementation should be.</p>
<p>So, if I change:</p>
<p>indexAction => listAction<br />
putAction => updateAction<br />
Add Zend_Controller_Action_Rest_Interface</p>
<p>Think that will be good for this proposal to move forward?</p>
Jan 09, 2009
Matthew Weier O'Phinney
<p>I was going based on other literature I've read, not the spec. I'm fine with identifying the identity as part of the payload – but make sure it's well documented what the various schemes are. Bonus points if you can make it configurable. <ac:emoticon ac:name="smile" /> That said, I really don't like using "new" to indicate a new record and "edit" to grab one to update; that's part of what REST tries to get around. If there is no entity identifier, it's a new record; POST updates the record.</p>
<p>Regarding the query parameters, it was unclear from your table that the _method=(PUT|DELETE) was a part of the payload; I thought it was part of the URI. Putting that in the payload is fine by me.</p>
<p>One last note on URIs: while the default ZF route uses key/value pairs, I really don't think it's necessary to do so with a REST route – and in fact makes the URLs look less clean. Let's go with traditional REST routes, and drop the id/:id in favor of just :id.</p>
<p>As for the action names, I think either index or list would work well for the collection of entities; maybe list could be an alias for index. I also do prefer using updateAction over putAction, as it identifies what's happening semantically.</p>
<p>Finally, regarding the Zend_Controller_Action_Rest class, I think abstract is fine (no need for an interface), and that it <em>should</em> be part of the proposal; it makes for a clean, full solution that users can develop on immediately.</p>
<p>Overall, very nice!</p>
Jan 09, 2009
Luke Crouch
<p>Re: edit and new ...</p>
<p>I agree that performing stateful operations via URI tokens is RESTless, but in this route's usage, 'edit' and 'new' denote resources/nouns - not operations:</p>
<p>'new' = the form (a resource) for creating a new resource<br />
'edit' = the form (a resource) for editing an existing resource</p>
<p>This is basically to encourage "hypertext as the engine of application state." e.g., GET /resource/new delivers a representation (HTML page) that contains hypertext (<form method="post" action="/resource/">) that drives to another state of the application (creating a new resource). /resource/new DOES NOT perform any stateful operations, and does not respond to any requests other than GET.</p>
<p>With all that said, think it's fine to leave the 'new' and 'edit' actions in there as long as we make it explicit what their purpose is?</p>
<p>I'll work on dropping the key-value pairs for the identifier, but in using this route myself, I've found key-value params pretty useful. e.g., makes it easy to also support flexible identifiers like /name/:name or /modified_since/:timestamp.</p>
<p>I can also add a Zend_Controller_Action_Rest abstract class.</p>
Jan 09, 2009
Matthew Weier O'Phinney
<p>Aha - I was thinking of this more in terms of an XML/JSON REST service, not in terms of using it for HTML as well. With that in mind, I think it makes sense.</p>
<p>As for the /:id comment – you could think of it like Zend_Controller_Router_Route, where a /* means that anything following is key/value pairs. That would allow for urls like /wiki/SomePage/modified_since/2008-12-02 – which gives you the :id (SomePage) as well as extra key/value resources.</p>
Oct 30, 2010
Grayson Koonce
<p>This is great. If newAction and editAction facilitate collecting user input for postAction and putAction, what about deleteAction? Its the man out. The use case here is confirmation. Maybe 'remove' is necessary. The use case is similar in that its common to show a confirm form with a Zend_Form_Element_Hash to make 'real' sure the user wants to delete the resource at hand. Any thoughts?</p>
Nov 01, 2010
Luke Crouch
<p>newAction and editAction help enable RESTful HTML clients by leading into postAction and putAction, but there's nothing necessary about them nor about a removeAction.</p>
<p>Having said that, a removeAction could be really helpful for showing clients any and all linked resources that would be affected by a DELETE request.</p>
<p>We can create a ticket to add a removeAction to the abstract Controller and to the route and maybe work on that for Zend_Rest in 2.0</p>
Nov 01, 2010
Grayson Koonce
<p>I think it's a good idea. Also, assuming we get ZF-9823 fix (unable to assemble rest route for new and edit) in there I would be super stoaked <ac:emoticon ac:name="smile" />.</p>
Jan 09, 2009
Matthew Weier O'Phinney
<ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Acceptance</ac:parameter><ac:rich-text-body>
<p>This proposal is accepted for immediate development in the standard incubator. However, there are several changes/issues we would like to see addressed:</p>
<ul>
<li>Rename to Zend_Rest_Route and Zend_Rest_Controller</li>
<li>Do not inject the dispatcher and request object in the route constructor. Instead, allow for optional injection of the front controller. As the dispatcher and request object could change prior to routing, injecting the front controller (or, if not present, pulling the singleton instance) will allow retrieving the instances as registered at execution time.</li>
<li>The abstract Zend_Rest_Controller should <strong>not</strong> include the newAction and editAction methods, but the route should still allow for them. The Zend team's feeling is that while these may be useful in REST applications that utilize HTML, the majority of REST applications will likely not utilize them, and the controller should not enforce their existence.</li>
<li>The route should allow each of the following scenarios:
<ul>
<li>Acting as a fallback route, and route all matched requests as RESTful actions (this is the usage shown already in UC-01)</li>
<li>Allow registering a specific module or array of modules as containing controllers with RESTful actions:
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
// Only the module "api":
$restfulRoutes = new Zend_Rest_Route('api', $front);
// The modules "xml" and "json":
$restfulRoutes = new Zend_Rest_Route(array('xml', 'json'), $front);
]]></ac:plain-text-body></ac:macro></li>
<li>Allow registering specific module => controller combinations as RESTful controllers:
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
// The Service_RestController only:
$restfulRoute = new Zend_Rest_Route(array('service' => array('rest')), $front);
// The controllers: Json_RestController, Service_RestController, and Service_JsonController:
$restfulRoute = new Zend_Rest_Route(
array(
'json' => array('rest'),
'service' => array('rest', 'json'),
),
$front
);
]]></ac:plain-text-body></ac:macro>
We feel that this API would allow for mixing RESTful controllers with other application controllers.</li>
</ul>
</li>
<li>Finally, we have one concern regarding the matching of request method tokens. It cannot be assumed that the request is using a payload in a specific format; the request could be in JSON, XML, YAML, etc. As such, we request that if the matching is format specific, different subclasses be created for each specific format you intend to support (Zend_Rest_Route_Json, Zend_Rest_Route_Xml, etc.).</li>
</ul>
</ac:rich-text-body></ac:macro>
Jan 09, 2009
Luke Crouch
<p>We can't put these classes into Zend_Rest. Frankly and simply, Zend_Rest has nothing to do with REST. It's just another XML-RPC implementation that ignores the uniform HTTP interface and other elements of RESTful design and architecture. I've made mention in the mailing lists before that it needs to be re-named and/or merged with Zend_XmlRpc.</p>
<p>REST is a different architectural style. These classes are Zend_Controller classes; they enhance functionality of Zend_Controller to enable REST architectural style and technical design. I'd rather keep them in the Zend_Controller package.</p>
<p>The request matching will never be format-specific, so there's no need for different sub-classes for different formats. In fact, I've used this exact route class really well with Zend_Controller_Action_Helper_ContextSwitch for building REST API that supports HTML, JSON, and XML simultaneously using only separate template files.</p>
<p>The injection of the dispatcher and the request into the constructor are inherited from Zend_Controller_Router_Route_Module. I'll alter this class to accept the front controller in the constructor, but that won't fix the problem in Module.</p>
<p>I'll remove the newAction and editAction from the Controller.</p>
<p>I'll also start work on designating specific module and controllers as RESTful via this route class.</p>
Jan 09, 2009
Matthew Weier O'Phinney
<p>Our plan is to deprecate Zend_Rest_Server, and potentially Zend_Rest_Client as well. We are well aware that they do not follow RESTful design, and this is one reason we are excited about your proposal, as it follows our desire to offer RESTful offerings. (The current Zend_Rest offerings were written well before we had a proposal process, and did not have sufficient review.)</p>
<p>The reason we would like these classes under Zend_Rest is two-fold. First, for developers looking for REST solutions in Zend Framework, they are unlikely to look in Zend_Controller; placing them under Zend_Rest makes finding them easier. Second, all other protocol and service specific classes in ZF have their own namespace: Zend_XmlRpc, Zend_Soap, Zend_Json, Zend_Dojo (form and view integration), etc – even if they have ties to other components. While your implementation is specific to the MVC, it allows us to group REST related components in a single location; documentation can then indicate how the various subcomponents are used and how they relate to other ZF components.</p>
<p>Thanks for pointing out the dispatcher/request injection in the module route; I'll create an issue to track that. Also, thank you for clarifying that the route is not format specific – this wasn't clear from the proposal, so it's good to know you've already taken care of that. </p>
Jan 11, 2009
Luke Crouch
<p>Okay, I feel better about that plan to deprecate the existing Zend_Rest classes. I agree it will be nice for users to find all the REST classes in a single place, and I think replacing the current Zend_Rest documentation with a guide on how to use these new RESTful classes will be a huge improvement.</p>
<p>Given that, should this proposal be re-named to Zend_Rest or something more like that? I should also mention that I also use a Controller plugin called 'RestHandler' for better support of PUT requests often used in RESTful HTML clients - i.e., to digest PUT request bodies of type 'x-www-form-urlencoded' and make the params available via $request->getParams(). Should I add this plugin class to the proposal as well?</p>
Jan 11, 2009
Matthew Weier O'Phinney
<p>No need to rename the proposal; the core of it is basically the same: a route class for RESTful requests.</p>
<p>Yes, do please include the RestHandler plugin; that way we can have a fairly complete REST offering for users. Please update the page to show the API of the plugin, as well as a sample use case.</p>
Feb 10, 2009
Jerome Mouneyrac
<p>Hi, Zend_Rest_Server will be deprecated. Does it mean that there will be some new Zend_Restful_Server/Client? If yes, will the server be consistent with the others soap/amf/xmlrpc server? (the server load a class/method and check the phpdoc)</p>
Feb 10, 2009
Matthew Weier O'Phinney
<p>No. Zend_Rest_Server currently follows that paradigm (introspection of class to determine method signatures), but that paradigm is not <em>RESTful</em> – it's simply another RPC-style service. This has caused confusion for many developers, and does not serve our users well. If you want to do RPC using XML... use XML-RPC.</p>
<p>Zend_Rest_Client will likely continue to live on. However, for most use cases when querying RESTful architectures, Zend_Http_Client is a better choice, as it gives more fine-grained control over the request headers and body, and in many cases is more intuitive when using RESTful architectures.</p>
Jan 11, 2009
Luke Crouch
<p>I assume if the route is configured for an entire module, <strong>all</strong> requests to the module should be routed RESTfully to all controllers in it?</p>
Jan 11, 2009
Matthew Weier O'Phinney
<p>Correct. The three scenarios we see are:</p>
<ul>
<li>Route <strong>all</strong> requests as REST (UC-01) (unless specifically overridden with other routes)</li>
<li>Route <strong>all</strong> requests to a a given <strong>module</strong> as REST (i.e., all controllers in that module are REST controllers)</li>
<li>Route <strong>specific</strong> module/controller pairs as REST.</li>
</ul>
Jan 11, 2009
Remi ++
<p>Does this solution allows to submit identifier with Umlauts and Slashes?</p>
<p>Example Use Case:<br />
It should be possible to update products with the following identifiers:</p>
<ul class="alternate">
<li>ProductId: "Mü/120/abc"</li>
<li>ProductId: "Aß/230/def"</li>
</ul>
<p>In this Use Case the identifiers contains Slashes as well as Umlauts. Submitting identifiers with slashes (and different character sets) shouldn't lead to misinterpreted parameters.</p>
<p>Remi</p>
Jan 12, 2009
Luke Crouch
<p>I hadn't thought of this but will look at supporting it. I'm not sure how to support both the flexible key-value url param identifiers AND slashes in the identifiers, but I'll give it a try.</p>
Jan 12, 2009
Matthew Weier O'Phinney
<p>I don't think you <em>can</em> support both use cases. I'd recommend that if you need slashes in your URLs for identifiers that you write logic to convert another character to slashes on the server side (when posted via the REQUEST_URI, that is).</p>
Jan 12, 2009
Luke Crouch
<p>I've updated the proposal and code to meet the acceptance criteria. Couple of things discussed but not implemented ...</p>
<p>I didn't drop the key-value URI scheme because I have found it easier to implement a flexible 'index' action - i.e., one that accepts an assortment of filtering params like /new_since/:timestamp/changed_since/:timestamp - if each of the params retain names. As I consider this though, I could change the route to pass key-value URI params for the 'index' route only, and all other routes could operate from the /:module/:controller/:identifier scheme. How important is this feature?</p>
<p>I left the putAction as putAction, simply because the route code is getting a little complex already, and also because I think it helps to reinforce users' implementation of the HTTP uniform interface in their controllers. Again I could re-consider this if we think it's very important.</p>
Jan 13, 2009
Luke Crouch
<p>Also, I need a bit of coaching on my next steps. I <strong>think</strong> I have svn access, but can I simply check-out the standard incubator repos? How's the best way to set up a test project to use my Zend_Rest stuff from the incubator repos but use Zend_Controller from regular repos?</p>
Feb 02, 2009
Matthew Turland
<p>Could support for the X-HTTP-Method-Override header be included to supplement the _method parameter for clients that (for whatever reason) offer limited or no support for methods other than GET and POST?</p>
Feb 02, 2009
Luke Crouch
<p>Sure. I'll include it when I start putting the code into the repos.</p>
Mar 18, 2009
Wil Sinclair
<p>Luke, do you plan to have this ready for 1.8?</p>
Mar 19, 2009
Luke Crouch
<p>Hopefully. When is 1.8 scheduled?</p>
Jun 22, 2009
AJ
<p>Surely I'm a little lost, but I cannot find your proposal at the standard incubator repository. Where it is?</p>
<p> On the other hand, you said:
<br class="atl-forced-newline" /></p>
<blockquote>
<p>As I consider this though, I could change the route to pass key-value URI params for the 'index' route only, and all other routes could operate from the /:module/:controller/:identifier scheme. How important is this feature?</p></blockquote>
<p>I think this is a very important feature because it will allow a better integration with <a href="http://docs.dojocampus.org/dojox/data/JsonRestStore">dojox.data.JsonRestStore</a></p>
Jun 22, 2009
Luke Crouch
<p>AJ,</p>
<p>I'm actually working on getting this code into SVN right now and I'm using a patch from Rafael Dohms to do exactly this.</p>
<p>Thanks for the feedback,<br />
-L</p>
Jul 31, 2009
Jean-Sebastien HEDDE
<p>Hi,</p>
<p>Zend_Rest_Route::_checkRestfulModule() throw a E_WARNING on modules not declared in the __construct</p>
<p>Quick fix :</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
+ if ($this->_restfulControllers && array_key_exists($moduleName, $this->_restfulControllers) && array_search($controllerName, $this->_restfulControllers[$moduleName]) !== false)
]]></ac:plain-text-body></ac:macro>
Aug 25, 2009
Luke Crouch
<p>I don't see this line in the latest code in ZF 1.9.2. I may have already fixed this in the live code. Please use the ZF tracker to submit bugs now that the code is in the core library.</p>
<p><a class="external-link" href="http://framework.zend.com/issues/secure/Dashboard.jspa">http://framework.zend.com/issues/secure/Dashboard.jspa</a></p>
<p>Thanks,<br />
-L</p>