# 以前のバージョンからの移行

MVC コンポーネントの API は以前とは変更されました。 初期のバージョンから Zend Framework を使用しておられるかたは、 以下のガイドラインにしたがってスクリプトを変更し、 新しい仕組みに対応させてください。

## 1.7.x から 1.8.0 以降への移行

### 標準のルートの変更

新しい標準ルートでは翻訳セグメントが使用できるようになったため、 ルートのセグメントの先頭にある '@' は特殊文字と解釈されるようになりました。 この文字を静的セグメント内で使用するには、前にもうひとつ '@' をつけてエスケープする必要があります。 また、':' も同様です。

## 1.6.x から 1.7.0 以降への移行

### ディスパッチャインターフェイスの変更

ユーザからの指摘により、 `Zend_Controller_Action_Helper_ViewRenderer` が使っているディスパッチャ抽象クラスのメソッドの中で ディスパッチャインターフェイスに存在しないものがあることに気づきました。 次のメソッドを追加し、 自作のディスパッチャが同梱の実装と共存できるようにしています。

- `formatModuleName()`: リクエストオブジェクト内に格納されたりしている生のコントローラ名を受け取り、 それを再フォーマットして `Zend_Controller_Action` を継承した適切なクラス名にします。

## 1.5.x から 1.6.0 以降への移行

### ディスパッチャインターフェイスの変更

`Zend_Controller_Front` と `Zend_Controller_Router_Route_Module` は、ディスパッチャインターフェイスにないメソッドを使用していました。 次の 3 つのメソッドを追加し、 自作のディスパッチャが同梱の実装と共存できるようにしています。

- `getDefaultModule()`: デフォルトモジュールの名前を返します。

- `getDefaultControllerName()`: デフォルトコントローラの名前を返します。

- `getDefaultAction()`: デフォルトアクションの名前を返します。

## 1.0.x から 1.5.0 以降への移行

基本的な機能は同じでドキュメント化されている機能も変わりませんが、 ひとつだけ、ドキュメント化されていない "機能" が変更されました。

URL の書き方としてドキュメント化されている方法は、 camelCased 形式の名前のアクションを使用するために 単語の区切り文字を使用するというものです。デフォルトの区切り文字は '.' あるいは '-' ですが、ディスパッチャの設定で変更することができます。 ディスパッチャは内部でアクション名を小文字に変換し、 単語の区切り文字をもとに camelCasing 形式のアクションメソッド名を作成します。 しかし、PHP の関数名は大文字小文字を区別しないので、URL 自体を camelCasing 形式で書くこともできます。 この場合でも、ディスパッチャは URL を同じアクションメソッドに解決します。 たとえば 'camel-cased' はディスパッチャによって 'camelCasedAction' になります。一方 'camelCased' は 'camelcasedAction' となります。PHP では大文字小文字を細かく区別しないため、 これらはどちらも同じメソッドを実行することになります。

これは、ViewRenderer がビュースクリプトを解決する際に問題を引き起こします。 ドキュメントに記載されている正式な方法は、 単語の区切りをすべてダッシュに変換して単語は小文字にするというものです。 こうすればアクションとビュースクリプトの関連が明確になり、 小文字への正規化でスクリプトが見つかることが確実となります。 しかし、アクション 'camelCased' がコールされて解決された場合は、 単語の区切りはもう存在しません。そして ViewRenderer は `camel-cased.phtml` ではない別のファイル -- `camelcased.phtml` を探してしまうのです。

中にはこの "機能" を使用している開発者もいるようますが、 これは決して意図した機能ではありません。 1.5.0 のツリーでは、ViewRenderer はこの方式の解決を行わなくなりました。 これでアクションとビュースクリプトの結びつきが確実になったわけです。 まず、ディスパッチャはアクション名の大文字小文字をきちんと区別するようになります。 つまり、camelCasing 形式を使用したアクションの解決先は、 単語の区切りを使用した ('camel-casing') 場合とは違うものになるということです。 これで、ViewRenderer がビュースクリプトを解決する際には 区切り文字を使用したアクションのみを使用することになります。

