Разработчику. Сборник рецептов PHP
Задавайте вопросы

Программное создание запросов

Вернуться назад

Задача

Необходимо создать запрос INSERT или UPDATE из массива, составленного из имен полей. Например, требуется вставить нового пользователя в базу данных. Вместо того чтобы жестко запрограммировать каждое поле информации о пользователе (имя пользователя, почтовый адрес, дата рождения и т. д.), имена полей размещаются в массиве, и на основании этой информации и строится запрос. Так проще осуществлять поддержку, особенно если требуется, в зависимости от обстоятельств, выполнять запросы INSERT или UPDATE с одним и тем же набором полей.

Решение

Для выполнения запроса UPDATE постройте массив из пар поле/значение, а затем объедините все элементы этого массива с помощью функции join():

$fields = array('symbol','planet','element');

$update_fields = array();
foreach ($fields as $field) {
     $update_fields[] = "$field = " . $dbh->quote($GLOBALS[$field]);

}
$sql = 'UPDATE zodiac SET ' . join(',',$update_fields)
     . ' WHERE sign = ' . $dbh->quote($sign);

Для запроса INSERT создайте массив значений в порядке следования полей и постройте запрос, применяя функцию join() к каждому массиву:

$fields = array('symbol','planet','element');

$insert_values = array();
foreach ($fields as $field) {
     $insert_values[] = $dbh->quote($GLOBALS[$field]);
}
$sql = 'INSERT INTO zodiac (' . join(',',$fields) . ') VALUES ('
     . join(',',$insert_values) . ')';

Для PEAR DB версии 1.3 или старше следует применять метод DB:: autoPrepare():

$fields = array('symbol','planet','element');

// UPDATE: вставьте выражение WHERE
$update_prh = $dbh->autoPrepare('zodiac',$fields,DB_AUTOQUERY_UPDATE,
                 'sign = ?');
$update_values = array();
foreach ($fields as $field) { $update_values[] = $GLOBALS[$field]; }
$update_values[] = $GLOBALS['sign'];
$dbh->execute($update_prh,$update_values);

// INSERT: без выражения WHERE
$insert_prh = $dbh->autoPrepare('zodiac',$fields,DB_AUTOQUERY_INSERT);
$insert_values = array();
foreach ($fields as $field) { $insert_values[] = $GLOBALS[$field]; }
$dbh->execute($insert_prh,$insert_values);

Обсуждение

В последних версиях DB метод DB::autoPrepare() короткий, и с ним легко работать. PHP 4.2.2 поставляется с версией DB 1.2. Самую свежую версию DB можно загрузить с PEAR. Функция method_exists() позволяет проверить, поддерживает ли ваша версия DB функцию autoPrepare():

if (method_exists($dbh,'autoPrepare')) {
$prh = $dbh->autoPrepare('zodiac',$fields,DB_AUTOQUERY_UPDATE',
                'sign = ?');

// ...
} else {
     error_log("Can't use autoPrepare");
     exit;

}

Если функция DB::autoPrepare() недоступна, то можно прибегнуть к показанным в разделе «Решение» приемам обработки массивов, выполняющим ту же самую работу. Если сгенерированная последовательность целых чисел выступает в качестве первичных ключей, то можно объединить способы создания двух запросов в одну функцию. Функция определяет, существует ли запись, а затем генерирует корректный запрос, включая новый идентификатор, как показано в функции pc_build_query() примера (Описанного ниже):

Пример: pc_build_query()

function pc_build_query($dbh,$key_field,$fields,$table) {

if (! empty($_REQUEST[$key_field])) {
     $update_fields = array();

foreach ($fields as $field) {
$update_fields[] = "$field = ".$dbh->quote($_REQUEST[$field]);
}
return "UPDATE $table SET " . join(',',$update_fields) .
     " WHERE $key_field = ".$_REQUEST[$key_field];
} else {
     $insert_values = array();
     foreach ($fields as $field) {
          $insert_values[] = $dbh->quote($_REQUEST[$field]);
}
$next_id = $dbh->nextId($table);
return "INSERT INTO $table ($key_field," . join(',',$fields) .
     ") VALUES ($next_id," . join(',',$insert_values) . ')';
     }
}

