Handle Mysql Error with same Error number - php

I've a question.
I need to handle the Mysql error (like duplicate key, foreign constraints...) for example:
$id=$db->insert ('user', $data);
if(!$id){
switch($db->getLastErrno()){
throw new Exception(... );
}
}
Here i use error number to select the right Exception.
But for the same error, what i've to do?
I think to use error string, for example:
if($db->getLastErrno()==1452 && strpos($db->getLastError(), "contraint name created on db")>-1){
throw new Exception(... );
}
But i don't know why, i think it's a little bit trash. Does anyone have other solutions?

Put the if statement inside the case. You don't need to repeat the error number test.
switch ($db->getLastErrno()) {
case 1452:
if (strpos($db->getLastError(), "constraint name created on db") !== false) {
throw new Exception(...);
}
break;
...
}

Related

Exceptions - what is "exceptional"?

I've read that exceptions shouldn't be used for directing the flow of your application but should be used to recover the application to a stable state when something "exceptional" happens, for example, when you fail to connect to a database.
An example of where an exception shouldn't be used would be a user providing an incorrect login. It wouldn't be an exception since it's expected that that will happen.
I'm not sure whether the following case is exceptional or not:
I'm currently designing a simple blog. A "post" is assigned to just one "category". In my posts table I have a category_id field with a foreign key constraint.
Now, I'm using Laravel so if I try to delete a category that currently has posts in it, I believe it should throw an \Illuminate\Database\QueryException because of the foreign key constraint. Therefore should I rely on this and write code like:
try {
$category->delete();
}
catch (\Illuminate\Database\QueryException $e) {
// Tell the user that they can't delete the category because there are posts assigned to it
}
or since I know how I want my blog to work, should I use:
if ($category->posts->isEmpty()) {
$category->delete();
}
else {
// Tell the user they can't delete...
}
Any advice would be appreciated. Thanks!
It is very opinion based, so i'll give you my opinion:
Exceptions are powerfull, because you can attach a lot of information with it - and you can send them "up the callstack" without having hundrets of methods checking the return value of any call and returning whatever to their own caller.
This allows you to easily handle an error at the desired layer in the callstack.
A Method should return, what is the result of the call (even if it's void). If the call fails for any reason, there should be no return value.
Errors should not be transported by returnvalues, but with exceptions.
Imagine a function doing db-queries: KeyAlreadyExistsException, InvalidSyntaxException and NullPointerException - most likely you want to handle this "errors" at very different parts in your code.
(One is a code-error, one is a query-error, one is a logical-error)
Example one, easy "handling":
try{
method1(1);
}catch (Exception $e){
//Handle all but NullpointerExceptions here.
}
---
method1($s){
try{
method2($s+2);
} catch (NullPointerException $e){
//only deal with NPEs here, others bubble up the call stack.
}
}
---
method2($s){
//Some Exception here.
}
Example two - you see the required "nesting", and the stack-depth is only 2 here.
$result = method1(1);
if ($result === 1){
//all good
}else{
//Handle all but NullpointerExceptions here.
}
---
method1($s){
$result = method2($s+2);
if ($result === 1){
return $result;
}else{
if ($result === "NullPointerException"){
//do something
}
}
method2($s){
//Exception here.
}
Especially for maintainance, Exceptions have huge advantages: If you add a new "Exception" - the worstcase will be an unhandled exception, but code execution will break.
If you add new "return errors", you need to make sure, that every Caller is aware of these new errors:
function getUsername($id){
// -1 = id not found
$name = doQuery(...);
if (id not found) return -1;
else return $name;
}
vs
function getUsername($id){
$name = doQuery(...);
if (id not found) throw new IdNotFoundException(...);
return $name;
}
Now consider the handling in both cases:
if (getUsername(4)=== -1) { //error } else { //use it }
vs
try{
$name = getUsername(4);
//use it
}catch (IdNotFoundException $e){
//error
}
And now, you add the return code -2: First way would assume the username to be -2, until the error code is implemented. Second way (Another Exception) would cause the execution to stop with an unhandled exception somewhere way up in the callstack.
Dealing with return values (of any kind) for error-transportation is error prone and errors might vanish somewhere, turning into a "wrong" interpreted result.
Using exceptions is safer: You either have a return value to use, or a (handled or unhandled) exception, but no "wrong values" due to autocasts etc.

Doctrine2 insert fails silently, only on certain records

I have the following code which results sometimes in a silent failure:
public function updateCoreGameTableIfNecessary($coreEm)
{
$game = $this->getCoreGameRecord($coreEm);
if (!$game) {
$game = new Game();
$game->setHomeSchool($this->getHomeSchool()->getCoreSchool($coreEm));
$game->setDatetime($this->getDatetime()->format('Y-m-d H:i:s'));
$game->setDate($this->getDatetime()->getTimestamp());
$game->setTime($this->getDatetime()->format('H:i:s'));
$game->setSport($coreEm->getRepository('VNNCoreBundle:Sport')->findOneByName($this->getSport()->getName()));
$game->setSeason($coreEm->getRepository('VNNCoreBundle:Season')->findCurrent());
$game->setEventType(strtolower($this->getEventType()->getName()));
$game->setMeetName($this->getMeetName());
$game->setRemoteUnique(md5(rand(0, 100000)));
$game->setNotes($this->getRecap());
$game->setHomeConfId(0); // This field is no longer used, so value doesn't matter.
$game->setAwayConfId(0); // This field is no longer used, so value doesn't matter.
$game->setConfStatus(''); // This field is going away as well.
}
if ($this->getEventType()->getName() == 'Game') {
$game->setHomeScore($this->getHomeScore());
$game->setAwayScore($this->getAwayScore());
$game->setAwaySchool($this->getAwaySchool()->getCoreSchool($coreEm));
} else {
$game->setPlace($this->getPlace());
$game->setPoints($this->getHomeScore());
}
$game->setOwnerId($this->getUser()->getSchool()->getCoreSchool($coreEm)->getId());
$coreEm->persist($game);
$coreEm->flush();
return $game->getId();
}
It always starts with a $this that's already saved. For certain instances of $this (i.e. certain records in the database), $game won't get saved. I won't get an error or anything like that. It will just fail silently.
Any suggestions for debugging? I guess I'll try to figure out what's different about those certain records, but it seems like an insert should never silently fail, for any reason.

What is the best way to check if table exists in DynamoDB?

What is the best way to check if table exists in DynamoDb?
I would appreciate it if the code would be in PHP.
Either active or not.
* Added later as an example to various cases for error code 400
It's very easy to check if the table exist, it can have one of the following
TableStatus => CREATING, ACTIVE, DELETING or UPDATING
but in case i get error 400 it can mean more than one thing.
1) sent null string as a table name by mistake.
[x-aws-body] => {"TableName":""}
)
[body] => CFSimpleXML Object
(
[__type] => com.amazon.coral.validate#ValidationException
[message] => The paramater 'tableName' must be at least 3 characters long and at most 255 characters long
)
[status] => 400
2) syntax error in the command sent to DynamoDB, for example writting tabel_name instead of table_name.
[x-aws-body] => {"TabelName":"test7"}
)
[body] => CFSimpleXML Object
(
[__type] => com.amazon.coral.validate#ValidationException
[message] => The paramater 'tableName' is required but was not present in the request
)
[status] => 400
3) I would guess but didn't check, if I exceed at that same time the provisioned capacity on the table.
You can have a look at "describe_table" of the official PHP SDK. 400 means "does not exist" There is a pretty extensive example in the official documentation. Look at how it is used in the "delete" example, right at the bottom.
http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/LowLevelPHPTableOperationsExample.html
Here is the (stripped) example from the doc
<?php
require_once dirname(__FILE__) . '/sdk/sdk.class.php';
$dynamodb = new AmazonDynamoDB();
$table_name = 'ExampleTable';
$response = $dynamodb->describe_table(array('TableName' => $table_name));
if((integer) $response->status !== 400)
{
$error_type = $response->body->__type;
$error_code = explode('#', $error_type)[1];
if($error_code == 'ResourceNotFoundException')
{
echo "Table ".$table_name." exists.";
}
}
?>
Some of these answers are using the older SDK's and so I thought I'd update this useful question with what I coded up and works well. The newer exceptions really do make this task easier. This function gives you a nice boolean to use in scripts.
use Aws\DynamoDb\Exception\ResourceNotFoundException; // <-- make sure this line is at the top
public function TableExists($tableName) {
$ddb = DynamoDbClient::factory(array('region' => 'us-east-1')); // EC2 role security
try {
$result = $ddb->describeTable(array(
"TableName" => $tableName
));
} catch (ResourceNotFoundException $e) {
// if this exception is thrown, the table doesn't exist
return false;
}
// no exception thrown? table exists!
return true;
}
Hopefully this complete working code helps some of you.
I think the answer that solves this with describeTable is a good one, but fooling around with the status code response makes the code less readable and more confusing.
I chose to check for a tables existence using listTables. Here are the docs
$tableName = 'my_table';
$client = DynamoDbClient::factory(array('region' => 'us-west-2'));
$response = $client->listTables();
if (!in_array($tableName, $response['TableNames'])) {
// handle non-existence.
// throw an error if you want or whatever
}
// handle existence
echo "Table " . $tableName . " exists";
With DynamoDB you need to parse the contents of the error message in order to know what type of error you received since the status code is almost always 400. Here is a sample function that could work to determine if a table exists. It also allows you to specify a status as well if you want to check if it exists and if it is in a certain state.
<?php
function doesTableExist(AmazonDynamoDB $ddb, $tableName, $desiredStatus = null)
{
$response = $ddb->describe_table(array('TableName' => $tableName));
if ($response->isOK()) {
if ($desiredStatus) {
$status = $response->body->Table->TableStatus->to_string();
return ($status === $desiredStatus);
} else {
return true;
}
} elseif ($response->status === 400) {
$error = explode('#', $response->body->__type->to_string());
$error = end($error);
if ($error === 'ResourceNotFoundException') {
return false;
}
}
throw new DynamoDB_Exception('Error performing the DescribeTable operation.');
}
Update: In the AWS SDK for PHP 2, specific exceptions are thrown by the DynamoDB client, making this way easier to handle. Also, there are "Waiter" objects, including one for this use case (see usage in the unit test) that is designed to sleep until the table exists.
The above answers are correct if you just want to know whether the table exist or not. I want to make another helpful point here in case.
One should be very careful in multi-threaded or production level code.
Assuming that one thread deleted the table, then you will still get the answer that the table exists in answer to your query from second thread, until the table is fully deleted. In such case, once the table is deleted, the table handle in second thread is zombie, like the dangling pointer error in C++.
With dynamodb cli you can do it very simple as follows:
aws dynamodb describe-table --table-name "my-table"
If the table exists it returns
0 -- Command was successful. There were no errors thrown by either the CLI or by the service the request was made to.
If the table does not exist it returns
255 -- Command failed. There were errors thrown by either the CLI or by the service the request was made to.
See also:
http://docs.aws.amazon.com/cli/latest/reference/dynamodb/describe-table.html
http://docs.aws.amazon.com/cli/latest/topic/return-codes.html