今までこの "機能" に頼っていた人たちは、 以下のいずれかの方法で対応します。

- 一番いい方法: ビュースクリプトの名前を変更する。 利点: 前方互換性。欠点: もし対象となるビュースクリプトが多い場合は、 多くのファイルの名前を変更しなければならなくなります。

- その次にいい方法: ViewRenderer はビュースクリプトの解決を `Zend_Filter_Inflector` に委譲しています。 インフレクタのルールを変更し、 アクションの単語間をダッシュで区切らないようにします。

      $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'
      ));

  上のコードは、インフレクタを変更して単語をダッシュで区切らないようにしています。 もし実際のビュースクリプト名を camelCased にしたいのなら、さらに 'StringToLower' フィルタも削除することになるでしょう。

  ビュースクリプトの名前を変えるのが面倒だったり 時間がかかったりする場合は、 もしあまり時間を割けないのならこの方法が最適です。

- あまりお勧めしない方法: ディスパッチャに camelCased 形式のアクションをディスパッチさせるよう、フロントコントローラのフラグ useCaseSensitiveActions を設定します。

      $front->setParam('useCaseSensitiveActions', true);

  これで camelCasing 形式の URL を使えるようになり、 単語の区切り文字を使用した場合と同じアクションに解決されるようになります。 しかし、もともと抱えていた問題も残ったままとなってしまいます。 できれば先ほどのふたつのうちのいずれかを使用したほうがいいでしょう。

  このフラグを使用していると、 将来このフラグが廃止予定になったときに notice が発生することになります。

## 0.9.3 から 1.0.0RC1 以降への移行

1.0.0RC1 での最大の変更点は、 ErrorHandler プラグインと ViewRenderer アクションヘルパーが追加され、デフォルトで有効となったことです。 それぞれのドキュメントを熟読し、どのように動作するのかや 既存のアプリケーションに与える影響について確認しておきましょう。

`ErrorHandler` プラグインは `postDispatch()` で動作するもので、 例外をチェックして指定したエラーハンドラコントローラに転送します。 そのため、アプリケーション内にエラー処理用コントローラを含める必要があります。 このプラグインを無効にするには、フロントコントローラのパラメータ noErrorHandler を設定します。

    $front->setParam('noErrorHandler', true);

`ViewRenderer` アクションヘルパーは、 アクションコントローラへのビューの注入を自動的に行います。 また、現在のアクションにもとづいたビュースクリプトを自動的にレンダリングします。 ビュースクリプトをレンダリングせず、かつ転送やリダイレクトも行わないアクションがあった場合、 これは問題になるでしょう。というのも、 `ViewRenderer` はそんなアクションであっても アクション名をもとに自動的にビュースクリプトをレンダリングしようとするからです。

もし既存のコードにそのようなものがあった場合の対応方法はいくつか考えられます。 一番手っ取り早いのは、フロントコントローラの起動時に `ViewRenderer` を無効にしてからディスパッチを行うことです。

    // $front は Zend_Controller_Front のインスタンスであるとします
    $front->setParam('noViewRenderer', true);

しかし、長い目で見ればこれはあまりよい作戦ではありません。 今後も新しいコードを書き続けるならなおさらです。

`ViewRenderer` の機能を把握したら、コントローラのコードを見てみましょう。 まず、アクションメソッド (名前が 'Action' で終わっているメソッド) を探し、その中でどんな処理をしているかを確認しましょう。 もし次に挙げるいずれの内容も行っていない場合は、コードに手を加える必要があります。

- `$this->render();` のコール

- `$this->_forward();` のコール

- `$this->_redirect();` のコール

- `Redirector` アクションヘルパーのコール

一番簡単なのは、そのメソッド内で自動レンダリングを無効にすることです。

    $this->_helper->viewRenderer->setNoRender();

