| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.controller.migration">
- <title>Migrating from Previous Versions</title>
- <para>
- The API of the MVC components has changed over time. If you started
- using Zend Framework in an early version, follow the guidelines below to
- migrate your scripts to use the new architecture.
- </para>
- <sect2 id="zend.controller.migration.fromoneseventooneeight">
- <title>Migrating from 1.7.x to 1.8.0 or newer</title>
- <sect3 id="zend.controller.migration.fromoneseventooneeight.router">
- <title>Standard Route Changes</title>
- <para>
- As translated segments were introduced into the new standard
- route, the <code>@</code> character is now a special character
- in the beginning of a route segment. To be able to use it in a
- static segment, you must escape it by prefixing it with second
- <code>@</code> character. The same rule now applies for the
- <code>:</code> character.
- </para>
- </sect3>
- </sect2>
- <sect2 id="zend.controller.migration.fromonesixtooneseven">
- <title>Migrating from 1.6.x to 1.7.0 or newer</title>
- <sect3 id="zend.controller.migration.fromonesixtooneseven.dispatcher">
- <title>Dispatcher Interface Changes</title>
- <para>
- Users brought to our attention the fact that
- <classname>Zend_Controller_Action_Helper_ViewRenderer</classname> were
- using a method of the dispatcher abstract class that was not in
- the dispatcher interface. We have now added the following method to
- ensure that custom dispatchers will continue to work with the
- shipped implementations:
- </para>
- <itemizedlist>
- <listitem><para>
- <code>formatModuleName()</code>: should be used to take a raw
- controller name, such as one that would be packaged inside a request
- object, and reformat it to a proper class name that a class extending
- <classname>Zend_Controller_Action</classname> would use
- </para></listitem>
- </itemizedlist>
- </sect3>
- </sect2>
- <sect2 id="zend.controller.migration.fromoneohtoonesix">
- <title>Migrating from 1.5.x to 1.6.0 or Newer</title>
- <sect3 id="zend.controller.migration.fromoneohtoonesix.dispatcher">
- <title>Dispatcher Interface Changes</title>
- <para>
- Users brought to our attention the fact that
- <classname>Zend_Controller_Front</classname> and
- <classname>Zend_Controller_Router_Route_Module</classname> were each
- using methods of the dispatcher that were not in the dispatcher
- interface. We have now added the following three methods to
- ensure that custom dispatchers will continue to work with the
- shipped implementations:
- </para>
- <itemizedlist>
- <listitem><para>
- <code>getDefaultModule()</code>: should return the name of
- the default module.
- </para></listitem>
- <listitem><para>
- <code>getDefaultControllerName()</code>: should return the
- name of the default controller.
- </para></listitem>
- <listitem><para>
- <code>getDefaultAction()</code>: should return the
- name of the default action.
- </para></listitem>
- </itemizedlist>
- </sect3>
- </sect2>
- <sect2 id="zend.controller.migration.fromoneohtoonefive">
- <title>Migrating from 1.0.x to 1.5.0 or Newer</title>
- <para>
- Though most basic functionality remains the same, and all documented
- functionality remains the same, there is one particular
- <emphasis>undocumented</emphasis> "feature" that has changed.
- </para>
- <para>
- When writing URLs, the documented way to write camelCased action
- names is to use a word separator; these are '.' or '-' by default,
- but may be configured in the dispatcher. The dispatcher internally
- lowercases the action name, and uses these word separators to
- re-assemble the action method using camelCasing. However, because PHP
- functions are not case sensitive, you <emphasis>could</emphasis>
- still write URLs using camelCasing, and the dispatcher would resolve
- these to the same location. For example, 'camel-cased' would become
- 'camelCasedAction' by the dispatcher, whereas 'camelCased' would
- become 'camelcasedAction'; however, due to the case insensitivity of
- PHP, both will execute the same method.
- </para>
- <para>
- This causes issues with the ViewRenderer when resolving view
- scripts. The canonical, documented way is that all word separators
- are converted to dashes, and the words lowercased. This creates
- a semantic tie between the actions and view scripts, and the
- normalization ensures that the scripts can be found. However, if the
- action 'camelCased' is called and actually resolves, the word
- separator is no longer present, and the ViewRenderer attempts to
- resolve to a different location -- 'camelcased.phtml' instead of
- 'camel-cased.phtml'.
- </para>
- <para>
- Some developers relied on this "feature", which was never intended.
- Several changes in the 1.5.0 tree, however, made it so that the
- ViewRenderer no longer resolves these paths; the semantic tie is now
- enforced. First among these, the dispatcher now enforces case
- sensitivity in action names. What this means is that referring to
- your actions on the url using camelCasing will no longer resolve to
- the same method as using word separators (i.e., 'camel-casing').
- This leads to the ViewRenderer now only honoring the word-separated
- actions when resolving view scripts.
- </para>
- <para>
- If you find that you were relying on this "feature", you have several
- options:
- </para>
- <itemizedlist>
- <listitem><para>
- Best option: rename your view scripts. Pros: forward
- compatibility. Cons: if you have many view scripts that
- relied on the former, unintended behavior, you will have a
- lot of renaming to do.
- </para></listitem>
- <listitem>
- <para>
- Second best option: The ViewRenderer now delegates view
- script resolution to <classname>Zend_Filter_Inflector</classname>; you
- can modify the rules of the inflector to no longer separate
- the words of an action with a dash:
- </para>
- <programlisting language="php"><![CDATA[
- $viewRenderer =
- Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
- $inflector = $viewRenderer->getInflector();
- $inflector->setFilterRule(':action', array(
- new Zend_Filter_PregReplace(
- '#[^a-z0-9' . preg_quote(DIRECTORY_SEPARATOR, '#') . ']+#i',
- ''
- ),
- 'StringToLower'
- ));
- ]]></programlisting>
- <para>
- The above code will modify the inflector to no longer
- separate the words with dash; you may also want to remove
- the 'StringToLower' filter if you <emphasis>do</emphasis>
- want the actual view script names camelCased as well.
- </para>
- <para>
- If renaming your view scripts would be too tedious or time
- consuming, this is your best option until you can find the
- time to do so.
- </para>
- </listitem>
- <listitem>
- <para>
- Least desirable option: You can force the dispatcher to
- dispatch camelCased action names with a new front controller
- flag, 'useCaseSensitiveActions':
- </para>
- <programlisting language="php"><![CDATA[
- $front->setParam('useCaseSensitiveActions', true);
- ]]></programlisting>
- <para>
- This will allow you to use camelCasing on the url and still
- have it resolve to the same action as when you use word
- separators. However, this will mean that the original issues
- will cascade on through; you will likely need to use the
- second option above in addition to this for things to work
- at all reliably.
- </para>
- <para>
- Note, also, that usage of this flag will raise a notice that
- this usage is deprecated.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.migration.fromzeroninethree">
- <title>Migrating from 0.9.3 to 1.0.0RC1 or Newer</title>
- <para>
- The principal changes introduced in 1.0.0RC1 are the introduction of
- and default enabling of the
- <link
- linkend="zend.controller.plugins.standard.errorhandler">ErrorHandler</link>
- plugin and the <link
- linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer</link>
- action helper. Please read the documentation to each thoroughly to
- see how they work and what effect they may have on your
- applications.
- </para>
- <para>
- The <code>ErrorHandler</code> plugin runs during
- <code>postDispatch()</code> checking for exceptions, and forwarding
- to a specified error handler controller. You should include such a
- controller in your application. You may disable it by setting the
- front controller parameter <code>noErrorHandler</code>:
- </para>
- <programlisting language="php"><![CDATA[
- $front->setParam('noErrorHandler', true);
- ]]></programlisting>
- <para>
- The <code>ViewRenderer</code> action helper automates view injection
- into action controllers as well as autorendering of view scripts
- based on the current action. The primary issue you may encounter is
- if you have actions that do not render view scripts and neither
- forward or redirect, as the <code>ViewRenderer</code> will attempt
- to render a view script based on the action name.
- </para>
- <para>
- There are several strategies you can take to update your code. In
- the short term, you can globally disable the
- <code>ViewRenderer</code> in your front controller bootstrap prior
- to dispatching:
- </para>
- <programlisting language="php"><![CDATA[
- // Assuming $front is an instance of Zend_Controller_Front
- $front->setParam('noViewRenderer', true);
- ]]></programlisting>
- <para>
- However, this is not a good long term strategy, as it means most
- likely you'll be writing more code.
- </para>
- <para>
- When you're ready to start using the <code>ViewRenderer</code>
- functionality, there are several things to look for in your
- controller code. First, look at your action methods (the methods
- ending in 'Action'), and determine what each is doing. If none of
- the following is happening, you'll need to make changes:
- </para>
- <itemizedlist>
- <listitem><para>Calls to <code>$this->render()</code></para></listitem>
- <listitem><para>Calls to <code>$this->_forward()</code></para></listitem>
- <listitem><para>Calls to <code>$this->_redirect()</code></para></listitem>
- <listitem><para>Calls to the <code>Redirector</code> action helper</para></listitem>
- </itemizedlist>
- <para>
- The easiest change is to disable auto-rendering for that method:
- </para>
- <programlisting language="php"><![CDATA[
- $this->_helper->viewRenderer->setNoRender();
- ]]></programlisting>
- <para>
- If you find that none of your action methods are rendering,
- forwarding, or redirecting, you will likely want to put the above
- line in your <code>preDispatch()</code> or <code>init()</code>
- methods:
- </para>
- <programlisting language="php"><![CDATA[
- public function preDispatch()
- {
- // disable view script autorendering
- $this->_helper->viewRenderer->setNoRender()
- // .. do other things...
- }
- ]]></programlisting>
- <para>
- If you are calling <code>render()</code>, and you're using <link
- linkend="zend.controller.modular">the Conventional Modular
- directory structure</link>, you'll want to change your code to
- make use of autorendering:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- If you're rendering multiple view scripts in a single
- action, you don't need to change a thing.
- </para>
- </listitem>
- <listitem>
- <para>
- If you're simply calling <code>render()</code> with no
- arguments, you can remove such lines.
- </para>
- </listitem>
- <listitem>
- <para>
- If you're calling <code>render()</code> with arguments, and
- not doing any processing afterwards or rendering multiple
- view scripts, you can change these calls to read
- <code>$this->_helper->viewRenderer()</code>.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- If you're not using the conventional modular directory structure,
- there are a variety of methods for setting the view base path and
- script path specifications so that you can make use of the
- <code>ViewRenderer</code>. Please read the <link
- linkend="zend.controller.actionhelpers.viewrenderer">ViewRenderer
- documentation</link> for information on these methods.
- </para>
- <para>
- If you're using a view object from the registry, or customizing your
- view object, or using a different view implementation, you'll want
- to inject the <code>ViewRenderer</code> with this object. This can
- be done easily at any time.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Prior to dispatching a front controller instance:
- </para>
- <programlisting language="php"><![CDATA[
- // Assuming $view has already been defined
- $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
- Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
- ]]></programlisting>
- </listitem>
- <listitem>
- <para>
- Any time during the bootstrap process:
- </para>
- <programlisting language="php"><![CDATA[
- $viewRenderer =
- Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
- $viewRenderer->setView($view);
- ]]></programlisting>
- </listitem>
- </itemizedlist>
- <para>
- There are many ways to modify the <code>ViewRenderer</code>,
- including setting a different view script to render, specifying
- replacements for all replaceable elements of a view script path
- (including the suffix), choosing a response named segment to
- utilize, and more. If you aren't using the conventional modular
- directory structure, you can even associate different path
- specifications with the <code>ViewRenderer</code>.
- </para>
- <para>
- We encourage you to adapt your code to use the
- <code>ErrorHandler</code> and <code>ViewRenderer</code> as they are
- now core functionality.
- </para>
- </sect2>
- <sect2 id="zend.controller.migration.fromzeroninetwo">
- <title>Migrating from 0.9.2 to 0.9.3 or Newer</title>
- <para>
- 0.9.3 introduces <link
- linkend="zend.controller.actionhelpers">action helpers</link>.
- As part of this change, the following methods have been removed as
- they are now encapsulated in the <link
- linkend="zend.controller.actionhelpers.redirector">redirector
- action helper</link>:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <code>setRedirectCode()</code>; use
- <classname>Zend_Controller_Action_Helper_Redirector::setCode()</classname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>setRedirectPrependBase()</code>; use
- <classname>Zend_Controller_Action_Helper_Redirector::setPrependBase()</classname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <code>setRedirectExit()</code>; use
- <classname>Zend_Controller_Action_Helper_Redirector::setExit()</classname>.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Read the <link linkend="zend.controller.actionhelpers">action
- helpers documentation</link> for more information on how to
- retrieve and manipulate helper objects, and the <link
- linkend="zend.controller.actionhelpers.redirector">redirector
- helper documentation</link> for more information on setting
- redirect options (as well as alternate methods for redirecting).
- </para>
- </sect2>
- <sect2 id="zend.controller.migration.fromzerosix">
- <title>Migrating from 0.6.0 to 0.8.0 or Newer</title>
- <para>
- Per previous changes, the most basic usage of the MVC components
- remains the same:
- </para>
- <programlisting language="php"><![CDATA[
- Zend_Controller_Front::run('/path/to/controllers');
- ]]></programlisting>
- <para>
- However, the directory structure underwent an overhaul, several
- components were removed, and several others either renamed or added.
- Changes include:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <classname>Zend_Controller_Router</classname> was removed in favor of
- the rewrite router.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Controller_RewriteRouter</classname> was renamed to
- <classname>Zend_Controller_Router_Rewrite</classname>, and promoted to
- the standard router shipped with the framework;
- <classname>Zend_Controller_Front</classname> will use it by default if
- no other router is supplied.
- </para>
- </listitem>
- <listitem>
- <para>
- A new route class for use with the rewrite router was
- introduced,
- <classname>Zend_Controller_Router_Route_Module</classname>; it covers
- the default route used by the MVC, and has support for <link
- linkend="zend.controller.modular">controller
- modules</link>.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Controller_Router_StaticRoute</classname> was renamed
- to <classname>Zend_Controller_Router_Route_Static</classname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Controller_Dispatcher</classname> was renamed
- <classname>Zend_Controller_Dispatcher_Standard</classname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <classname>Zend_Controller_Action::_forward()</classname>'s arguments
- have changed. The signature is now:
- </para>
- <programlisting language="php"><![CDATA[
- final protected function _forward($action,
- $controller = null,
- $module = null,
- array $params = null);
- ]]></programlisting>
- <para>
- <varname>$action</varname> is always required; if no controller is
- specified, an action in the current controller is assumed.
- <varname>$module</varname> is always ignored unless
- <varname>$controller</varname> is specified. Finally, any
- <varname>$params</varname> provided will be appended to the
- request object. If you do not require the controller or
- module, but still need to pass parameters, simply specify
- null for those values.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.controller.migration.fromzerotwo">
- <title>Migrating from 0.2.0 or before to 0.6.0</title>
- <para>
- The most basic usage of the MVC components has not changed; you can
- still do each of the following:
- </para>
- <programlisting language="php"><![CDATA[
- Zend_Controller_Front::run('/path/to/controllers');
- ]]></programlisting>
- <programlisting language="php"><![CDATA[
- /* -- create a router -- */
- $router = new Zend_Controller_RewriteRouter();
- $router->addRoute('user',
- 'user/:username',
- array('controller' => 'user', 'action' => 'info')
- );
- /* -- set it in a controller -- */
- $ctrl = Zend_Controller_Front::getInstance();
- $ctrl->setRouter($router);
- /* -- set controller directory and dispatch -- */
- $ctrl->setControllerDirectory('/path/to/controllers');
- $ctrl->dispatch();
- ]]></programlisting>
- <para>
- We encourage use of the Response object to aggregate content and
- headers. This will allow for more flexible output format switching
- (for instance, JSON or XML instead of XHTML) in your applications.
- By default, <code>dispatch()</code> will render the response, sending both
- headers and rendering any content. You may also have the front
- controller return the response using <code>returnResponse()</code>,
- and then render the response using your own logic. A future version
- of the front controller may enforce use of the response object via
- output buffering.
- </para>
- <para>
- There are many additional features that extend the existing API,
- and these are noted in the documentation.
- </para>
- <para>
- The main changes you will need to be aware of will be found when
- subclassing the various components. Key amongst these are:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <classname>Zend_Controller_Front::dispatch()</classname> by default
- traps exceptions in the response object, and does not render
- them, in order to prevent sensitive system information from
- being rendered. You can override this in several ways:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Set <code>throwExceptions()</code> in the front
- controller:
- </para>
- <programlisting language="php"><![CDATA[
- $front->throwExceptions(true);
- ]]></programlisting>
- </listitem>
- <listitem>
- <para>
- Set <code>renderExceptions()</code> in the response
- object:
- </para>
- <programlisting language="php"><![CDATA[
- $response->renderExceptions(true);
- $front->setResponse($response);
- $front->dispatch();
- // or:
- $front->returnResponse(true);
- $response = $front->dispatch();
- $response->renderExceptions(true);
- echo $response;
- ]]></programlisting>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem><para>
- <classname>Zend_Controller_Dispatcher_Interface::dispatch()</classname>
- now accepts and returns a <xref linkend="zend.controller.request" />
- object instead of a dispatcher token.
- </para></listitem>
- <listitem><para>
- <classname>Zend_Controller_Router_Interface::route()</classname>
- now accepts and returns a <xref linkend="zend.controller.request" />
- object instead of a dispatcher token.
- </para></listitem>
- <listitem>
- <para><classname>Zend_Controller_Action</classname> changes include:</para>
- <itemizedlist>
- <listitem><para>
- The constructor now accepts exactly three arguments,
- <classname>Zend_Controller_Request_Abstract $request</classname>,
- <classname>Zend_Controller_Response_Abstract $response</classname>,
- and <code>array $params (optional)</code>.
- <classname>Zend_Controller_Action::__construct()</classname> uses
- these to set the request, response, and invokeArgs
- properties of the object, and if overriding the
- constructor, you should do so as well. Better yet, use
- the <code>init()</code> method to do any instance
- configuration, as this method is called as the final
- action of the constructor.
- </para></listitem>
- <listitem><para>
- <code>run()</code> is no longer defined as final, but is
- also no longer used by the front controller; its sole
- purpose is for using the class as a page controller. It
- now takes two optional arguments, a
- <classname>Zend_Controller_Request_Abstract $request</classname>
- and a <classname>Zend_Controller_Response_Abstract $response</classname>.
- </para></listitem>
- <listitem><para>
- <code>indexAction()</code> no longer needs to be
- defined, but is encouraged as the default action. This
- allows using the RewriteRouter and action controllers to
- specify different default action methods.
- </para></listitem>
- <listitem><para>
- <code>__call()</code> should be overridden to handle any
- undefined actions automatically.
- </para></listitem>
- <listitem><para>
- <code>_redirect()</code> now takes an optional second
- argument, the HTTP code to return with the redirect, and
- an optional third argument, <varname>$prependBase</varname>,
- that can indicate that the base URL registered with the
- request object should be prepended to the url specified.
- </para></listitem>
- <listitem>
- <para>
- The <code>_action</code> property is no longer set. This property was a
- <classname>Zend_Controller_Dispatcher_Token</classname>,
- which no longer exists in the current incarnation.
- The sole purpose of the token was to provide
- information about the requested controller, action,
- and URL parameters. This information is now
- available in the request object, and can be accessed
- as follows:
- </para>
- <programlisting language="php"><![CDATA[
- // Retrieve the requested controller name
- // Access used to be via: $this->_action->getControllerName().
- // The example below uses getRequest(), though you may also directly
- // access the $_request property; using getRequest() is recommended as
- // a parent class may override access to the request object.
- $controller = $this->getRequest()->getControllerName();
- // Retrieve the requested action name
- // Access used to be via: $this->_action->getActionName().
- $action = $this->getRequest()->getActionName();
- // Retrieve the request parameters
- // This hasn't changed; the _getParams() and _getParam() methods simply
- // proxy to the request object now.
- $params = $this->_getParams();
- // request 'foo' parameter, using 'default' as default value if not found
- $foo = $this->_getParam('foo', 'default');
- ]]></programlisting>
- </listitem>
- <listitem>
- <para>
- <code>noRouteAction()</code> has been removed. The
- appropriate way to handle non-existent action
- methods should you wish to route them to a default
- action is using <code>__call()</code>:
- </para>
- <programlisting language="php"><![CDATA[
- public function __call($method, $args)
- {
- // If an unmatched 'Action' method was requested, pass on to the
- // default action method:
- if ('Action' == substr($method, -6)) {
- return $this->defaultAction();
- }
- throw new Zend_Controller_Exception('Invalid method called');
- }
- ]]></programlisting>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem><para>
- <classname>Zend_Controller_RewriteRouter::setRewriteBase()</classname> has
- been removed. Use <classname>Zend_Controller_Front::setBaseUrl()</classname>
- instead (or <classname>Zend_Controller_Request_Http::setBaseUrl()</classname>, if
- using that request class).
- </para></listitem>
- <listitem><para>
- <classname>Zend_Controller_Plugin_Interface</classname> was replaced
- by <classname>Zend_Controller_Plugin_Abstract</classname>. All methods now
- accept and return a <xref linkend="zend.controller.request" />
- object instead of a dispatcher token.
- </para></listitem>
- </itemizedlist>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|