How to dynamically update tables in PHP - php

I'm building an application where users can add, edit and delete users from the database.
I've done the 'View Users' ( Select statement returning joined tables ) and the 'Add Users' ( Returns a form for user to fill in and INSERTS into database after validation of course )
But I'm having trouble with the 'Edit Users'.
My Edit form is the SAME as the add form but the values for the text boxes are filled in with values from the database.
Upon submit, the logic checks for mismatches between the user input and the database values (So we know what we're actually updating in the database)
So I end up with an array of all the values that need to be changed, example:
$values_to_update = array (
"telephone" => "07788991010"
"email_address" => "my_new_email_address#host.com"
);
The values in this array are dynamic and I need to thing of a way to dynamically update each field.
Also, the fields may also come from different tables.
I DON'T want to do:
if ( isset ( $values_to_update[ "telephone" ] ) )
$database->update("UPDATE users SET telephone = '{$values_to_update[ "telephone" ]}' WHERE user_id = $user_id");
else if ( isset ( $values_to_update[ "email_address" ] ) )
$database->update("UPDATE authentication SET email_address = '{$values_to_update[ "email_address" ]}' WHERE user_id = $user_id");
else if ( /* ... */)
// etc etc etc
Does anybody have any ideas of a better way I could do this?
I was thinking maybe I could use one HUGE update statement uses the same select statment that fetches the data. but i dont know how this would work.
Is it a standard practise for applications to store an array of fields to tables for dynamic query generation?

A clean way I've found of doing this in PDO-style ORM mappers (which is also used in Zend Framework):
public function save($model) {
// Possible values to insert
$values = array(
":id" => $model->id,
":name" => $model->name,
//...
":contact_number" => $model->telephone
);
// If model id is set, we are updating a record, otherwise inserting
if (isset($model->id)) {
$sql = "UPDATE tbl SET name = :name, ..., contact_number = :contact_number WHERE id = :id LIMIT 1";
} else {
// Don't pass the ID when it isn't in the query
unset($values[":id"]);
$sql = "INSERT INTO tbl (name, ..., contact_number) VALUES (:name, ..., :contact_number)";
}
// Execute the query with our values (below is a PDO example)
$stmt = $this->db->prepare($sql);
$stmt->execute($values);
$stmt->closeCursor();
// Get the new ID if we inserted
if (!isset($model->id)) {
$model->id = $this->db->lastInsertId();
}
return $model;
}
Usually this amounts to writing a single save method for each model. You could extend this in UPDATE situations by keeping a copy of the originally-retrieved model, so that you only update the columns that have changed, however I don't see any huge overhead by updating all columns.

Related

Combining two queries into a single query

I have two queries and I want to combine them into one so that it only returns one row in my database.
I have tried UNION but I keep getting an error. Can anyone please advise me on the code for it?
Below are my queries:
if(isset($_POST["response"]))
{
$query = "INSERT INTO response(response) VALUES (:response)";
$statement = $conn->prepare($query);
$statement->execute(
array(
':response' => $_POST["response"]
)
);
$query = " INSERT INTO response (student_id)
SELECT studentid
FROM student
WHERE studentid = '".$_SESSION['studentid']."'";
$statement = $conn->prepare($query);
$statement->execute(
);
UNION is used for combining multiple SELECT queries into a single result set. Check the mySQL (or any generic ANSI SQL) documentation.
Anyway, for no apparent reason you are making two INSERT queries when it looks like you're inserting into the same table and presumably want to insert everything into the same row in the same table. Right now you will make 2 rows instead of 1. You can insert more than one field as part of a single query.
I'm thinking:
if(isset($_POST["response"]))
{
$query = "INSERT INTO response (student_id, response) SELECT studentid, :response FROM student WHERE studentid = :studentID";
$statement = $conn->prepare($query);
$statement->execute(
array(
':response' => $_POST["response"],
':studentID' => $_SESSION['studentid']
)
);
}
However, since you only require the studentID in the table, and you already have the studentID from the session, it seems pointless to select from the students table at all. The only exception might be if you need to verify that the value in the session is correct - but surely you have already verified it before you added it to the session? If you haven't, you certainly should.
So in fact simply
if(isset($_POST["response"]))
{
$query = "INSERT INTO response (student_id, response) VALUES (:studentID, :response)";
$statement = $conn->prepare($query);
$statement->execute(
array(
':response' => $_POST["response"],
':studentID' => $_SESSION['studentid']
)
);
}
should be sufficient.

Add new user and usermeta into database with SQL

I've using this to create a new user in the WordPress database...
// Add user to WP users table.
$user_table_name = $wpdb->prefix . "users";
$unique_string = substr(md5(rand(0, 1000000)), 0, 10);
$wpdb->insert( $user_table_name, array(
'user_login' => sanitize_text_field($_POST['email']),
'user_pass' => sanitize_text_field(MD5($unique_string)),
'user_email' => sanitize_text_field($_POST['email']),
'user_registered' => sanitize_text_field(date("Y-n-d G:i:s")),
'user_status' => $_POST['1'],
'display_name' => sanitize_text_field($_POST['first_name']) . " " . sanitize_text_field($_POST['last_name'])
) );
...which works fine, and let's pretend that the ID of that user turned out to be 1234 in the database table (thanks to auto increment).
So now I also need to add the corresponding user meta information into the usermeta table for that user, and this is where I get a little confused.
The code above is easy because it's just adding a row to a table. But the usermeta table is different because it will need - in this case - a bunch of rows with the corresponding user_ID of 1234 each respectively with:
nickname (I'll use the email address for this)
wp_capabilities (value to be a:1:{s:10:"subscriber";b:1;})
sales (a custom field I have - value will be set to the word "yes")
colour (another custom field I have - value will be set to the word "green")
I'm guessing the SQL statement is going to be similar to the one at the start of this post.
If anyone could show me, that would be awesome.
UPDATE:
So this is mostly done. This works:
// Add corresponding user metadata to WP users table.
$usermeta_table_name = $wpdb->prefix . "usermeta";
$last_id = $wpdb->insert_id;
$role = sanitize_text_field('a:1:{s:10:"subscriber";b:1;}');
$wpdb->query(
$wpdb->prepare(
"
INSERT INTO $usermeta_table_name (
`umeta_id`,
`user_id`,
`meta_key`,
`meta_value` )
VALUES (
NULL,
$last_id,
$usermeta_table_name . 'capabilities',
'$role' )
",
$last_id, $last_id
)
);
That will add one row to the usermeta table, but how can I add 2 more rows within the same statement?
Store the last inserted row's ID to a variable:
$last_id = $wpdb->insert_id;
now, use this $last_id variable for metadata insertion. The insert_id variable is provided by the wpdb class.
OK so I feel a little silly about this - though to be fair it's been a long time since I wrote any SQL :-)
The answer is simply to follow this method:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

PDO insert into query based on another field

I have a table named 'users' that contains 'username' and 'team_name' columns.
I have created form that populates two select dropdowns based on a 'username' from the users table and a 'team_name' from the 'teams' table.
I am now trying to create an insert statement that takes the 'team_name' and 'username' selected and inputs the 'team_name' into the 'users' table WHERE the 'username' is equal to one provided by the dropdown list.
$result = $conn->prepare("INSERT INTO users (`team_name`) VALUES ('{$teamname}') WHERE username = $username");
I am getting a syntax error SQLState[420000] - I think this is due to me not declaring username anywhere else within the statement i.e. columns - However, I do not want to give it a value - I just want it to post the team_name to the particuar username provided.
What is the best way to solve this?
UPDATE:
Even when using
UPDATE users SET team_name=$teamname WHERE username=$username
I still receive the error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'grillzeE' in 'where clause
When the username does exist within the username column.
I think this is the query you are looking for:
INSERT INTO users (team_name)
SELECT team_name
FROM teams
WHERE username = ?
If this is PDO then you are losing the benefit of prepared statements to a degree by actually specifying the variable value in the query rather than as a bound variable. Typically you should be using placeholders for the variables and substituting then in at runtime.
$stmt= $conn->prepare("INSERT INTO users (`team_name`) VALUES (:teamname) WHERE username = :username");
if( isset( $username ) && isset( $teamname ) ){
$params=array(':teamname' => $teamname, ':username' => $username );
foreach( $params as $key => &$val ) {
$stmt->bindParam( $key, $val );
}
$stmt->execute();
}

INSERT into Table On Columns That Exist

Suppose I have a very large array of information for a user:
$user=array(
"name"=>"john",
"ip"=>"xx.xx.xx.xx",
"email"=>"john#something.com",
//lots more values
)
Let's also suppose that this information needs to go into more than one table. For instance a username needs to go table users, address needs to go into a details table, etc.
Now, I use a certain self-made function to insert into my tables that matches array keys to column names and array values to the values being inputted. Something similar to this:
function insert_sql($table, arr $values){
GLOBAL $dbc;
$sql="INSERT INTO `$table` (".implode(array_keys($values), ", ").") VALUES (".implode(array_values($values), ", ").")";
$dbc->prepare($sql)->execute();
return $dbc->lastInsertId();
}
//I don't actually use this function, just trying to show you what is being accomplished.
The problem is that my function uses all the keys and all the values, so when I just need certain parts of the array put into multiple tables, it doesn't work.
The question is:
How do I make an INSERT statement ignore a column if it doesn't exist? So if I insert name,email,address, into table users, but this table doesn't have an address column, I need it to insert the row with the name and email but simply ignore the fact that the address column is not there.
EDIT: The other option is to make an array with the columns of a table and use it to filter the values array. Although I am not really sure how to set this up.
Find given table column names:
SELECT
column_name
FROM
information_schema.columns
WHERE
table_name = 'tablename'
And then just whitelist your keys in $values array
Example:
function insert_sql($table, array $values){
global $connection;
$query = "SELECT column_name FROM information_schema.columns WHERE table_name = :tablename";
/* #var $stmt PDOStatement */
$stmt = $connection->prepare($query);
$stmt->execute(array(
'tablename' => $table
));
$columns = array_flip($stmt->fetchAll(PDO::FETCH_COLUMN, 0));
$values = array_intersect_key($values, $columns);
var_dump($values);
}
How do I make an INSERT statement ignore a column if it doesn't exist?
So if I insert name,email,address, into table users, but this table
doesn't have an address column, I need it to insert the row with the
name and email but simply ignore the fact that the address column is
not there.
You can't
Instead you should map your data to the appropriate tables with separate inserts.

Cakephp system for update the row for given id if no id exists, create a new row

What is do you think is the best way to create a procedure where request is made and if there are any existing id in the database, update if not create a new one.
I was using something like below and it seems to work but is there are better way?
$id = $this->User->findByFacebookId($facebook);
if($id){
$this->User->set(array(
'facebook_id' => $facebook,
'longitude' => $longitude,
'latitude' => $latitude,
'firstname' => $firstname,
'surname' => $surname
));
$this->User->id = $id['User']['id'];
$this->User->save($this->data);
Yup, CakePHP basically does this by default. If your data has no id field an INSERT statement is issued, whereas if there is an id field it issues UPDATE ... WHERE ID = ?.
Just to show how simply this can be done, below is a way to do the same without even calling Model::set() or updating the Model::id property:
// get existing record (so we can get value of `id` field)
$existing = $this->User->findByFacebookId($facebook);
// if record exists, map data to correct record `id`
if ($existing) {
$this->data['User']['id'] = $existing['User']['id'];
}
// save data to table (`id` determines if INSERT or UPDATE)
$this->User->save($this->data);

Categories