レンダリング、転送あるいはリダイレクトを行っているアクションメソッドがひとつもない場合は、 上で示したコードを `preDispatch()` メソッドあるいは `init()` メソッド内に書くといいでしょう。

    public function preDispatch()
    {
        // ビュースクリプトの自動レンダリングを無効にします
        $this->_helper->viewRenderer->setNoRender()
        // .. 何かほかのことをします...
    }

もしメソッド内で `render()` をコールしていて、 規約どおりのディレクトリ構造 を使用しているのなら、自動レンダリングを使用するようにコードを書き換えましょう。

- ひとつのアクションで複数のビュースクリプトをレンダリングしている場合は、 なにも変更する必要はありません。

- 何も引数を指定せずに `render()` をコールしている場合は、 その行を削除します。

- 引数つきで `render()` をコールしていて、 その後に何か処理をしたり複数のビュースクリプトを実行したりしていない場合は、 その行を `$this->_helper->viewRenderer();` のように変更します。

独自のディレクトリ構造を使用している場合は、 ビューの基底パスやスクリプトのパスをメソッドで設定してから `ViewRenderer` を使用します。これらのメソッドについての詳細は ViewRenderer のドキュメント を参照ください。

ビューオブジェクトをレジストリから取得していたり ビューオブジェクトをカスタマイズしていたり、 あるいはデフォルトとは異なるビューを使用している場合は、 そのオブジェクトを `ViewRenderer` に注入するために次のようにします。 これはいつでも好きなときに行えます。

- フロントコントローラのインスタンスをディスパッチする前なら

      // $view はすでに定義されているものとします
      $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
      Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);

- 起動処理の中ならどこでも

      $viewRenderer =
          Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
      $viewRenderer->setView($view);

`ViewRenderer` を変更するにはさまざまな方法があります。 たとえばレンダリングするビュースクリプトを別のものに変更したり ビュースクリプトパスの置換可能な要素（サフィックスを含む） を置換する内容を指定したり、使用するレスポンスセグメントを選択したりなどのことができます。 規約どおりのディレクトリ構造以外を使用する場合は、 `ViewRenderer` でのパスの決定方法を変更することもできます。

`ErrorHandler` および `ViewRenderer` は今やコア機能として組み込まれているので、 既存のコードについてもできるだけこれに適合するようにすることをお勧めします。

## 0.9.2 から 0.9.3 以降への移行

0.9.3 では アクションヘルパー が利用できるようになりました。この変更にともない、以下のメソッドが削除され、 リダイレクタ アクションヘルパー に組み込まれました。

- `setRedirectCode()` の代わりに `Zend_Controller_Action_Helper_Redirector::setCode()` を使用します。

- `setRedirectPrependBase()` の代わりに `Zend_Controller_Action_Helper_Redirector::setPrependBase()` を使用します。

- `setRedirectExit()` の代わりに `Zend_Controller_Action_Helper_Redirector::setExit()` を使用します。

ヘルパーオブジェクトの取得方法や操作方法についての詳細は アクションヘルパーのドキュメント を、 そしてリダイレクトの設定方法（新しいメソッドなど）についての詳細は リダイレクタ アクションヘルパーのドキュメント を参照ください。

## 0.6.0 から 0.8.0 以降への移行

前回変更された、もっとも基本的な MVC コンポーネントの使用法は、そのまま同じです。

    Zend_Controller_Front::run('/path/to/controllers');

しかし、ディレクトリ構造を見直し、いくつかのコンポーネントが削除されました。 また、名前が変更されたり新たに追加されたものもあります。以下にそれらをまとめます。

- `Zend_Controller_Router` は削除されました。 かわりに rewrite ルータを使用してください。

- `Zend_Controller_RewriteRouter` は `Zend_Controller_Router_Rewrite` という名前に変わり、 このフレームワークの標準ルータに格上げされました。 `Zend_Controller_Front` は、 特に別のルータを指定しない限りこのルータをデフォルトで使用します。

