0

So i have made an SignUP form in AngularJS+PHP+MySQL and now i want to catch PDO exception in my angular so I can make an IF duplicate entry for example 'login' I can print it out in my Angular, but i have no idea where to begin. I have googled a bit but can't find anything really helpful.

This is my .controller :

.controller('registerController', function($scope, $http) {
  $scope.registerData = {firstname : null, lastname : null, login: null, password : null, email : null, city : null, postalcode : null, adress: null, country: null};

  $scope.registerFunction = function() {
    $http({
        method: "post",
        url: './php/registration.php',
        data: {
            firstname: $scope.registerData.firstname,
            lastname: $scope.registerData.lastname,
            login: $scope.registerData.login,
            password: $scope.registerData.password,
            email: $scope.registerData.email,
            city: $scope.registerData.city,
            postalcode: $scope.registerData.postalcode,
            adress: $scope.registerData.adress,
            country: $scope.registerData.country,
        },
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
    });
    swal("Good job!", "You have been registered!", "success");
  };
})

This is my form in html+bootstrap :

  <div class="modal fade" id="registerModal">
    <div class="modal-dialog">
      <div class="modal-content" ng-controller="registerController">
        <div class="modal-header"><h4 class="modal-title">Sign Up</h4></br><button type="button" class="close" data-dismiss="modal">&times;</button></div>
        <div class="modal-body"><form>
            <div class="row">
                <div class="col-lg-6">
                  <label style="float: left;"><b>Firstname:</b></label>
                  <input type="text" ng-model="registerData.firstname" class="form-control">
                  <label style="float: left;"><b>Lastname:</b></label>
                  <input type="text" ng-model="registerData.lastname" class="form-control">
                  <label style="float: left;"><b><span class="redstar">*</span> Login:</b></label>
                  <input type="text" ng-model="registerData.login" class="form-control">
                  <label style="float: left;"><b><span class="redstar">*</span> Password:</b></label>
                  <input type="password" ng-model="registerData.password" class="form-control">
                  <label style="float: left;"><b><span class="redstar">*</span> Repeat Password:</b></label>
                  <input type="password" class="form-control">
                </div>
                <div class="col-lg-6">
                  <label style="float: left;"><b><span class="redstar">*</span> E-Mail:</b></label>
                  <input type="text" ng-model="registerData.email" class="form-control">
                  <label style="float: left;"><b>City:</b></label>
                  <input type="text" ng-model="registerData.city" class="form-control">
                  <label style="float: left;"><b>Postal Code:</b></label>
                  <input type="text" ng-model="registerData.postalcode" class="form-control">
                  <label style="float: left;"><b>Adress:</b></label>
                  <input type="text" ng-model="registerData.adress" class="form-control">
                  <label style="float: left;"><b>Country:</b></label>
                  <select class="form-control" ng-model="registerData.country" required>
                    <option ng-repeat="item in countries" value="{{item.id}}">
                      {{item.name}}
                    </option>
                  </select>
                </div>
                <div class="col-lg-12">
                  <p style="float:left;">Fields marked with <span class="redstar"><b>*</b></span> are required.</p></br>
                </div>
            </div>
        </form></div>
        <div class="modal-footer"><button type="button" class="btn btn-danger" data-dismiss="modal">Close</button><button type="button" class="btn btn-success" data-dismiss="modal" ng-click="registerFunction()">Sign Up</button></div>
        </div></div>
    </div>

This is how i execute it :

<?php
include_once 'config.php';
$data = json_decode(file_get_contents("php://input"));

$firstname = $data->firstname;
$lastname = $data->lastname;
$login = $data->login;
$password = $data->password;
$email = $data->email;
$city = $data->city;
$postalcode = $data->postalcode;
$adress = $data->adress;
$country = $data->country;

