1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
|
<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.controller.request">
<title>The Request Object</title>
<sect2 id="zend.controller.request.introduction">
<title>Introduction</title>
<para>
The request object is a simple value object that is passed between
<classname>Zend_Controller_Front</classname> and the router, dispatcher, and
controller classes. It packages the names of the requested module,
controller, action, and optional parameters, as well as the rest of
the request environment, be it <acronym>HTTP</acronym>, the <acronym>CLI</acronym>, or
<acronym>PHP</acronym>-GTK.
</para>
<itemizedlist>
<listitem>
<para>
The module name is accessed by <methodname>getModuleName()</methodname> and
<methodname>setModuleName()</methodname>.
</para>
</listitem>
<listitem>
<para>
The controller name is accessed by <methodname>getControllerName()</methodname>
and <methodname>setControllerName()</methodname>.
</para>
</listitem>
<listitem>
<para>
The name of the action to call within that controller is
accessed by <methodname>getActionName()</methodname> and
<methodname>setActionName()</methodname>.
</para>
</listitem>
<listitem>
<para>
Parameters to be accessible by the action are an associative array
of key and value pairs that are retrieved by
<methodname>getParams()</methodname> and set with
<methodname>setParams()</methodname>, or individually by
<methodname>getParam()</methodname> and <methodname>setParam()</methodname>.
</para>
</listitem>
</itemizedlist>
<para>
Based on the type of request, there may be more methods available.
The default request used, <classname>Zend_Controller_Request_Http</classname>,
for instance, has methods for retrieving the request <acronym>URI</acronym>, path
information, <varname>$_GET</varname> and <varname>$_POST</varname> parameters,
etc.
</para>
<para>
The request object is passed to the front controller, or if none is
provided, it is instantiated at the beginning of the dispatch
process, before routing occurs. It is passed through to every object
in the dispatch chain.
</para>
<para>
Additionally, the request object is particularly useful in testing.
The developer may craft the request environment, including module,
controller, action, parameters, <acronym>URI</acronym>, etc, and pass the request
object to the front controller to test application flow. When paired
with the <link linkend="zend.controller.response">response
object</link>, elaborate and precise unit testing of <acronym>MVC</acronym>
applications becomes possible.
</para>
</sect2>
<sect2 id="zend.controller.request.http">
<title>HTTP Requests</title>
<sect3 id="zend.controller.request.http.dataacess">
<title>Accessing Request Data</title>
<para>
<classname>Zend_Controller_Request_Http</classname> encapsulates access to
relevant values such as the key name and value for the
controller and action router variables, and all additional
parameters parsed from the <acronym>URI</acronym>. It additionally allows access to
values contained in the superglobals as public members, and
manages the current Base <acronym>URL</acronym> and Request <acronym>URI</acronym>.
Superglobal values cannot be set on a request object, instead use the
<methodname>setParam()</methodname> and <methodname>getParam()</methodname> methods
to set or retrieve user parameters.
</para>
<note>
<title>Superglobal Data</title>
<para>
When accessing superglobal data through
<classname>Zend_Controller_Request_Http</classname> as public member
properties, it is necessary to keep in mind that the
property name (superglobal array key) is matched to a
superglobal in a specific order of precedence: 1. <constant>GET</constant>, 2.
<constant>POST</constant>, 3. <constant>COOKIE</constant>, 4.
<constant>SERVER</constant>, 5. <constant>ENV</constant>.
</para>
</note>
<para>
Specific superglobals can be accessed using a public method as
an alternative. For example, the raw value of
<varname>$_POST['user']</varname> can be accessed by calling
<methodname>getPost('user')</methodname> on the request object. These
include <methodname>getQuery()</methodname> for retrieving
<varname>$_GET</varname> elements, and <methodname>getHeader()</methodname> for
retrieving request headers.
</para>
<note>
<title>GET and POST Data</title>
<para>
Be cautious when accessing data from the request object as
it is not filtered in any way. The router and dispatcher
validate and filter data for use with their tasks, but leave
the data untouched in the request object.
</para>
</note>
<note>
<title>Retrieving the Raw POST Data</title>
<para>
As of 1.5.0, you can also retrieve the raw post data via the
<methodname>getRawBody()</methodname> method. This method returns
<constant>FALSE</constant> if no data was submitted in that fashion, but the
full body of the post otherwise.
</para>
<para>
This is primarily useful for accepting content when
developing a RESTful <acronym>MVC</acronym> application.
</para>
</note>
<para>
You may also set user parameters in the request object using
<methodname>setParam()</methodname> and retrieve these later using
<methodname>getParam()</methodname>. The router makes use of this
functionality to set parameters matched in the request <acronym>URI</acronym> into
the request object.
</para>
<note>
<title>getParam() Retrieves More than User Parameters</title>
<para>
In order to do some of its work, <methodname>getParam()</methodname> actually
retrieves from several sources. In order of priority, these
include: user parameters set via <methodname>setParam()</methodname>,
<constant>GET</constant> parameters, and finally <constant>POST</constant>
parameters. Be aware of this when pulling data via this
method.
</para>
<para>
If you wish to pull only from parameters you set via
<methodname>setParam()</methodname>, use the
<methodname>getUserParam()</methodname>.
</para>
<para>
Additionally, as of 1.5.0, you can lock down which parameter
sources will be searched. <methodname>setParamSources()</methodname>
allows you to specify an empty array or an array with one or
more of the values '_GET' or '_POST' indicating which
parameter sources are allowed (by default, both are
allowed); if you wish to restrict access to only '_GET'
specify <methodname>setParamSources(array('_GET'))</methodname>.
</para>
</note>
<note>
<title>Apache Quirks</title>
<para>
If you are using Apache's 404 handler to pass incoming
requests to the front controller, or using a PT flag with
rewrite rules, <varname>$_SERVER['REDIRECT_URL']</varname>
contains the <acronym>URI</acronym> you need, not
<varname>$_SERVER['REQUEST_URI']</varname>. If you are using such
a setup and getting invalid routing, you should use the
<classname>Zend_Controller_Request_Apache404</classname> class instead
of the default <acronym>HTTP</acronym> class for your request object:
</para>
<programlisting language="php"><![CDATA[
$request = new Zend_Controller_Request_Apache404();
$front->setRequest($request);
]]></programlisting>
<para>
This class extends the
<classname>Zend_Controller_Request_Http</classname> class and simply
modifies the autodiscovery of the request <acronym>URI</acronym>. It can be
used as a drop-in replacement.
</para>
</note>
</sect3>
<sect3 id="zend.controller.request.http.baseurl">
<title>Base Url and Subdirectories</title>
<para>
<classname>Zend_Controller_Request_Http</classname> allows
<classname>Zend_Controller_Router_Rewrite</classname> to be used in subdirectories.
<classname>Zend_Controller_Request_Http</classname> will attempt to automatically
detect your base <acronym>URL</acronym> and set it accordingly.
</para>
<para>
For example, if you keep your <filename>index.php</filename> in a
webserver subdirectory named
<filename>/projects/myapp/index.php</filename>, base <acronym>URL</acronym> (rewrite
base) should be set to <filename>/projects/myapp</filename>. This string will
then be stripped from the beginning of the path before
calculating any route matches. This frees one from the necessity
of prepending it to any of your routes. A route of
<command>'user/:username'</command> will match <acronym>URI</acronym>s like
<filename>http://localhost/projects/myapp/user/martel</filename> and
<filename>http://example.com/user/martel</filename>.
</para>
<note>
<title>URL Detection is Case Sensitive</title>
<para>
Automatic base <acronym>URL</acronym> detection is case sensitive, so make sure
your <acronym>URL</acronym> will match a subdirectory name in a filesystem (even
on Windows machines). If it doesn't, an exception will be raised.
</para>
</note>
<para>
Should base <acronym>URL</acronym> be detected incorrectly you can override it
with your own base path with the help of the
<methodname>setBaseUrl()</methodname> method of either the
<classname>Zend_Controller_Request_Http</classname> class, or the
<classname>Zend_Controller_Front</classname> class. The easiest
method is to set it in <classname>Zend_Controller_Front</classname>,
which will proxy it into the request object. Example usage to
set a custom base <acronym>URL</acronym>:
</para>
<programlisting language="php"><![CDATA[
/**
* Dispatch Request with custom base URL with Zend_Controller_Front.
*/
$router = new Zend_Controller_Router_Rewrite();
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('./application/controllers')
->setRouter($router)
->setBaseUrl('/projects/myapp'); // set the base url!
$response = $controller->dispatch();
]]></programlisting>
<note>
<title>Fully-Qualified URL is not supported</title>
<para>
Passing a fully-qualified URL (ie: http://example.com/) to the
<methodname>setBaseUrl</methodname> method is not supported, and
will cause issues for both the usage describe above and when using
the URL view helper. See ticket
<ulink url="http://framework.zend.com/issues/browse/ZF-10923">
ZF-10923
</ulink> for more details.
</para>
</note>
</sect3>
<sect3 id="zend.controller.request.http.method">
<title>Determining the Request Method</title>
<para>
<methodname>getMethod()</methodname> allows you to determine the
<acronym>HTTP</acronym> request method used to request the current resource.
Additionally, a variety of methods exist that allow you to get
boolean responses when asking if a specific type of request has
been made:
</para>
<itemizedlist>
<listitem><para><methodname>isGet()</methodname></para></listitem>
<listitem><para><methodname>isPost()</methodname></para></listitem>
<listitem><para><methodname>isPut()</methodname></para></listitem>
<listitem><para><methodname>isDelete()</methodname></para></listitem>
<listitem><para><methodname>isHead()</methodname></para></listitem>
<listitem><para><methodname>isOptions()</methodname></para></listitem>
</itemizedlist>
<para>
The primary use case for these is for creating RESTful <acronym>MVC</acronym>
architectures.
</para>
</sect3>
<sect3 id="zend.controller.request.http.ajax">
<title>Detecting AJAX Requests</title>
<para>
<classname>Zend_Controller_Request_Http</classname> has a rudimentary
method for detecting <acronym>AJAX</acronym> requests:
<methodname>isXmlHttpRequest()</methodname>. This method looks for an
<acronym>HTTP</acronym> request header <emphasis>X-Requested-With</emphasis> with
the value 'XMLHttpRequest'; if found, it returns <constant>TRUE</constant>.
</para>
<para>
Currently, this header is known to be passed by default with the
following JS libraries:
</para>
<itemizedlist>
<listitem>
<para>Prototype and Scriptaculous (and libraries derived from Prototype)</para>
</listitem>
<listitem><para>Yahoo! UI Library</para></listitem>
<listitem><para>jQuery</para></listitem>
<listitem><para>MochiKit</para></listitem>
</itemizedlist>
<para>
Most <acronym>AJAX</acronym> libraries allow you to send custom
<acronym>HTTP</acronym> request headers; if your library does not send this header,
simply add it as a request header to ensure the
<methodname>isXmlHttpRequest()</methodname> method works for you.
</para>
</sect3>
</sect2>
<sect2 id="zend.controller.request.subclassing">
<title>Subclassing the Request Object</title>
<para>
The base request class used for all request objects is the abstract
class <classname>Zend_Controller_Request_Abstract</classname>. At its most
basic, it defines the following methods:
</para>
<programlisting language="php"><![CDATA[
abstract class Zend_Controller_Request_Abstract
{
/**
* @return string
*/
public function getControllerName();
/**
* @param string $value
* @return self
*/
public function setControllerName($value);
/**
* @return string
*/
public function getActionName();
/**
* @param string $value
* @return self
*/
public function setActionName($value);
/**
* @return string
*/
public function getControllerKey();
/**
* @param string $key
* @return self
*/
public function setControllerKey($key);
/**
* @return string
*/
public function getActionKey();
/**
* @param string $key
* @return self
*/
public function setActionKey($key);
/**
* @param string $key
* @return mixed
*/
public function getParam($key);
/**
* @param string $key
* @param mixed $value
* @return self
*/
public function setParam($key, $value);
/**
* @return array
*/
public function getParams();
/**
* @param array $array
* @return self
*/
public function setParams(array $array);
/**
* @param boolean $flag
* @return self
*/
public function setDispatched($flag = true);
/**
* @return boolean
*/
public function isDispatched();
}
]]></programlisting>
<para>
The request object is a container for the request environment. The
controller chain really only needs to know how to set and retrieve the
controller, action, optional parameters, and dispatched status. By
default, the request will search its own parameters using the
controller or action keys in order to determine the controller and
action.
</para>
<para>
Extend this class, or one of its derivatives, when you need the
request class to interact with a specific environment in order to
retrieve data for use in the above tasks. Examples include <link
linkend="zend.controller.request.http">the <acronym>HTTP</acronym>
environment</link>, a <acronym>CLI</acronym> environment, or a
<acronym>PHP</acronym>-GTK environment.
</para>
</sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
|