- rewrite ルータで使用する、新しいルートクラスが追加されました。名前は `Zend_Controller_Router_Route_Module` です。 これは MVC で使用するデフォルトのルートのほかに、コントローラモジュール をサポートしています。

- `Zend_Controller_Router_StaticRoute` は `Zend_Controller_Router_Route_Static` という名前に変わりました。

- `Zend_Controller_Dispatcher` は `Zend_Controller_Dispatcher_Standard` という名前に変わりました。

- `Zend_Controller_Action::_forward()` の引数が変わりました。 新しいシグネチャは次のとおりです。

      final protected function _forward($action,
                                        $controller = null,
                                        $module = null,
                                        array $params = null);

  `$action` は常に必須です。 コントローラを指定しなかった場合は、 現在のコントローラ内のアクションであるとみなされます。 `$controller` を指定しなかった場合は、 `$module` は常に無視されます。 最後に、`$params` で指定した任意の値が リクエストオブジェクトに追加されます。 コントローラやモジュールは不要だがパラメータは渡したいという場合は、 コントローラやモジュールに `NULL` を指定します。

## 0.2.0 以前のバージョンから 0.6.0 への移行

MVC コンポーネントの基本的な部分は変わっていません。 次のいずれの方法も使用可能です。

    Zend_Controller_Front::run('/path/to/controllers');

    /* -- ルータを作成します -- */
    $router = new Zend_Controller_RewriteRouter();
    $router->addRoute('user',
                      'user/:username',
                      array('controller' => 'user', 'action' => 'info')
    );

    /* -- ルータをコントローラに設定します -- */
    $ctrl = Zend_Controller_Front::getInstance();
    $ctrl->setRouter($router);

    /* -- コントローラのディレクトリを設定し、ディスパッチします -- */
    $ctrl->setControllerDirectory('/path/to/controllers');
    $ctrl->dispatch();

レスポンスオブジェクトを使用して、コンテンツとヘッダを取得することを推奨します。 これにより、アプリケーション内で より柔軟な出力書式の切り替え (たとえば XHTML ではなく JSON や XML を使用するなど) ができるようになります。 デフォルトでは、`dispatch()` はレスポンスのレンダリングを行い、 ヘッダとレンダリングされた内容の両方を送信します。 フロントコントローラから `returnResponse()` を使用してレスポンスを返し、レスポンスのレンダリングを独自に行うこともできます。 将来のバージョンのフロントコントローラでは、 レスポンスオブジェクトに出力バッファリングを使用する予定です。

これまでの API に加え、多くの機能が追加されています。 追加された機能についてはドキュメントを参照ください。

最大の変更点は、多くのコンポーネントで サブクラス化による拡張が可能になったことです。以下にポイントを整理します。

- `Zend_Controller_Front::dispatch()` は、デフォルトでレスポンスオブジェクトの例外をトラップします。 例外の内容はレンダリングしません。これにより、 システムについての機密情報がレンダリングされてしまうことを防ぎます。 この挙動を変更するにはいくつかの方法があります。

  - フロントコントローラで `throwExceptions()` を設定します。

        $front->throwExceptions(true);

  - レスポンスオブジェクトで `renderExceptions()` を設定します。

        $response->renderExceptions(true);
        $front->setResponse($response);
        $front->dispatch();

        // あるいは
        $front->returnResponse(true);
        $response = $front->dispatch();
        $response->renderExceptions(true);
        echo $response;

- `Zend_Controller_Dispatcher_Interface::dispatch()` は、ディスパッチャトークンではなく リクエストオブジェクト を使用するようになりました。

- `Zend_Controller_Router_Interface::route()` は、ディスパッチャトークンではなく リクエストオブジェクト を使用するようになりました。