$dbh->query("INSERT INTO `accounts` (`account_id`, `firstname`, `lastname`, `login`, `password`, `email`, `city`, `postalcode`, `adress`, `country`, `role`)
    VALUES (NULL,'".$firstname."','".$lastname."','".$login."',MD5('".$password."'),'".$email."','".$city."','".$postalcode."','".$adress."','".$country."', 0) ") or die(mysql_error());
$dbh = null;
?>

And this is my connection :

<?php
$hostname='localhost';
$username='root';
$password='';

try {
    $dbh = new PDO("mysql:host=$hostname;dbname=myshop",$username,$password);

    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // <== add this line
    echo 'Connected to Database';
}
catch(PDOException $e)
    {
    echo $e->getMessage();
    }
?>

My question is how can i for example add and If in my controller like there is an error duplicate entry for 'login' i do something in my angular. So how can i catch the error in to my controller?

deceze
  • 510,633
  • 85
  • 743
  • 889
SupremeDEV
  • 384
  • 1
  • 15

2 Answers2

2

You cannot catch a server-side exception in client-side code, exceptions don't propagate across HTTP. You need to abstract that more: the client makes an HTTP request to the server, the server returns an HTTP status code and response content. If an exception, or anything else bad, happens on the server, the server signals that to the client using the HTTP status code. So if an exception happens, you set an appropriate code:

try {
    ...
} catch (PDOException $e) {
    header('HTTP/1.0 500 Internal Server Error');
    // Maybe: echo json_encode(['error' => 'You fool!']);
    exit;
}

In fact, if you simply don't catch the exception and let PHP die with an unhandled exception error, the web server will by default respond with such a 500 status code.

On the client side, this will cause the $http promise to reject, and you can handle that:

$http(...)
    .catch(response => {
        console.error('Error fooing the bar', response.statusText);
        // do something constructive
    });

Pick an appropriate status code to respond with to distinguish various conditions: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

deceze
  • 510,633
  • 85
  • 743
  • 889
  • So as i understood, now when i add the header into my catch exception in php. Add the .catch after my $http promise in my controller and do for example console.log('something'), now when exception occurs it should console log me something ? – SupremeDEV Mar 16 '18 at 08:50
  • Yes indeed. The `$http` promise should reject and execute the failure callback (`.catch`) whenever a status code outside the 2xx range is encountered. – deceze Mar 16 '18 at 08:52
  • I will edit my question with updated code. Can u check if this is what you mean ? Because it still doesn't work and i have no idea what mistake i did. – SupremeDEV Mar 16 '18 at 08:53
  • So, what *is* it doing? ¯\\_(ツ)_/¯ Have you checked the developer tools' network inspector to see what your request returns exactly? – deceze Mar 16 '18 at 08:58
  • And please don't basically edit the answer into the question, it makes it somewhere between pointless and hard to follow for anyone coming later. – deceze Mar 16 '18 at 09:00
  • Yes. My registration.php returns the exception like : `Connected to Database
    Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '' for key 'login'' in C:\xampp2\htdocs\MyOwnShop\php\registration.php:16 Stack trace: #0 C:\xampp2\htdocs\MyOwnShop\php\registration.php(16): PDO->query('INSERT INTO `ac...') #1 {main} thrown in C:\xampp2\htdocs\MyOwnShop\php\registration.php on line 16
    ` And my console doesn't show anything.
    – SupremeDEV Mar 16 '18 at 09:00
  • I will edit the anwser back to what it was and add the edited code at the bottom then. Thank you for the tip ! – SupremeDEV Mar 16 '18 at 09:01
  • Then your problem is that the header cannot be set because you already have produced output ("Connected to Database"): https://stackoverflow.com/q/8028957/476 – deceze Mar 16 '18 at 09:02
  • Okey. I will mark all tips and try do work something out :) Thank you very much for your help. I will come back when i fix it to mark it as anwser and if i don't fix it i will come back to get you help. Thank you again ! – SupremeDEV Mar 16 '18 at 09:05
2

In addition to the great answer from @deceze, there is one thing that needs to be explained.

There are two kind of exceptions: expected and unexpected ones. And they should be treated differently.

One you asked for is an expected one. The username already taken is a regular case, I wouldn't call it an error from the application point of view. So the response should be regular as well. A meaningful message should be sent to Angular, and the latter should act accordingly: prompt a user to try another username.

Another thing is an unexpected error. Such as your database server is down. For this kind of error, no particular error message should be shown but a generic excuse and a suggestion to try later.

and now to the implementation: you should catch the expected error and shouldn't otherwise.

An example can be seen in my PDO tutorial:

try {
    $pdo->prepare("INSERT INTO users VALUES (NULL,?,?,?,?)")->execute($data);
} catch (PDOException $e) {
    $existingkey = "Integrity constraint violation: 1062 Duplicate entry";
    if (strpos($e->getMessage(), $existingkey) !== FALSE) {
        // Take some action if there is a key constraint violation, i.e. duplicate name
    } else {
        throw $e;
    }
}

here you can see that a caught Exception should be tested against a list of expected errors and re-thrown id there is no match.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • Hi, thought I'd reach you on here as SO doesn't have any other way to contact. I'm not sure about your edit on my question as it means the answers would no longer apply to it, and also the answer which you linked in my question is different to the accepted answer which solved my problem – The Codesee Mar 20 '18 at 16:05