I'm creating a multi-step form for my users. They will be allowed to update any or all the fields. So, I need to send the values, check if they are set and if so, run an UPDATE. Here is what I have so far:
public function updateUser($firstName, $lastName, $streetAddress, $city, $state, $zip, $emailAddress, $industry, $password, $public = 1,
$phone1, $phone2, $website,){
$updates = array(
'firstName' => $firstName,
'lastName' => $lastName,
'streetAddress' => $streetAddress,
'city' => $city,
'state' => $state,
'zip' => $zip,
'emailAddress' => $emailAddress,
'industry' => $industry,
'password' => $password,
'public' => $public,
'phone1' => $phone1,
'phone2' => $phone2,
'website' => $website,
);
Here is my PDO (well, the beginning attempt)
$sth = $this->dbh->prepare("UPDATE user SET firstName = "); //<---Stuck here
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_ASSOC);
return $result;
Basically, how can I create the UPDATE statement so it only updates the items in the array that are not NULL?
I thought about running a foreach loop like this:
foreach($updates as $key => $value) {
if($value == NULL) {
unset($updates[$key]);
}
}
but how would I write the prepare statement if I'm unsure of the values?
If I'm going about this completely wrong, please point me in the right direction. Thanks.
First of all, use array_filter to remove all NULL values:
$updates = array_filter($updates, function ($value) {
return null !== $value;
});
Secondly, bind parameters, that makes your live a lot easier:
$query = 'UPDATE table SET';
$values = array();
foreach ($updates as $name => $value) {
$query .= ' '.$name.' = :'.$name.','; // the :$name part is the placeholder, e.g. :zip
$values[':'.$name] = $value; // save the placeholder
}
$query = substr($query, 0, -1).';'; // remove last , and add a ;
$sth = $this->dbh->prepare($query);
$sth->execute($values); // bind placeholder array to the query and execute everything
// ... do something nice :)
The below can be optimized:
$i = 0; $query = array();
foreach($updates as $key => $value) {
if ($value != NULL) {
$query[] = "{$key} = :param_{$i}";
$i++;
}
}
if (! empty($query)) {
$finalQuery = implode(",", $query);
$sth = $this->dbh->prepare('UPDATE user SET ' . $finalQuery);
$i = 0;
foreach($updates as $key => $value) {
if ($value != NULL) {
$sth->bindParam(':param_'.$i, $value, PDO::PARAM_STR);
$i++;
}
}
}
Related
I am inserting a record on my table after inserting to another table. This my sample code:
if(isset($_POST['submit'])){
$database = new Database();
$db = $database->getConnection();
$employee = new Employee($db);
if(!empty($first_name) && !empty($family_name) && !empty($first_name_arabic) && !empty($family_name_arabic)){
$emp_number = isset($_POST['emp_number']) && !empty($_POST['emp_number']) ? $_POST['emp_number'] : $employee->generateEmployeeNumber();
$fields = [
'reference' => $reference,
'emp_number' => $emp_number,
'first_name' => $first_name,
'middle_name' => $middle_name,
'third_name' => $third_name,
'family_name' => $family_name,
'nationality' => $nationality,
];
$employee->createOrUpdate($fields, '');
$result = $employee->selectOne('Reference', $reference);
if(!empty($_POST['passport_number']) && !empty($_POST['passport_place_issue']) && !empty($_POST['passport_date_issue']) && !empty($_POST['passport_date_expiry']) && !empty($result['id'])) {
$passport = new Passport($db);
$passport_fields = [
'passport_number' => $_POST['passport_number'],
'place_issue' => $_POST['passport_place_issue'],
'date_issue' => date_format(date_create($_POST['passport_date_issue']), 'Y-m-d'),
'date_expiry' => date_format(date_create($_POST['passport_date_expiry']), 'Y-m-d'),
'reference' => $result['reference'] ,
'employee_id' => $result['id'],
'status' => 'Active',
];
$passport->createOrUpdate($passport_fields, '');
}
}
}
but my problem is my insertion for passport table is not doing anything and no error is being return to me. As for the creatOrUpdate this is how i did:
function createOrUpdate($fields, $id){
if(is_null($id) || empty($id)){
$implodeColumns = implode(', ', array_keys($fields));
$implodePlaceholder = implode(", :", array_keys($fields));
$sql = "INSERT INTO " . $this->table_name. "($implodeColumns) VALUES(:".$implodePlaceholder.")";
echo "SQL ".$sql;
$stmt = $this->conn->prepare($sql);
foreach ($fields as $key => $value) {
$stmt->bindValue(":".$key,$value);
}
$stmt->execute();
}else{}
}
I don't know if creating a method with a same name is affecting the code, but createOeUpdate method for employee is from employee.php where createOrUpdate mehod for passport is from passport.php. Only employee is being saved in my database.
Any help is much appreciated
If the names are the same from different files you need to use namespaces like:
namespace name_of_your_main_file;
// Maybe need to add full path
// if it's not in the same folder.
use employee;
use passport;
// And use it with same names as:
employee::createOrUpdate(
I have a update query using PDO,
but when I execute it, it deletes my record.
public function update($e) {
$sql = 'UPDATE experiences SET company = :company, position = :position, duty = :duty WHERE id = :id';
//$this->operaction($sql, $e);
$id = $e['id'];
$company = $e['company'];
$position = $e['position'];
$duty = $e['duty'];
$pdostmt = $this->db->prepare($sql);
$pdostmt->bindValue(':id', $id, PDO::PARAM_INT);
$pdostmt->bindValue(':company', $company, PDO::PARAM_STR);
$pdostmt->bindValue(':position', $position, PDO::PARAM_STR);
$pdostmt->bindValue(':duty', $duty, PDO::PARAM_STR);
$pdostmt->execute();
}
$e is an array of $_POST array('id' => '6', 'company' => 'webcanada', 'position' => 'web developer', 'duty' => 'build website');
Can anyone suggest I have done wrong?
Thanks.
I have this code :
public function changeProfile ($first_name, $last_name, $email, $phone, $password,
$bank_name, $bank_account_number, $bank_account_name,
$gender, $birthday, $address, $area, $default_type) {
$this->connect();
$data = array ('first_name' => $this->escapeString($first_name),
'last_name' => $this->escapeString($last_name),
'email' => $this->escapeString($email),
'phone' => $this->escapeString($phone),
'password' => $this->escapeString($password),
'bank_name' => $this->escapeString($bank_name),
'bank_account_number' => $this->escapeString($bank_account_number),
'bank_account_name' => $this->escapeString($bank_account_name),
'gender' => $this->escapeString($gender),
'birthday' => $this->escapeString($birthday),
'address' => $this->escapeString($address),
'area' => $this->escapeString($area),
'default_type' => $this->escapeString($default_type));
$this->update('user', $data, 'email = "'.$email.'" AND phone = "'.$phone.'"');
$res = $this->getResult();
}
Now, I have a problem like this :
I want to 'skip' some variables on the function, for example $birthday and $gender, so that it won't be processed on SQL UPDATE and let the current data as it is.
I mean, if $birthday and $gender data doesn't exist, then don't update existing data on the table. because when I tried to use NULL as variables on the function, my data replaced with empty data.
how to manage this situation without having multiple if to check each variables?
thank you
If you have the option, you should replace your function's argument list with an array of arguments, for example:
public function changeProfile($variables)
{
$this->connect();
$data = array();
foreach ($variables as $key => $value) {
$data[$key] = $this->escapeString($value);
}
// Validation?
if (!isset($data['email'], $data['phone'])) {
die('Required fields missing.');
}
$this->update('user', $data, 'email = "' . $data['email'] . '" AND phone = "' . $data['phone'] . '"');
$res = $this->getResult();
}
This assumes that the SQL query is static. You could also add some more fields to it if you needed to.
You'd then call it like this:
$test->changeProfileUpdated([
'first_name' => 'john',
'last_name' => 'doe',
'email' => 'example#example.com',
'phone' => 12345,
'password' => 'password1',
'bank_name' => 'ANZ',
'bank_account_number' => '123-456',
'bank_account_name' => 'J DOE',
'gender' => 'M',
'birthday' => '1/2/13',
'address' => '12 Fake St',
'area' => 'Area 51',
'default_type' => 'Some default'
]);
Here's a demo comparing your code, this example and a validation failure.
If you cannot change the method signature to take an array instead you can naturally check each value with isset() or empty() depending on your data needs like:
if (!empty($gender) {
$data['gender'] => $this->escapeString(escapeString);
}
However this is tedious. A better way would be to take an array as an input and then have an array of valid and or required keys. Something like this:
class MyClass
{
private $valid_keys = [
"first_name", "last_name", "email", "phone", "password",
"bank_name", "bank_account_number", "bank_account_name",
"gender", "birthday", "address", "area", "default_type"
];
public function changeProfile($profile)
{
// Return valid keys
$profile = array_filter($profile, function ($key) {
return in_array($key, self::$valid_keys);
} , ARRAY_FILTER_USE_KEY);
// Escape values
$profile = array_map(function ($value) {
// .. your escape function
}, $profile);
// Do your stuff
$this->update('user', $profile, 'email = "'. $profile['email'].'" AND phone = "'.$profile['phone'].'"');
$res = $this->getResult();
}
}
That way you'll only set valid data and you have a way of escaping it generically.
Oh yeah and of course only the values in $profile will get send to your update function.
If you cannot change the method signature you can look into using func_get_args().
public function changeProfile($first_name, $last_name, $email, $phone, $password,
$bank_name, $bank_account_number, $bank_account_name,
$gender, $birthday, $address, $area, $default_type)
{
$args = func_get_args();
$profile = [];
// Important: $valid_keys should be the same as your function parameters and in the same order for this to work. If you want to go further you can look at `ReflectionMethod` to get the names through reflection.
foreach ($args as $index => $value) {
$key = self::$valid_keys[$index];
$profile[$key] = $this->escapeValue($value);
}
// Do your stuff
$this->update('user', $profile, 'email = "'. $profile['email'].'" AND phone = "'.$profile['phone'].'"');
$res = $this->getResult();
}
check if it is null or not then save it in an array as given below
function changeProfile ($first_name, $last_name,$email,$phone) {
$this->connect();
$data=array();
if($first_name!=""){
$data['first_name']= $this->escapeString($first_name);
}
if($last_name!=""){
$data['last_name']=$this->escapeString($last_name);
}
if($email!=""){
$data['email']=$this->escapeString($email);
}
if($phone!=""){
$data['phone']=$this->escapeString($phone);
}
$this->update('user', $data, 'email = "'.$email.'" AND phone = "'.$phone.'"');
$res = $this->getResult();
}
Question:
I have an array of post values that looks like:
$_POST['children'] = array(
[0]=>array(
'fname' => 'name',
'mname' => 'mname',
'lname' => 'lname,
'dob' => '10/17/1992
),
[1]=>array(
'fname' => 'name',
'mname' => 'mname',
'lname' => 'lname,
'dob' => '10/17/1992
),
[2]=>array(
'fname' => 'name',
'mname' => 'mname',
'lname' => 'lname,
'dob' => '10/17/1992
)
);
// and so on
I have a script set up in my my view functions that checks for old input, and repopulates the values in the case that the form does not validate. I need to find a way to return the above array as a series of key/value pairs i.e.
'children[0][fname]' = 'name'
'children[0][mname]' = 'mname'
'children[0][lname]' = 'lname'
// ... and so on for all fields
Ideally, I would like this to work with an array of any depth, which makes me think I need some sort of recursive function to format the keys. I am having a terrible time getting my head around how to do this.
What I have tried
I have been working with the following function:
function flatten($post_data, $prefix = '') {
$result = array();
foreach($post_data as $key => $value) {
if(is_array($value)) {
if($prefix == ''){
$result = $result + flatten($value, $prefix. $key );
}else{
$result = $result + flatten($value, $prefix. '[' . $key . ']');
}
}
else {
$result[$prefix . $key .''] = $value;
}
}
return $result;
}
This gets me somewhat close, but isn't quite right. It returns the following when I feed it my $_POST array
[children[1]fname] => test
[children[1]mname] => test
[children[1]lname] => test
[children[1]dob] =>
// Expecting: children[1][fname] => test
// ...
Or is there potentially an easier way to accomplish this?
What ended up working for me:
function flatten($post_data, $prefix = '') {
$result = array();
foreach($post_data as $key => $value) {
if(is_array($value)) {
if($prefix == ''){
$result = $result + flatten($value, $prefix. $key );
}else{
$result = $result + flatten($value, $prefix. '[' . $key . ']');
}
}
else {
if( $prefix == ''){
$result[$prefix . $key.''] = $value;
}else{
$result[$prefix . '['.$key.']'.''] = $value;
}
}
}
return $result;
}
it wasn't accounting for the return value of the last call of the recursive function being a scalar value. The addition of these this if/else statement seems to have resolved it.
if( $prefix == ''){
$result[$prefix . $key.''] = $value;
}else{
$result[$prefix . '['.$key.']'.''] = $value;
}
Let's say I wanted to check to see if a variable is empty and then do something... I can do this:
if ( empty($phone) ) { $phone = 'Not Provided'; }
But I want to do that for a bunch of items. So I'm thinking an array and a loop, so something like this:
$optionalFieldsArray = array($phone, $address, $city, $state, $zip);
foreach ($optionalFieldsArray as $value) {
//what goes here????
}
Is this foreach a resonable way to do it, where I could check if $phone, $address, $city, etc. are empty and assign the "Not Provided" string to it when it is?
If so, can someone help me with the syntax that goes inside that loop?
you can do like this:
<?php
$required_vars = array( 'phone', 'address', 'city', 'state', 'zip' );
foreach( $required_vars as $required_var ) {
if( empty( $$required_var ) )
$$required_var = 'Not Provided'; // $$var -> variable with name = value of $var
}
?>
check the above code yourself. then only you can understand how it works. because it is confusing concept.
$optionalFieldsArray = array('phone'=>$phone, 'address'=>$address, 'city'=>$city, 'state'=>$state, 'zip'=>$zip);
foreach ($optionalFieldsArray as $key => $value) {
if ( empty($value) ) { $optionalFieldsArray[$key] = 'Not Provided'; }
}
echo "<pre>";
print_r($optionalFieldsArray);
echo "</pre>";
I'd say something like -
$optionalFieldsArray = array($phone, $address, $city, $state, $zip);
foreach ($optionalFieldsArray as $key => $value) {
if ( empty($optionalFieldsArray[$key]) ) {
$optionalFieldsArray[$key] = 'Not Provided';
}
}
Combine the two code examples you provided, and use strings as keys in the optional array:
$optional = array(
'phone' => $phone,
'address' => $address,
'city' => $city,
'state' => $state,
'zip' => $zip,
);
foreach ($optional as $type => $value) {
if ($value == null) {
echo "The {$type} field is empty!<br>";
}
}
$optionalFieldsArray = array($phone, $address, $city, $state, $zip);
foreach($optionalFieldsArray as $k => $v) {
// you could check for !empty here if you wanted too
$optionalFieldsArray[$k] = empty($v) ? 'Not Provided' : $v;
}
print_r($optionalFieldsArray);
Input Vars:
$phone = "1234567899";
$address = "";
$city = "";
$state = "";
$zip = "";
Output:
Array ( [0] => 1234567899 [1] => Not Provided [2] => Not Provided [3] => Not Provided [4] => Not Provided )