2016-06-30 5 views
2

PHP 7.0(Ubuntu 16.04)のSlim Frameworkを使用してREST APIを構築しています。 PHP 7.0の拡張Exceptionクラスで間違ったパラメータエラーが発生しました

namespace App\Exceptions; 

class AppException extends \Exception 
{ 

} 

は、それから私は、すべてのアプリケーション例外の基底例外としてこれを使用して次のように適切な例外処理のために、私は基本 \Exceptionクラスを拡張しました。
namespace App\Exceptions; 


use Slim\Container; 
use Slim\Http\Request; 
use Slim\Http\Response; 

class JsonApiException extends AppException 
{ 

    private $params = [ 
     "message" => "", 
     "code" => 0, 
     "previous" => null, 
     "api" => [ 
      "message" => "", 
      "code" => "", 
      "status" => 200 
     ] 
    ]; 

    public function __construct(array $params) 
    { 
     $this->params = array_merge_recursive($this->params, $params); 
     parent::__construct($this->params["message"], 0, $this->params["previous"]); 
    } 

    public function getApiMessage() { 
     return $this->params["api"]["message"]; 
    } 

    public function getApiCode() { 
     return $this->params["api"]["code"]; 
    } 

    public function getHttpStatusCode() { 
     return $this->params["api"]["status"]; 
    } 

    public function shouldBeLogged() { 
     return false; 
    } 

    public function log(Container $container, Request $request) { 
     if(!$this->shouldBeLogged()) return; 
     $logger = $container->get('logger.info'); 
     $logger->info($this, array_merge($request->getHeaders(), [ 
      "method" => $_SERVER["REQUEST_METHOD"], 
      "time" => $_SERVER["REQUEST_TIME"], 
      "query_string" => $_SERVER["QUERY_STRING"], 
      "host" => $_SERVER["HTTP_HOST"], 
      "referer" => $_SERVER["HTTP_REFERER"], 
      "user_agent" => $_SERVER["HTTP_USER_AGENT"], 
      "ip" => $_SERVER["REMOTE_ADDR"], 
      "uri" => $_SERVER["REQUEST_URI"] 
     ])); 
    } 

    public function httpRespond(Response $response) { 
     return $response->withJson([ 
      "error" => true, 
      "errors" => [ 
       "server" => [[ 
        "code" => $this->getApiCode(), 
        "message" => $this->getApiMessage() 
       ]] 
      ] 
     ], $this->getHttpStatusCode()); 
    } 

} 

は、その後、私はすべてのJSONのエラーのためのベース例外としてこれを使用する:JSONレスポンスを持っているすべての例外がユーザーに付与するために、私は別のクラスを書きました。私は、次のエラーを使用して、登録のために提供した電子メールアドレスがすでに存在することをクライアントに知らせます。

namespace App\Exceptions\Validation\User; 

use App\Exceptions\JsonApiException; 

class EmailAlreadyUsedException extends JsonApiException 
{ 

    public function __construct() 
    { 
     parent::__construct([ 
      "message" => "The e-mail provided by the exception has already been used", 
      "api" => [ 
       "message" => "The provided e-mail address has already been used", 
       "code" => "EmailAlreadyUsed" 
      ], 
      "previous" => null 
     ]); 
    } 

} 

エラーが発生するたびに、私は検証中に、一度に複数のエラーで応答可能にするために、別のカスタム例外に追加します。

namespace App\Exceptions; 


use Slim\Http\Response; 

class JsonApiMultipleException extends JsonApiException 
{ 

    private $httpStatusCode = 200; 
    private $exceptions = []; 

    public function __construct($httpStatusCode = 200, \Exception $previous = null) 
    { 
     parent::__construct([]); 
     $this->httpStatusCode = 200; 
    } 

    public function setHttpStatusCode(int $code) { 
     $this->httpStatusCode = $code; 
    } 

    public function add(string $param, JsonApiException $exception) { 
     if(!array_key_exists($param, $this->exceptions)) { 
      $this->exceptions[$param] = []; 
     } 
     $this->exceptions[$param][] = $exception; 
    } 

    public function length() { 
     $len = 0; 
     foreach ($this->exceptions as $param => $exceptions) { 
      $len += count($exceptions); 
     } 
     return $len; 
    } 

    public function map() { 
     $mapped = []; 
     foreach ($this->exceptions as $param => $exceptions) { 
      $mapped[$param] = array_map(function (JsonApiException $exception) { 
       return [ 
        "code" => $exception->getApiCode(), 
        "message" => $exception->getApiMessage() 
       ]; 
      }, $exceptions); 
     } 
     return $mapped; 
    } 

    public function getExceptions() { 
     return $this->exceptions; 
    } 