- `Zend_Controller_Action` の変更点は以下のようになります。

  - コンストラクタが受け付ける引数は `Zend_Controller_Request_Abstract` `$request`、 `Zend_Controller_Response_Abstract` `$response` および array `$params` (オプション) の三つになりました。 `Zend_Controller_Action::__construct()` は、これらを使用してリクエストやレスポンス、 そしてオブジェクトの invokeArgs プロパティを指定します。 コンストラクタをオーバーライドすることで、 この挙動をお望みのように変更することができます。 さらによいことに、`init()` メソッドを使用してインスタンスの設定を自由に行うことができます。 このメソッドは、コンストラクタでの処理の最後にコールされます。

  - `run()` は final メソッドではなくなりました。 しかし、このメソッドはもはやフロントコントローラでは使用されません。 これは、クラスをページコントローラとして使用する場合にのみ使用します。 オプションの引数 `Zend_Controller_Request_Abstract` `$request` および `Zend_Controller_Response_Abstract` `$response` を受け取ります。

  - `indexAction()` を定義する必要はなくなりました。 しかし、デフォルトのアクションとして定義しておくことを推奨します。 これにより、RewriteRouter とアクションコントローラで デフォルトのアクションメソッドを別々に指定できるようになります。

  - `__call()` をオーバーライドして、 未定義のアクションが自動的に処理されるようにする必要があります。

  - `_redirect()` にはオプションで二番目、三番目の引数が追加されました。 二番目の引数はリダイレクト時に返す HTTP コードです。 三番目の引数 `$prependBase` を使用すると、リクエストオブジェクトに登録したベース URL を URL の前に連結することを指示できます。

  - プロパティ `$_action` は設定されなくなりました。 このプロパティの内容は `Zend_Controller_Dispatcher_Token` でしたが、これは現在のバージョンにはもう存在しません。 トークンの唯一の目的は、要求されたコントローラやアクション、 URL パラメータについての情報を提供することでした。 これらは現在はリクエストオブジェクトから次のようにして取得できるようになっています。

        // 要求されたコントローラ名を取得します。
        // その際には $this->_action->getControllerName() を使用します。
        // 以下の例では getRequest() を使用していますが、直接 $_request プロパティに
        // アクセスしてもかまいません。ただ getRequest() を使用することを推奨します。
        // とういのは、親クラスがこのメソッドをオーバーライドして挙動を変更しているかもしれないからです。
        $controller = $this->getRequest()->getControllerName();

        // 要求されたアクション名を取得します。
        // その際には $this->_action->getActionName() を使用します。
        $action = $this->getRequest()->getActionName();

        // リクエストパラメータを取得します。
        // これは変わっていません。_getParams() メソッドおよび _getParam() メソッドは
        // 現在は単なるリクエストオブジェクトへのプロキシです。
        $params = $this->_getParams();
        // パラメータ 'foo' を取得します。見つからなかった場合はデフォルト値 'default' を設定します
        $foo = $this->_getParam('foo', 'default');

  - `noRouteAction()` は削除されました。 存在しないアクションメソッドを扱うには、 `__call()` を使用してデフォルトのアクションに誘導します。

        public function __call($method, $args)
        {
            // 存在しない 'Action' メソッドが要求された場合に、
            // それをデフォルトのアクションに渡します。
            if ('Action' == substr($method, -6)) {
                return $this->defaultAction();
            }

            throw new Zend_Controller_Exception('無効なメソッド呼び出しです');
        }

- `Zend_Controller_RewriteRouter::setRewriteBase()` は削除されました。かわりに `Zend_Controller_Front::setBaseUrl()` を使用してください (あるいは、リクエストクラスを使用している場合は `Zend_Controller_Request_Http::setBaseUrl()` を使用します)。

- `Zend_Controller_Plugin_Interface` は `Zend_Controller_Plugin_Abstract` に置き換えられました。 すべてのメソッドは、ディスパッチャトークンではなく リクエストオブジェクト をやり取りするようになりました。