How to catch DB exception when overriding actionCreate in Yii2 RESTful API? - rest

I'm using the Yii2 RESTful API implementation.
This is a good start: http://budiirawan.com/setup-restful-api-yii2/
I'm overriding the CREATE method with my own action:
public function actionCreate(){
$params = $_REQUEST;
if (!empty($params["name"]) && !empty($params["code"])) {
$model = new $this->modelClass;
foreach ($params as $key => $value) {
if (!$model->hasAttribute($key)) {
throw new \yii\web\HttpException(400, 'Invalid attribute:' . $key);
}
}
$model->attributes=$params;
try {
$model->save();
} catch (CDbException $ex) {
// ... NEVER REACH THIS POINT :-(
throw new \yii\web\HttpException(405, 'Error saving model');
} catch (Exception $ex) {
// ... NEVER REACH THIS POINT :-(
throw new \yii\web\HttpException(405, 'Error saving model');
}
} else {
throw new \yii\web\HttpException(400, 'No data input');
}
}
The problem is when the model is trying to be saved, in my case there is an "Integrity constraint violation" in my database.
What I would like is to handle that error and run my "catch", but I don't know how to "catch" that error, because Yii is "taking control" of that error and throw a 500 error as response.
How can I handle the "model save" errors ?

Yii2 does not have CDbException. To catch all db related exceptions you need to catch(\yii\db\Exception $e){...} and to catch any other exceptions catch(\Exception $e){...}
You are catching two exceptions but they do the same thing so just
catch(\Exception $e){
throw new \yii\web\HttpException(405, 'Error saving model');
}
\Exception is basic php exception class from which all yii2 exceptions inherited

Related

PowerShell Try/Catch with If Statements

Problem/Details
I am working in PowerShell and trying to figure out how custom Try Catch statements work. My current major issue involves mixing Try/Catch and If statements. So the idea of what I am trying to achieve is something like this:
try {
if (!$someVariable.Text) { throw new exception 0 }
elseif ($someVariable.Text -lt 11) { throw new exception 1 }
elseif (!($someVariable.Text -match '[a-zA-Z\s]')) { throw new exception 2}
}
catch 0 {
[System.Windows.Forms.MessageBox]::Show("Custom Error Message 1")
}
catch 1 {
[System.Windows.Forms.MessageBox]::Show("Custom Error Message 2")
}
catch 2 {
[System.Windows.Forms.MessageBox]::Show("Custom Error Message 3")
}
Now I know the above code is very inaccurate in terms of what the actual code will be, but I wanted to visually display what I'm thinking and trying to achieve.
Question
Does anyone know how to create custom error messages with PowerShell that could assist me with achieving something close to the above idea and explain your answer a bit? Thank you in advance
So far, the link below is the closest thing I have found to what I'm trying to achieve:
PowerShell Try, Catch, custom terminating error message
The Error you throw is stored at $_.Exception.Message
$a = 1
try{
If($a -eq 1){
throw "1"
}
}catch{
if ($_.Exception.Message -eq 1){
"Error 1"
}else{
$_.Exception.Message
}
}
I would suggest using the $PSCmdlet ThrowTerminatingError() method. Here's an example:
Function New-ErrorRecord
{
param(
[String]$Exception,
[String]$ExceptionMessage,
[System.Management.Automation.ErrorCategory] $ErrorCategory,
[String] $TargetObject
)
$e = New-Object $Exception $ExceptionMessage
$errorRecord = New-Object System.Management.Automation.ErrorRecord $e, $ErrorID, $ErrorCategory, $TargetObject
return $ErrorRecord
}
Try
{
If (not condition)
{
$Error = #{
Exception = 'System.Management.Automation.ParameterBindingException'
ExceptionMessage = 'Error text here'
ErrorCategory = [System.Management.Automation.ErrorCategory]::InvalidArgument
TargetObject = ''
}
$PSCmdlet.ThrowTerminatingError((New-ErrorRecord #Error))
}
} Catch [System.Management.Automation.ParameterBindingException]
{
'do stuff'
}

Powershell throw exceptions with data

How to use 'throw' direction in PowerShell to throw an exception with custom data object?
Say, could it do this?:
throw 'foo', $myData
then the data can be used in 'catch' logic:
catch {
if ($_.exception.some_property -eq 'foo') {
$data = $_.exception.some_field_to_get_data
# dealing with data
}
}
edited:
My intention is to know is there a brief and cool syntax to throw an exception (without explicitly creating my own type) with a name that I can decide by its name and deal with its data in the 'catch' blocks.
You can throw any kind of System.Exception instance (here using a XamlException as an example):
try {
$Exception = New-Object System.Xaml.XamlException -ArgumentList ("Bad XAML!", $null, 10, 2)
throw $Exception
}
catch{
if($_.Exception.LineNumber -eq 10){
Write-Host "Error on line 10, position $($_.Exception.LinePosition)"
}
}
If you're running version 5.0 or newer of PowerShell, you can use the new PowerShell Classes feature to define custom Exception types:
class MyException : System.Exception
{
[string]$AnotherMessage
[int]$SomeNumber
MyException($Message,$AnotherMessage,$SomeNumber) : base($Message){
$this.AnotherMessage = $AnotherMessage
$this.SomeNumber = $SomeNumber
}
}
try{
throw [MyException]::new('Fail!','Something terrible happened',135)
}
catch [MyException] {
$e = $_.Exception
if($e.AnotherMessage -eq 'Something terrible happened'){
Write-Warning "$($e.SomeNumber) terrible things happened"
}
}

ZF2 application - Dispatch error event triggered every time

I'am working on a Zend Framework 2 application and have a strange behavior concerning error handling. My code in Module.php:
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$eventManager->attach(\Zend\Mvc\MvcEvent::EVENT_ROUTE, [$this, 'onPreRoute'], 100);
$eventManager->attach(\Zend\Mvc\MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'handleError']);
}
public function onPreRoute(MvcEvent $e)
{
$serviceManager = $e->getTarget()->getServiceManager();
$router = $serviceManager->get('router');
$router->setTranslator($serviceManager->get('translator'));
}
public function handleError(MvcEvent $e)
{
$error = $e->getParam('error');
file_put_contents('error.log', $error . PHP_EOL, FILE_APPEND);
switch($error) {
case 'error-router-no-match':
$router = $e->getRouter();
$url = $router->assemble([], ['name' => 'home']);
header('Location: ' . $url);
exit;
}
}
As you can see I'am translating the routes. This works fine. But on every request the dispatch error event is triggered too. The error.log file will be created every time. But the redirect will be only performed if the route doesn't really exist. I think it depends on the translator or is my code in Module.php not correct?
Resolved!
The reason was that the browser automatically requests /favicon.ico and that was not available :-)