    public function httpRespond(Response $response) 
    { 
     return $response->withJson([ 
      "error" => true, 
      "errors" => $this->map() 
     ], $this->httpStatusCode); 
    } 

} 

しかし、私は検証中にこの例外をスロー():

namespace App\Validators; 

use App\Exceptions\Validation\User\EmailAlreadyUsedException; 
use App\Exceptions\Validation\User\InvalidEmailException; 
use App\Exceptions\Validation\User\InvalidFirstNameException; 
use App\Exceptions\Validation\User\InvalidLastNameException; 
use App\Exceptions\Validation\User\InvalidPasswordException; 
use Respect\Validation\Validator as v; 

class UserValidator extends Validator 
{ 

    //... 

    private function validateEmail() { 

     //Validate e-mail 
     if(!v::stringType()->email()->validate($this->user->getEmail())) { 
      $this->exception->add('email', new InvalidEmailException()); 
     } 

     //Check if e-mail already used 
     if(\UserQuery::create()->filterByEmail($this->user->getEmail())->count() > 0) { 
      $this->exception->add('email', new EmailAlreadyUsedException()); 
     } 
    } 

    //... 

} 

それは、次の例外がスローされます。

[Thu Jun 30 05:42:47 2016] Slim Application Error: 
Type: Error 
Message: Wrong parameters for App\Exceptions\Validation\User\EmailAlreadyUsedException([string $message [, long $code [, Throwable $previous = NULL]]]) 
File: /var/www/ElectroAbhi/app/Exceptions/JsonApiException.php 
Line: 33 
Trace: #0 /var/www/ElectroAbhi/app/Exceptions/JsonApiException.php(33): Exception->__construct(Array, 0, Array) 
#1 /var/www/ElectroAbhi/app/Exceptions/Validation/User/EmailAlreadyUsedException.php(19): App\Exceptions\JsonApiException->__construct(Array) 
#2 /var/www/ElectroAbhi/app/Validators/UserValidator.php(58): App\Exceptions\Validation\User\EmailAlreadyUsedException->__construct() 
#3 /var/www/ElectroAbhi/app/Validators/UserValidator.php(32): App\Validators\UserValidator->validateEmail() 
#4 /var/www/ElectroAbhi/app/Routes/API/User/Create.php(39): App\Validators\UserValidator->validate() 
#5 [internal function]: App\Routes\API\User\Create->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response), Array) 
#6 /var/www/ElectroAbhi/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php(41): call_user_func(Object(App\Routes\API\User\Create), Object(Slim\Http\Request), Object(Slim\Http\Response), Array) 
#7 /var/www/ElectroAbhi/vendor/slim/slim/Slim/Route.php(325): Slim\Handlers\Strategies\RequestResponse->__invoke(Object(App\Routes\API\User\Create), Object(Slim\Http\Request), Object(Slim\Http\Response), Array) 
#8 /var/www/ElectroAbhi/vendor/slim/slim/Slim/MiddlewareAwareTrait.php(116): Slim\Route->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response)) 
#9 /var/www/ElectroAbhi/vendor/slim/slim/Slim/Route.php(297): Slim\Route->callMiddlewareStack(Object(Slim\Http\Request), Object(Slim\Http\Response)) 
#10 /var/www/ElectroAbhi/vendor/slim/slim/Slim/App.php(443): Slim\Route->run(Object(Slim\Http\Request), Object(Slim\Http\Response)) 
#11 /var/www/ElectroAbhi/vendor/slim/slim/Slim/MiddlewareAwareTrait.php(116): Slim\App->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response)) 
#12 /var/www/ElectroAbhi/vendor/slim/slim/Slim/App.php(337): Slim\App->callMiddlewareStack(Object(Slim\Http\Request), Object(Slim\Http\Response)) 
#13 /var/www/ElectroAbhi/vendor/slim/slim/Slim/App.php(298): Slim\App->process(Object(Slim\Http\Request), Object(Slim\Http\Response)) 
#14 /var/www/ElectroAbhi/public/index.php(105): Slim\App->run() 
#15 {main} 

私は実際にここで混乱しています。どのようにパラメータを取らないEmailAlreadyUsedExceptionにコンストラクタを実装したときに、定義をEmailAlreadyUsedException([string $message [, long $code [, Throwable $previous = NULL]]])として表示していますか?

UPDATE

私は[「メッセージ」]はJsonApiExceptionのコンストラクタで配列ですが、今はもっと混乱しているデバッグしようとした理由の$ this - > paramsはを見つける:

私は

parent::__construct([ 
      "message" => "The e-mail provided by the exception has already been used", 
      "api" => [ 
       "message" => "The provided e-mail address has already been used", 
       "code" => "EmailAlreadyUsed" 
      ], 
      "previous" => null 
     ]); 
