Insertar/actualizar función auxiliar usando PDO

Resuelto Your Common Sense asked hace 54 años • 11 respuestas

Tengo una función auxiliar muy simple para producir una declaración SET para el uso tradicional del controlador MySQL simple:

function dbSet($fields) {
  $set='';
  foreach ($fields as $field) {
    if (isset($_POST[$field])) {
      $set.="`$field`='".mysql_real_escape_string($_POST[$field])."', ";
    }
  }
  return substr($set, 0, -2); 
}

usado así

$id = intval($_POST['id']);
$fields = explode(" ","name surname lastname address zip fax phone");
$_POST['date'] = $_POST['y']."-".$_POST['m']."-".$_POST['d'];
$query  = "UPDATE $table SET ".dbSet($fields)." stamp=NOW() WHERE id=$id";

hace que el código sea bastante SECO y fácil pero flexible al mismo tiempo.

Debo preguntar si alguien está dispuesto a compartir una función similar, utilizando la función de declaraciones preparadas de PDO.

Todavía tengo dudas sobre cómo lograr esto.
¿Existe una forma directa y sencilla de utilizar declaraciones preparadas por PDO para insertar datos? ¿Qué forma debería tener? ¿Ayudante del generador de consultas? ¿O insertar un asistente de consulta? ¿Qué parámetros debería tomar?

Espero que pueda ser lo suficientemente fácil como para usarlo como respuesta aquí en SO. Porque en cada tema podemos ver recomendaciones de uso de declaraciones preparadas, pero no hay un solo buen ejemplo. Un ejemplo de la vida real, quiero decir. Creo que escribir bind_param() 20 veces no es un buen estilo de programación. E incluso 20 signos de interrogación también.

Your Common Sense avatar Jan 01 '70 08:01 Your Common Sense
Aceptado

Normalmente tengo una clase que extiende PDO, pero mi clase es bastante personalizada. Si lo limpio y lo pruebo, lo publicaré más adelante. Sin embargo, aquí hay una solución para su sistema.

function dbSet($fields, &$values) {
    $set = '';
    $values = array();

    foreach ($fields as $field) {
        if (isset($_POST[$field])) {
            $set .= "`$field` = ?,";
            $values[] = $_POST[$field];
        }
    }

    return rtrim($set, ',');
}

$fields = explode(" ","name surname lastname address zip fax phone date");
$_POST['date'] = $_POST['y']."-".$_POST['m']."-"$_POST['d'];

$query  = "UPDATE $table SET ".dbSet($fields, $values).", stamp=NOW() WHERE id=?";
$values[] = $id;

$dbh->prepare($query);
$dbh->execute($values);  

Puede que esto no sea perfecto y podría necesitar ajustes. Tiene en cuenta que $dbhestá configurado con una conexión PDO. A la espera de cualquier problema menor de sintaxis que haya cometido, debería funcionar.

EDITAR

Realmente, creo que elegiría Doctrine ORM (u otro ORM). A medida que configura el modelo y agrega toda la validación allí, es tan simple como:

$table = new Table();
$table->fromArray($_POST);
$table->save();

Eso debería poblar los contenidos fácilmente. Por supuesto, esto es con un ORM, como Doctrine.

ACTUALIZADO

Hice algunos ajustes menores al primer código, como volver a colocarlo issety usarlo rtrimsobre substr. Para trabajar en proporcionar una maqueta de una clase de extensión PDO, solo hay que diseñar la forma de hacerlo y realizar algunas pruebas unitarias para asegurarse de que funcione.

Jim avatar Sep 22 '2010 20:09 Jim

Gracias a todos.
Cada respuesta fue útil y desearía poder dividir la recompensa.

Al final, para mi sorpresa, pude hacerlo de la misma manera que antes, según la respuesta aceptada.

$fields = array("login","password");
$_POST['password'] = MD5($_POST['login'].$_POST['password']);
$stmt = $dbh->prepare("UPDATE users SET ".pdoSet($fields,$values)." WHERE id = :id");
$values["id"] = $_POST['id'];
$stmt->execute($values);

Se puede incluir en una función auxiliar, pero dudo que sea necesario. Acortará el código en una sola línea.

código pdoSet:

function pdoSet($fields, &$values, $source = array()) {
  $set = '';
  $values = array();
  if (!$source) $source = &$_POST;
  foreach ($fields as $field) {
    if (isset($source[$field])) {
      $set.="`$field`=:$field, ";
      $values[$field] = $source[$field];
    }
  }
  return substr($set, 0, -2); 
}
Your Common Sense avatar Oct 13 '2010 08:10 Your Common Sense

Extendería la clase Core PDO y agregaría un método como este:

class Database extends PDO
{
    public function QueryFromPost($Query,$items)
    {
        $params = array();
        $Query .= ' WHERE ';

        foreach($items as $key => $default)
        {
             $Query .= ' :' . $key. ' = ' . $key;
             if(isset($_POST[$key]))
             {
                  $params[':' . $key] = $_POST[$key];
             }else
             {
                 $params[':' . $key] = $default;
             }
        }
        $s = $this->prepare($Query);
        return $s->execute($params);
    }
}

Entonces usa así

$db = new Database(/*..Default PDO Params*/);
$statement = $db->QueryFromPost('SELECT * FROM employees',array('type' => 'plc'));
foreach($preparedStatement->fetchAll() as $row)
{
    //...
}

Pero como ya se ha dicho que deberías estar MUY cansado de lo que intentas hacer, necesitas validar tus datos, han sido desinfectados pero tú no validados.

RobertPitt avatar Sep 22 '2010 21:09 RobertPitt

He estado parcheando algo trivial para lo que considero casos recurrentes de vinculación de parámetros. http://fossil.include-once.org/hybrid7/wiki/db

De todos modos; proporciona algunos marcadores de posición de declaraciones preparadas alternativas . Su ejemplo podría abreviarse a:

db("UPDATE table SET :, WHERE id=:id", $columns[], $where[]);

Este caso solo funciona con parámetros con nombre, por lo que $set sería array("name"=>..) y $where=array("id"=>123). Se :,expande en la primera matriz que pasa. Se reemplaza con pares de nombre=:nombre separados por comas (por eso su mnemotécnico es ).:,

Hay algunos marcadores de posición más :, :& ::y :?para diferentes casos de uso. Sólo que ??es realmente una especie de estándar. Por lo tanto, es necesario acostumbrarse, pero simplifica significativamente las declaraciones preparadas y el enlace de matrices (que PDO no hace de forma nativa).

mario avatar Sep 22 '2010 21:09 mario