in php i need one line if condition for time compare

i have to value
$mo=strtotime($input_array['MondayOpen']);
$mc=strtotime($input_array['MondayClose']);
now i need a if condition to display an error on below conditions
if one of them($mo or $mc) are empty, null or blank.
if close time($mc) is less than open time($mo)
means if both are empty(null) or $mc>$mo then go further
please suggest optimized one line if condition for this
i know it seems very basic question, but i m facing problem when both are null
either i was using simple
if(($mo==NULL && $mc!=NULL) || ( $mo>=$mc && ($mo!=NULL && $mc!=NULL)) )
Keep in mind that 0, null, and blank all mean completely different things here. As indicated previously, strtotime will never return NULL. However, 0 is a valid unix timestamp, whereas false means that the strtotime function was unable to process the value provided.
Also, you've requested that a single-line solution; however, in my opinion, it is much better in this case to write out each condition and display a different error message for each condition. That way, the user knows what actually went wrong. Perhaps this is a better way:
// Only check for errors if we have at least one value set
if (!empty($input['MondayOpen']) || !empty($input['MondayClosed']) {
$mo = strtotime($input['MondayOpen']);
$mc = strtotime($input['MondayClosed']);
$invalid = false;
if (false === $mo) {
echo "Invalid Opening Time\n";
$invalid = true;
}
if (false === $mc) {
echo "Invalid Closing Time\n";
$invalid = true;
}
if (!$invalid && $mc <= $mo) {
echo "Closing time must be After Opening Time\n";
$invalid = true;
}
if ($invalid) {
exit(); // Or handle errors more gracefully
}
}
// Do something useful
All right. How about this.
It checks whether $mo and $mc are valid dates using is_numeric. Any NULL or false values will be caught by that.
I haven't tested it but it should work.
I spread it into a huge block of code. In the beginning, when learning the language, this is the best way to make sense out of the code. It is not the most elegant, nor by far the shortest solution. Later, you can shorten it by removing whitespace, or by introducing or and stuff.
I'm not 100% sure about the number comparison part, and I don't have the time to check it right now. You'll have to try out whether it works.
You need to decide how you want to handle errors and insert the code to where my comments are. A simple echo might already do.
// If $mo or $mc are false, show error.
// Else, proceed to checking whether $mo is larger
// than $mc.
if ((!is_numeric($mo)) and (is_numeric($mc)))
{
// Error: $mo is either NULL, or false, or something else, but not a number.
// While $mc IS a number.
}
elseif ((!is_numeric($mc)) and (is_numeric($mo)))
{
// Error: $mc is either NULL, or false, or something else, but not a number.
// While $mo IS a number.
}
else
{
if (($mc <= $mo) and ((is_numeric($mc) or (is_numeric($mo)))))
{
// Error: closing time is before opening time.
}
else
{
// Success!!
}
}
in php, strotime will return a integer or false. Checking for null in this case will never bear fruit, but otherwise...
if((!$mo xor !$mc) || ($mc && $mc<=$mo)){
print('error');
}else{
print('no_error');
}
oops, edited for correctness. I transposed $mc and $mo. XOR should be correct though.
You can try:
print ((empty($mo) && empty($mc)) || ($mc > $mo)) ? 'case_true_message' : 'case_false_message';
But you should also check the manual :) - for basic control structures

