2012-07-20 17 views
8

thisと非常によく似たやり方をしたいのですが、AJAXリクエストのCakePHPの世界です。現時点では私はこれをやっている:CakePHPでのAjaxエラー処理

$this->autoRender = false; 
$this->response->statusCode(500); 

それはthisのオフに基づいています。しかし、この解決策は私のクライアント側のエラーハンドラで、私は500エラー応答に含まれているメッセージを表示することができますように、私はレールの例のようなカスタムメッセージを含めることができません。

Ruby on Railsの例のようにCakePHPに同じ機能を実装するにはどうすればよいですか?

答えて

0
クックブックで説明したようにあなたがCakeExceptionsを使用することができます

:カスタムメッセージを使用したい場合、私は本番モード:(でdebug = 1を使用するより他に方法が見つからないhttp://book.cakephp.org/2.0/en/development/exceptions.htmlしかし

が組み込まれてここに私のアプローチです方法:お使いのコントローラで

if($this->request->is('ajax')){ 
    Configure::write('debug', 1); 
} 

if(!$allowed) { 
    throw new InternalErrorException('Keep your fingers away from me!'); // 500 error 
} 

変更AJAXで使用される誤差が、出力何もエラーテンプレートは/app/View/Errors/error500.ctp:

<?php 
if($this->request->is('ajax')): 
    // Output for AJAX calls 
    echo $name; 

else: 
    //Standard CakePHP output ?> 
    <h2><?php echo $name; ?></h2> 
    <p class="error"> 
     <strong><?php echo __d('cake', 'Error'); ?>: </strong> 
     <?php echo __d('cake', 'An Internal Error Has Occurred.'); ?> 
    </p> 
    <?php 
    if (Configure::read('debug') > 0): 
     echo $this->element('exception_stack_trace'); 
    endif; 

endif; ?> 

にあなたは、あなたのAJAXで返されたテキストを解析することができます呼び出します。

//... 
error: function (request) { 
    yourErrorShowingFunction(_this, request.responseText); 
} 
//... 

希望は、このことができます:)

を誰もが(デバッグモードを上書きせずに)生産モードでカスタムエラーを使用する方法のアイデアを持っている場合、私は次のようになります。ここで私が使用してjQueryのパーツです非常に幸せ!

+0

デバッグモードになってから私が望んでいた答えではありませんでしたが、他の誰もこれについて考えているようではないので、正しいとマークします。努力をいただきありがとうございます! –

2

また、私の場合、jaxeryリクエスト(jquery mobile)を使用する際に、カスタム例外とエラーコードで苦労しました。ここで私が思いついた解決策は、デバッグモードを上書きすることなく。開発モードで、またオプションでプロダクションモードでカスタムエラーをスローします。

AppExceptionRenderer.php:

<?php 
App::uses('ExceptionRenderer', 'Error'); 

class AppExceptionRenderer extends ExceptionRenderer 
{ 
    public function test($error) 
    { 
     $this->_sendAjaxError($error); 
    } 

    private function _sendAjaxError($error) 
    { 
     //only allow ajax requests and only send response if debug is on 
     if ($this->controller->request->is('ajax') && Configure::read('debug') > 0) 
     { 
      $this->controller->response->statusCode(500); 
      $response['errorCode'] = $error->getCode(); 
      $response['errorMessage'] = $error->getMessage(); 
      $this->controller->set(compact('response')); 
      $this->controller->layout = false; 
      $this->_outputMessage('errorjson'); 
     } 
    } 
} 

デバッグモードで例外を表示したい場合は、Configure::read('debug') > 0を残すことができます私はそれが誰かに役立ちます願っています。ビューerrorjson.ctpは、「Error/errorjson」にあります。CTP ':この場合

<?php 
echo json_encode($response); 
?> 

私の例外が呼び出され

TestException

のように定義されては、次のとおりです。私は、カスタムエラーコードを持って

<?php 
class TestException extends CakeException { 
    protected $_messageTemplate = 'Seems that %s is missing.'; 

    public function __construct($message = null, $code = 2) { 
     if (empty($message)) { 
        $message = 'My custom exception.'; 
      } 
      parent::__construct($message, $code); 
    } 
} 

2、$code = 2、私のjsonの応答のために。 Ajaxのレスポンスは、次のJSONデータでエラー500をキャストします:

{"errorCode":"2","errorMessage":"My custom exception."} 