Slim 3 blackholing errors

I have a small slim 3 app, and when I throw an exception slim simply shows the generic error message:
Slim Application Error
A website error has occurred. Sorry for the temporary inconvenience.
In slim 2 you can do something like this to turn on debug mode giving you backtraces etc:
$app->config('debug', true);
In slim 3 there doesn't seem to be one. Additionally, it seems to be overriding my exception and error handlers.
How can I get slim to spit out errors, or at least to call my error handlers (Which pipe the output to kint for debug information)
Looking through the source, it's possible to initialize slim 3 with error display like so:
$app = new \Slim\App(['settings' => ['displayErrorDetails' => true]]);
I'm not sure if it's possible to change this setting after the fact without replacing the errorHandler altogether.
To show full stack trace on default exception handler use what j-v said.
If you want to handle exceptions in Slim yourself then you need to override Slim's default exception handler as it will be used before your "not in Slim" error handler:
$app = new \Slim\App();
$container = $app->getContainer();
$container['errorHandler'] = function(ServerRequestInterface $request, ResponseInterface $response, Exception $exception) {
//Handle exception here
}
Error handling is rather well documented: Official Docs
$app = new \Slim\App();
$c = $app->getContainer();
$c['errorHandler'] = function ($c) {
return function ($request, $response, $exception) use ($c) {
return $c['response']->withStatus(500)
->withHeader('Content-Type', 'text/html')
->write('Something went wrong!');
};
};
Error handling is best solution to this. You can do something like to see Error Trace
$app = new \Slim\App();
$container = $app->getContainer();
$container['phpErrorHandler'] = $container['errorHandler'] = function ($c) {
return function ($request, $response, $exception) use ($c) {
return $c['response']->withStatus(500)
->withHeader('Content-Type', 'text/html')
->write('Something went wrong!<br><br>' .
nl2br($error->getTraceAsString()));
};
};
Make displayErrorDetails->true.
You will find cause of error.
$config = ['settings' => [
'addContentLengthHeader' => true,
'displayErrorDetails' => true
]];
$app = new \Slim\App($config)

Fatal error: Uncaught OAuthException: An active access token must be used to query information about the current user. thrown in

with my app's administrator acount on facebook my app work normally, but with other app I get error: Fatal error: Uncaught OAuthException: An active access token must be used to query information about the current user. What's wrong here? I tried many ways using different guides but does not return true results .Help me, please if you can, Thank you very much.
My code here :
//$return_url = loginFacebook;
$this->load->library('facebook', $this->app_config);
parse_str($_SERVER['QUERY_STRING'], $_GET);
if (isset($_GET['code'])) {
if (isset($_GET['code']) && !isset($_GET['error'])) {
$user = $this->facebook->getUser();
if($user){
try{
$fb_user = $this->facebook->api('/me?fields=email,username,name,picture');
//print_r('<pre>');print_r($fb_user);die;
if (!$fb_user) {
show_error('invalid access_token');
}
if(!isset($fb_user['email'])) {
show_error('invalid facebook account');
}
// do somthing here
$this->load->view('login_success',$array);
}
}catch (FacebookApiException $e) {
echo $e->getMessage();
}
} else {
echo "Could not log in with Facebook";
}
} else if ($_GET['error']) {
show_error('user denied!!!');
}
} else {
$log = array(
'scope' => $this->scope,
'redirect_uri' => $return_url
);
if(strlen(store()) > 1) $log['display'] = 'popup';
else $log['display'] = 'wap';
$loginUrl = $this->facebook->getLoginUrl($log);
header("Location: $loginUrl");
}