Objects and error handling in PHP

What's the best practice to handle errors if using objects?
A) Before the method of object is called and not even getting to execute method if there's some error, or
B) Just pass parameters and perform error checking in method itself, returning error code or something.
Please pick your option and short description, why?
Thanks orlandu63, it is good practice, but what about non-fatal errors, such as user should provide a title for something, and he/she didn't?
class Sample {
var $err_no_title = 1;
function createNewRecord ($title) {
if (!$title) return $this->err_no_title;
}
}
Or use exceptions for these kind of errors also?
If you're using OO, you might as well use Exceptions. My answer is a mix of both A and B:
class DatabaseConnectionException extends Exception {}
class Database {
public function connect($user, $pass, $db) {
//Connection stuff.
if($baduser) {
throw new DatabaseConnectionException('Username (' . $user. ') is invalid.')
}
if($badpass) {
//''
}
}
}
$db = new Database;
try {
$db->connect($user, $pass, $db);
catch (DatabaseConnectionException $e) {
die('I cannot connect to the database:' . $e);
}
What are the advantages to this? I don't know, but it seems right.
You can read more on it on http://php.net/exceptions and google.
Regarding your second part,
First of all your example will treat it more of an error than a "warning" since you exit the function and thus don't create a record if you have no title. This shows that method B is flawed. So method A all the way.
To choose from options you offer it would be B, but don't use error codes and throw exceptions instead. All the logic (even validation of inputs) should be encapsulated in the function.
The reasons are:
The function may change and so may change requirements for inputs.
User of your function may not always know, what the inputs should be like.
You surely don't want to repeat the validation code everywhere you use the function.
Be careful though, as exceptions are raised by object oriented code only. For example this code does not fire an exception:
<?php
$number = $number / 0;
?>
Your example would be like:
<?php
class Sample {
function createNewRecord ($title) {
if (!$title) throw new Exception('Title required');
}
}
...
try {
$mysample->createNewRecord($title);
} catch ($ex) {
echo "Could not create record. Please try again. (Reason: $ex)";
}
...
?>
In the first place, this sort of thing should be validated in the user interface. So it would be A, but B needs to be there to. So final verdict would be: both.

Categories