を明らかに、あなたもあなたのコントローラから例外をスローする必要があります。

throw new TestException(); 

と例外レンダラーを含めhttp://book.cakephp.org/2.0/en/development/exceptions.html#using-a-custom-renderer-with-exception-renderer-to-handle-application-exceptions

これは範囲外ですが、JQueryでのajaxエラー応答を処理するために私は以下を使用します:

$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) { 
    //deal with my json error 
}); 
+0

非常にうまく動作します。ありがとう。 – MotsManish

7

上記のように、例外はCakePHPのAJAXリクエストでエラーを返す方法です。ここで私の解決策は、エラーがどのように見えるの細かい制御を得るためです。また、上記のように、カスタム例外レンダラーを使用していますが、カスタム例外は使用していません。デフォルトのエラー応答がJSONのこのようなオブジェクトである:デフォルトのレンダラはAJAXのエラーを処理する方法のような

{"name":"An Internal Error Has Occurred", "url": "\/users\/login.json"} 

I ほとんど

<?php 
// File: /app/Lib/Error/CustomExceptionRenderer.php 
App::uses('ExceptionRenderer', 'Error'); 
class CustomExceptionRenderer extends ExceptionRenderer { 

    // override 
    public function error400($error) { 
     $this->_prepareView($error, 'Not Found'); 
     $this->controller->response->statusCode($error->getCode()); 

     $this->_outputMessage('error400'); 
    } 

    // override 
    public function error500($error) { 
     $this->_prepareView($error, 'An Internal Error Has Ocurred.'); 
     $code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500; 
     $this->controller->response->statusCode($code); 

     $this->_outputMessage('error500'); 
    } 

    private function _prepareView($error, $genericMessage) { 
     $message = $error->getMessage(); 
     if(!Configure::read('debug') && !Configure::read('detailed_exceptions')) { 
      $message = __d('cake', $genericMessage); 
     } 
     $url = $this->controller->request->here(); 
     $renderVars = array(
      'name' => h($message), 
      'url' => h($url), 
      ); 
     if(isset($this->controller->viewVars['csrf_token'])) { 
      $renderVars['csrf_token'] = $this->controller->viewVars['csrf_token']; 
     } 
     $renderVars['_serialize'] = array_keys($renderVars); 
     $this->controller->set($renderVars); 
    } 
} 

その後、bootstrap.phpの中で:私はちょうどそれを少し微調整したいので、ここで

Configure::write('Exception.renderer', 'CustomExceptionRenderer'); 

は、それがどのように動作するかです:

  • は、私は新しいを返すようにしたいと言いますCSRFトークンが私のエラー応答に含まれているため、例外がスローされる前に既存のトークンが期限切れになった場合、次にリクエストを試みるときにブラックホールドになることはありません。 CSRF保護の詳細については、Security Component documentationを参照してください。
  • app/Lib/Errorに新しいクラスを作成します。デフォルトのレンダラーを拡張することも、拡張することもできません。私はちょっとしたことを少し変えたいだけで、例を単純にしておきたいので、私はそれを拡張しています。
  • 返されるJSONオブジェクトの作成にデフォルトのレンダラーが使用するメソッドをオーバーライドします。これはRequest Handler Componentで行い、ベストプラクティスに準拠しています。実際、デフォルトレンダラも同じことをしています。
  • 物事をDRYにするための新しいプライベートメソッド。
  • プロダクションでカスタムエラーメッセージが表示されないという問題を解決するには、オプションの構成キーを追加します。デフォルトでは、このクラスは本番での一般的なメッセージを表示しますが、デバッグが0に設定されていて、特定のエラーメッセージが必要な場合は、次のように指定します:Configure::write('detailed_exceptions', 1);
  • 応答に新しいトークンを追加します。私の場合は、AppControllerのbeforeFilterメソッドの新しいトークンで既にController::setを呼び出しているので、$this->controller->viewVarsで利用できます。おそらく、これを達成するために数十もの方法があります。

今、あなたの応答は次のようになります。

{ 
    "name":"The request has been black-holed", 
    "url":"\/users\/login.json", 
    "csrf_token":"1279f22f9148b6ff30467abaa06d83491c38e940" 
} 

任意のタイプの任意の追加データは、同じ結果をController::setに渡された配列に追加することができます。

+0

これは本当に私に多くの助けになります。 –