0123を渡しているにもかかわらず> Array()

から

class JsonApiException extends AppException 
{ 

    private $params = [ 
     "message" => "", 
     "code" => 0, 
     "previous" => null, 
     "api" => [ 
      "message" => "", 
      "code" => "", 
      "status" => 200 
     ] 
    ]; 

    public function __construct(array $params) 
    { 
     print_r($params); 
     die; 
     $this->params = array_merge_recursive($this->params, $params); 
     parent::__construct($this->params["message"], 0, $this->params["previous"]); 
    } 

} 

結果

EmailAlreadyUsedExceptionからJsonApiExceptionのコンストラクタまで、$ params配列は空になっているようです。私は何かをもう一度見逃している?

答えて

0

長いデバッグセッションの後、障害はOOPの動作にはありませんでした。それは私がJsonApiExceptionのデフォルトのパラメータをマージするために使用していた機能にありました。 array_merge_recursiveの代わりにmerges the elements of one or more arrays together so that the values of one are appended to the end of the previous oneを使用する代わりに、array_replace_recursiveを使用しました。

Array 
(
    [message] => Array 
     (
      [0] => 
      [1] => The e-mail provided by the exception has already been used 
     ) 

    [code] => Array 
     (
      [0] => 0 
      [1] => 0 
     ) 

    [api] => Array 
     (
      [message] => Array 
       (
        [0] => 
        [1] => The provided e-mail address has already been used 
       ) 

      [code] => Array 
       (
        [0] => 
        [1] => EmailAlreadyUsed 
       ) 

      [status] => Array 
       (
        [0] => 200 
        [1] => 
       ) 

     ) 

) 

array_replace_recursiveを使用した場合、$ paramsはプロパティとなり、一方で:

Array 
(
    [message] => The e-mail provided by the exception has already been used 
    [code] => 0 
    [previous] => 
    [api] => Array 
     (
      [message] => The provided e-mail address has already been used 
      [code] => EmailAlreadyUsed 
      [status] => 200 
     ) 

) 

順番に提供

array_merge_recursiveを使用して、JsonApiExceptionの$ paramsはプロパティに値を割り当てられました正しいパラメータを\Exception::__construct()に設定してください。私はまだarray_replace_recursiveを補正する値を設定するため奇妙ですArray()を取得しています

class JsonApiException extends AppException 
{ 

    private $params = [ 
     "message" => "", 
     "code" => 0, 
     "previous" => null, 
     "api" => [ 
      "message" => "", 
      "code" => "", 
      "status" => 200 
     ] 
    ]; 

    public function __construct(array $params) 
    { 
     print_r($params); 
     die; 
     $this->params = array_replace_recursive($this->params, $params); 
     parent::__construct($this->params["message"], 0, $this->params["previous"]); 
    } 

} 

:私はこれを行うにしようとすると、それは、動作しますが、

ただ一つのことは、しかし奇妙です。

2

すべての例外クラスはparent::__constructとなります。つまり、最終的には、クラスコンストラクタ\Exceptionが呼び出されます。そのコンストラクタに正しいパラメータを指定していません。

あなたのスタックトレースから伝えることができます:

トレース:#0 /var/www/ElectroAbhi/app/Exceptions/JsonApiException.php(33):例外 - > __構築物(配列、0、アレイ)

あなたEmailAlreadyUsedExceptionはコンストラクタが期待するものではありません(Array, 0, Array)とPHPのネイティブ\Exceptionのコンストラクタを呼び出すJsonApiExceptionのコンストラクタを呼び出します。

あなたはこれらの2行を修正する必要があります。

$this->params = array_merge_recursive($this->params, $params); 
parent::__construct($this->params["message"], 0, $this->params["previous"]); 

どうやら、$this->params["message"]$this->params["previous"]が配列されています。しかし、あなたはparent::__constructに渡すparamsが[文字列$メッセージ[、ロング$コード[、Throwableの$前回= NULL]]]派生クラスのコンストラクタをオーバーライド

はありませんが、署名

と一致する必要があります親クラスのコンストラクタをオーバーライドしないでください。

+0

しかし、私は 'JsonApiException'から' \ Exception'のコンストラクタに正しいパラメータを渡していますか?コンストラクタをオーバーライドすると、そのコンストラクタの定義を変更できますか? –

+0

@abishekスタックトレースは、配列、数値、および配列を渡していることを示しています。これは、親コンストラクタのシグネチャとは異なるものです。派生クラスのコンストラクタをオーバーライドしても、親クラスのコンストラクタはオーバーライドされません。 – Gordon

+0

'$ this-> params [" message "]'がコンストラクタの配列であり、まったく新しい結果を得た理由をデバッグしようとしました。私の更新を確認してください。 –

関連する問題