How to return a boolean if the record has been updated on the database?
Example:
try {
$SQL = "UPDATE addressbook SET valid = '0' WHERE id = :id";
$query = $this->db->prepare($SQL);
$query->bindValue(":id", $id);
$query->execute();
//How do I know if record has been updated?
} catch (PDOException $e) {
$j['success'] = 'false';
echo json_encode($j);
return;
}
You can use:
PDOStatement::rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement executed by the corresponding PDOStatement object.
If the last SQL statement executed by the associated PDOStatement was a SELECT statement, some databases may return the number of rows returned by that statement. However, this behaviour is not guaranteed for all databases and should not be relied on for portable applications.
PDOStatement::rowCount (PHP 5 >= 5.1.0, PECL pdo >= 0.1.0)
To your particular case, returning a boolean:
return $query->rowCount() ? true : false;
If something went wrong but your code was updated in the database, that sounds like a really precarious state to be in. It's probably better to use a transaction and rollback on exception.
Something like (untested):
$this->db->beginTransaction();
try {
$SQL = "UPDATE addressbook SET valid = '0' WHERE id = :id";
$query = $this->db->prepare($SQL);
$query->bindValue(":id", $id);
$query->execute();
$this->db->commit();
return true;
//How do I know if record has been updated?
} catch (PDOException $e) {
$this->db->rollback();
return false;
}
Also, you probably don't want to mix your JSON in with this code, separate it out and have something outside your class deal with JSON.
Related
I am new to php and trying hard to learn its why you guys and gals need to Forgive me for asking a lot!
Here is my question;
I am trying to call a function with where clause multiple times, I have read allmost all posts and examples still didn't understand how to do it.
I tought that An example will be more useful than any blurb I can write.
Here is the function I am trying to create and use it multiple times :
function getTable($tableName, $clause) {
$stmt = $pdo->prepare("SELECT * FROM ".$tableName." WHERE ".$clause." = :".$clause);
$stmt->bindParam(":$clause", $clause, PDO::PARAM_STR);
$stmt->execute();
if($stmt->rowCount() > 0){
return true;
}else{
return false;
}
return $stmt;
}
I am not sure if my fucntion is safe or its rigth.
AND this is how I am trying to call function, which I dont know how to call table name and where clause and how to turn while loop.
getTable('posts');
If you give an example of creating and caling function, I would be grateful, Thanks
Nope, your function is not safe. Moreover it is just useless. There is no use case where you would use it like this getTable('posts');. And for the everything else it is much better to allow the full SQL syntax, not some limited subset.
The simplest yet most powerful PDO function I can think of is a function that accepts a PDO object, an SQL query, and array with input variables. A PDO statement is returned. I wrote about such function in my article about PDO helper functions. So here is the code:
function pdo($pdo, $sql, $args = NULL)
{
if (!$args)
{
return $pdo->query($sql);
}
$stmt = $pdo->prepare($sql);
$stmt->execute($args);
return $stmt;
}
With this function you will be able to run any query, with any number of WHERE conditions, and get results in many different formats. Here are some examples from the article mentioned above:
// getting the number of rows in the table
$count = pdo($pdo, "SELECT count(*) FROM users")->fetchColumn();
// the user data based on email
$user = pdo($pdo, "SELECT * FROM users WHERE email=?", [$email])->fetch();
// getting many rows from the table
$data = pdo($pdo, "SELECT * FROM users WHERE salary > ?", [$salary])->fetchAll();
// getting the number of affected rows from DELETE/UPDATE/INSERT
$deleted = pdo($pdo, "DELETE FROM users WHERE id=?", [$id])->rowCount();
// insert
pdo($pdo, "INSERT INTO users VALUES (null, ?,?,?)", [$name, $email, $password]);
// named placeholders are also welcome though I find them a bit too verbose
pdo($pdo, "UPDATE users SET name=:name WHERE id=:id", ['id'=>$id, 'name'=>$name]);
// using a sophisticated fetch mode, indexing the returned array by id
$indexed = pdo($pdo, "SELECT id, name FROM users")->fetchAll(PDO::FETCH_KEY_PAIR);
Special for you, here is the while example, though this method is considered clumsy and outdated:
$stmt = pdo($pdo,"SELECT * FROM tableName WHERE field = ?",[$value]);
while ($row = $stmt->fetch()) {
echo $row['name'];
}
More transaction questions!
What I have right now is a mess of strung-together queries, that are all manually reversed if any fail:
Code Block 1
$stmt1 = $db->prepare(...); // Update table1, set col=col+1
if($stmt1 = $db->execute(...)){
$stmt2 = $db->prepare(...); // Insert into table2, id=12345
if($stmt2 = $db->execute(...)){
$stmt3 = $db->prepare(...); // Select val from table3
if($stmt3 = $db->execute(...)){
$result = $stmt3->fetchAll();
if($result[0]['val'] == something){
$stmt4 = $db->prepare(...); // Update table4, set status=2
if($stmt4 = $db->execute(...)){
return true;
}else{
$stmt1 = $db->prepare(...); // Update table1, set col=col-1 (opposite of above)
$stmt1 = $db->execute(...);
$stmt2 = $db->prepare(...); // Delete from table2, where id=12345 (opposite of above)
$stmt2 = $db->execute(...);
return false;
}
}
return true;
}else{
$stmt1 = $db->prepare(...); // Update table1, set col=col-1 (opposite of above)
$stmt1 = $db->execute(...);
$stmt2 = $db->prepare(...); // Delete from table2, where id=12345 (opposite of above)
$stmt2 = $db->execute(...);
return false;
}
}else{
$stmt1 = $db->prepare(...); // Update table1, set col=col-1 (opposite of above)
$stmt1 = $db->execute(...);
return false;
}
}
It's a mess, difficult to debug, difficult to add on to, difficult to understand when the queries are large, and won't return all tables back to original state if the connection is lost mid-way through.
This same process is even worse when deleting a row, because everything in it needs to be stored - just in case the operation needs to be undone.
Now, I know most of this will still work when I port it over to a single transaction, but the one part I am unsure of is:
Code Block 2
$result = $stmt3->fetchAll();
if($result[0]['val'] == something){
... continue ...
}else{
... reverse operations ...
return false;
}
Because the results-gathering would take place before the commit() in the transaction. As follows:
Code Block 3
$db->beginTransaction();
try{
$stmt1 = $db->prepare(...);
$stmt1->execute();
$stmt2 = $db->prepare(...);
$stmt2->execute();
$stmt3 = $db->prepare(...);
$stmt3->execute();
$result = $stmt3->fetchAll();
if($result[0]['val'] == something){
$stmt4 = $db->prepare(...);
$stmt4->execute();
}else{
$db->rollBack();
return false;
}
$db->commit();
return true;
}catch(Exception $e){
$db->rollBack();
throw $e;
return false;
}
Will this work? Specifically, can I include the $result = $stmt3->fetchAll(); before the commit(), and then execute the conditional query?
Also, I'm not entirely sure on this, but do I require the $db->rollBack(); within the try block, if the code is exited (return false) before the commit()?
Your first question:
Specifically, can I include the $result = $stmt3->fetchAll(); before the commit(), and then execute the conditional query?
I see no reason why it should not work. A transaction behaves basically the same as operations without transactions - except that changes are only drafts. Any changes you make in the previous statements will be applied to a "working copy" valid for this single session only. For you it will appear completely transparent. However any changes will be rolled back if you do not commit them.
Also worth noting (emphasis mine):
In layman's terms, any work carried out in a transaction, even if it is carried out in stages, is guaranteed to be applied to the database safely, and without interference from other connections, when it is committed.
This can cause racing conditions.
Your second question:
Also, I'm not entirely sure on this, but do I require the $db->rollBack(); within the try block, if the code is exited (return false) before the commit()?
From the documentation it says:
When the script ends or when a connection is about to be closed, if you have an outstanding transaction, PDO will automatically roll it back.
Therefore you do not necessarily require to roll back manually as it will be done by the driver itself.
However note the following from the same source as well:
Warning PDO only checks for transaction capabilities on driver level. If certain runtime conditions mean that transactions are unavailable, PDO::beginTransaction() will still return TRUE without error if the database server accepts the request to start a transaction.
So be sure to check the compatibility beforehand!
A few notes
Do NOT begin a transaction in another transaction. This will commit the first transaction implicitely. See this comment.
Another note from the documentation:
Some databases, including MySQL, automatically issue an implicit COMMIT when a database definition language (DDL) statement such as DROP TABLE or CREATE TABLE is issued within a transaction. The implicit COMMIT will prevent you from rolling back any other changes within the transaction boundary.
I have a script which is containing some queries:
$id = $_GET['id'];
$value = $_GET['val'];
// database connection here
// inserting
$stm1 = $db_conn->prepare("INSERT into table1 (col) VALUES (?)");
$stm1->execute(array($value));
// updating
$stm2 = $db_conn->prepare("UPDATE table2 SET col = "a new row inserted" WHERE id = ?");
$stm2->execute(array($id));
As you see there is two statements (insert and update). All I'm trying to do is making sure both of them work or none of them.
I mean I want to implement a dependency between those two statements. If updating fails, then inserting shouldn't work and vice versa. How can I do that?
You could use sql transactions
http://www.sqlteam.com/article/introduction-to-transactions
You can use transactions and PDO has an api for this (http://php.net/manual/en/pdo.begintransaction.php),
$id = $_GET['id'];
$value = $_GET['val'];
// database connection here
try{
$db_conn->beginTransaction();
// inserting
$stm1 = $db_conn->prepare("INSERT into table1 (col) VALUES (?)");
$stm1->execute(array($value));
// updating
$stm2 = $db_conn->prepare("UPDATE table2 SET col = "a new row inserted" WHERE id = ?");
$stm2->execute(array($id));
$db_conn->commit();
}
catch(PDOException $e){
$db_conn->rollBack();
}
As others said, you could use 'transactions'.
Or
you could mannualy check whether the data is right in the database. Just 'select' what you have inserted.
The 'execute' function return 'true' on success or 'false' on failure. You can do something like:
$isDone=$stm1->execute(array($value));
if(!$isDone){
echo 'Operation fails, I will stop.';
return false;
}
I am trying to fetch the 'id' column data from my database. Since the purpose of this is a login, there is only one potential row that is returned for the SQL query I have used. I would like to create a reference ($this->result) for the id of the user so that I can use this later on. At the moment it appears nothing is being retrieved from $this->result = $stmt->fetchColumn(); Does anyone have any suggestions for how I can make this work?
$sql='SELECT id FROM member WHERE username=:var and password=:var2';
try {
$stmt = $connection->prepare($sql);
$stmt->bindParam(":var", $myusername);
$stmt->bindParam(":var2", $mypassword);
$stmt->execute();
} catch(PDOException $ex) {
echo "An Error occured!";
some_logging_function($ex->getMessage());
}
$this->count = $stmt->rowCount();
$this->result = $stmt->fetchColumn();
I'm working on a school project creating a CMS for my portfolio site. I am having trouble getting my update function to work. I have a feeling it has something to do with the way I'm constructing my PDO Transaction. In my database I have a projects table, category table, and the associative content_category table. I'm able to insert my projects into those tables just fine. What I want to do is insert into my projects table then delete all records from the content_category table and finally insert the current category records into that associative table to complete the transaction. I do get my return statement "Project Updated" returned. But the tables aren't being updated. Any ideas anyone?
Here's the code:
This is a function in my Project class.
public function update(){
try {
$conn = getConnection();
$conn->beginTransaction();
$sql = "UPDATE project
SET project_title = :title,
project_description = :desc,
project_isFeatured = :feat,
project_mainImage = :image
WHERE project_id = :id";
$st = $conn->prepare($sql);
$st->bindValue(":id", $this->id, PDO::PARAM_INT);
$st->bindValue(":title", $this->title, PDO::PARAM_STR);
$st->bindValue(":desc", $this->description, PDO::PARAM_STR);
$st->bindValue(":feat", $this->isFeatured, PDO::PARAM_BOOL);
$st->bindValue(":image", $this->mainImage, PDO::PARAM_INT);
$st->execute();
$sql = "DELETE from content_category
WHERE content_id = :id";
$st = $conn->prepare($sql);
$st->bindValue("id", $this->id, PDO::PARAM_INT);
$st->execute();
$sql = "INSERT into content_category (content_id, cat_id)
VALUES (?,?)";
$st = $conn->prepare($sql);
foreach($this->categories as $key=>$value){
$st->execute(array(intval($projectID), intval($value)));
}
$conn->commit();
$conn = null;
return "Project updated";
}
catch(Exception $e) {
echo $e->getMessage();
$conn->rollBack();
return "Error... Unable to update!";
}
}
Your database engine for the tables needs to be INNODB. If you are using phpMyAdmin, it defaults to MyISAM. (I don't know if that will cause the updates not to go through or just the transaction line to be ignored. Edit: Pretty sure the documentation is saying that it will throw an error and not do anything if you beginTransaction on a myISAM)
In order to make sure you are not encountering a PDO error, you should set the PDO error reporting like this:
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
There are functions in PDO such as prepare() which will either return false or throw a PDOException depending on what error mode is set. This way, it will throw an exception and you'll definitely know if you are having a problem!
Also, if your database doesn't support transactions (like MyISAM), the beginTransaction() function will return false. So, maybe add a check in there like:
if($conn->beginTransaction()) {
// Do transaction here
} else {
echo("Unable to use transactions with this database.");
}
Oddly enough, according to PHP documentation, you would be getting an exception if your database doesn't support transactions...
Unfortunately, not every database supports transactions, so PDO needs to run in what is known as "auto-commit" mode when you first open the connection. Auto-commit mode means that every query that you run has its own implicit transaction, if the database supports it, or no transaction if the database doesn't support transactions. If you need a transaction, you must use the PDO::beginTransaction() method to initiate one. If the underlying driver does not support transactions, a PDOException will be thrown (regardless of your error handling settings: this is always a serious error condition).
Commit returns TRUE on success or FALSE on failure. You can check it. Also check for errorCode.