Sasha
Sasha

Reputation: 8705

PHP PDO - Update with bindValue (set and where parametes are same)

This is a bit confusing for me, so I will try to explain it the best I can.

I am running update but nothing is happens.

This is the query which I get:

"UPDATE users SET name = :name, surname = :surname WHERE name = :name AND surname = :surname"

I start the query like this:

$data = ['name' => 'Sasha', 'surname' => 'M'];

$user = $users->where(['name' => 'TestName', 'surname' => 'TestSurname'])->update($data);

This is the update function:

public function update($data)
    {
        $fields = explode(',', $this->prepareFields($data));
        $values = explode(',', $this->prepareValues($data));

        $i = 0;
        $count = count($fields);

        $query = "UPDATE {$this->_tablename} SET ";

        for($i; $i < $count; $i++):
            $query .= $fields[$i] . " = " . $values[$i] . ',';
        endfor;

        $query = rtrim($query, ',');
        $query .= " WHERE " . rtrim($this->_dbWhere, ' AND ');

        $this->query($query);

        $this->bindData($data);

        $this->_dbBind = call_user_func_array('array_merge', $this->_dbBind);
        $this->bindData($this->_dbBind);

        $this->execute();

        return $this->lastInsertId();
    }

Where function:

public function where($field, $value = null)
    {

        if(!is_array($field)):
            $this->_dbWhere  .= $field . ' = :' . $field . ' AND ';
            $this->_dbBind[] = [$field => $value];
        else:

           foreach($field as $key => $value):
               $this->_dbWhere .= $key . ' = :' . $key . ' AND ';
                $this->_dbBind[] = [$key => $value];
           endforeach;

        endif;

        return $this;
    }

Bind data function:

public function bindData($data)
    {
        foreach ($data as $key => $value) :
            $this->bind(':' . $key, $value);
        endforeach;
    }

public function bind($param, $value, $type = null){

    if (is_null($type)) {
        switch (true) {
            case is_int($value):
                $type = \PDO::PARAM_INT;
                break;
            case is_bool($value):
                $type = \PDO::PARAM_BOOL;
                break;
            case is_null($value):
                $type = \PDO::PARAM_NULL;
                break;
            default:
                $type = \PDO::PARAM_STR;
        }
    }

    $this->stmt->bindValue($param, $value, $type);
}

Prepare fields and prepare values:

public function prepareFields($data)
    {
        return $fields = implode(', ', array_keys($data));
    }

    public function prepareValues($data)
    {
        $values = implode(', :', array_keys($data));

        return ':' . $values;
    }

Query function:

public function query($query){
        $this->stmt = $this->handler->prepare($query);
    }

Upvotes: 1

Views: 600

Answers (1)

RobP
RobP

Reputation: 9522

The crux of this is that you use the same placeholder :fieldname in the WHERE clause and in the SET portion of the statement. You do need to correct other small issues raised here, but a simple solution is to make this change in the where() function:

    if(!is_array($field)):
        // make up a placeholder name distinct from the one used in SET clause
        $field_placeholder = ":where_".$field
        $this->_dbWhere  .= $field . ' = ' . $field_placeholder . ' AND ';
        $this->_dbBind[] = [$field_placeholder => $value];
    else:

Upvotes: 2

Related Questions