С помощью этой функции можно сделать простую страничку для редактирования всей информации из таблицы zodiac:

require 'DB.php';

$dbh = DB::connect('mysql://test:@localhost/test');
$dbh->setFetchMode(DB_FETCHMODE_OBJECT);

$fields = array('sign','symbol','planet','element',
                'start_month','start_day','end_month','end_day');

switch ($_REQUEST['cmd']) {
case 'edit':
     $row = $dbh->getRow('SELECT ' . join(',',$fields) .
                    " FROM zodiac WHERE id = ?",array($_REQUEST['id']));

case 'add':
     print '<form method="post" action="'.$_SERVER['PHP_SELF'].'">';
     print '<input type="hidden" name="cmd" value="save">';
     print '<table>';
     if ('edit' == $_REQUEST['cmd']) {
          printf('<input type="hidden" name="id" value="%d">',
               $_REQUEST['id']);
}
foreach ($fields as $field) {
     if ('edit' == $_REQUEST['cmd']) {
           $value = htmlspecialchars($row->$field);
      } else {
           $value = '';
}
     printf('<tr><td>%s: </td><td><input type="text" name="%s" value="%s">,
               $field,$field,$value);
     printf('</td></tr>');

}
     print '<tr><td></td><td><input type="submit" value="Save"></td></tr>';
     print '</table></form>';
      break;
case 'save':
     $sql = pc_build_query($dbh,'id',$fields,'zodiac');
     if (DB::isError($sth = $dbh->query($sql))) {
          print "Couldn't add info: ".$sth->getMessage();
} else {
     print "Added info.";
}
     print '<hr>';
default:
     $sth = $dbh->query('SELECT id,sign FROM zodiac');
     print '<ul>';
     while ($row = $sth->fetchRow()) {
           printf('<li> <a href="%s?cmd=edit&id=%s">%s</a>',
                    $_SERVER['PHP_SELF'],$row->id,$row->sign);
}
     print '<hr><li> <a href="'.$_SERVER['PHP_SELF'].'?cmd=add">Add New</a>';
     print '</ul>';
      break;
}

Оператор switch на основе значения элемента $_REQUEST['cmd'] определяет, какое действие предпримет программа. Если $_REQUEST['cmd'] равен add или edit, то программа показывает текстовые окна для каждого поля из массива $fields, как показано на рис. (ниже) Если значение элемента $_REQUEST['cmd'] равно edit, то значения для строк с указанным $id загружаются из базы данных и отображаются в качестве значений по умолчанию. Если $_REQUEST['cmd'] равен save, то программа вызывает функцию pc_build_query(), чтобы сгенерировать соответствующий запрос на вставку или обновление информации в базе данных. После сохранения данных (или если ни один элемент в $_REQUEST['cmd']

Добавление и редактирование записи

не определен), программа выводит список всех знаков зодиака, как показано на рис. ниже:

Вывод списка записей

Определяя, какой запрос, INSERT или UPDATE, следует строить, функция pc_build_query() основывается на присутствии переменной запроса $_REQUEST['id'] (поскольку id передается в переменную $key_field). Еси переменная $_REQUEST['id'] не пуста, то эта функция конструирует запрос UPDATE для модификации строки с указанным идентификатором. Если переменная $_REQUEST['id'] пуста (или она вовсе не была установлена), то функция генерирует новый идентификатор с помощью функции nextId() и использует этот новый идентификатор в запросе INSERT, который добавляет строку в таблицу.

Вернуться назад

Рейтинг@Mail.ru

Яндекс.Метрика

Индекс цитирования


Рейтинг Сайтов ДОСКИ.РУ