$paramsArray[‘fname’] = $_POST[‘fname’]; $paramsArray[‘sname’] = $_POST[‘sname’];
Всех, кому интересно, как я решил такую задачу, приглашаю под кат.
Для начала стоит рассказать немного о PDO.
Дело в том, что я стал использовать PDO в своих проектах не так давно. Положительных эмоций была масса. Во-первых, практически не приходилось больше самому заботится о «чистке» передаваемых параметров: все, что могло нанести вред базе, благополучно отметалось при подготовке запроса. Во-вторых сменить СУБД, чаще всего, можно было заменой одной единственной строки. Плюс ко всему, мы имеем возможность использовать сразу несколько СУБД, что в некоторых случаях может быть полезно. В-третьих, параметры легко передавать: поместили все в массив и — готово. Можно использовать как безымянные, на манер JDBC, так и именные параметры.
Пример:
require_once('config.php'); $dbc = new PDO("mysql:host=".HOST.";dbname=".DATA_BASE_NAME.";charset=utf8", USER, PASSWORD); #Для безымянных $sqlString = "INSERT INTO table1(`name`, `text`, `date`) VALUES (?, ?, ?)"; $params = array("First Post", "Hello World", "01/01/2013"); $statment = $dbc->prepare($sqlString); $statment->execute($params); #Для именных $sqlString = "INSERT INTO table1(`name`, `text`, `date`) VALUES (:name, :text, :date)"; $params = array("name" => "Second Post", "text" => "Say Hello", "date" => "01/02/2013"); $statment = $dbc->prepare($sqlString); $statment->execute($params);
Отличительной чертой именных параметров является то, что их можно передавать в любом порядке. Собственно, за это я их и полюбил.
$params = array("text" => "Habrahabr", "name" => "Third Post", "date" => "01/03/2013"); $statment->execute($params);
Итак, соберем все в единое целое и напишем немного кода.
class DB { static private $dbc static public function dbc () { try { require_once('config.php'); self::$dbc = new PDO("mysql:host=".HOST.";dbname=".DATA_BASE_NAME.";charset=utf8", USER, PASSWORD); } catch(PDOException $exc) { Logger::setLog($exc->getMessage()); return false; } } static public function insert($sqlString, $object) { if (!isset(self::$dbc)) { self::dbc(); } try{ $statment = self::$dbc->prepare($sqlString); $statment->execute((array)$object); return self::$dbc->lastInsertId(); } catch (PDOException $exc) { Logger::setLog($exc->getMessage()); return false; } } }
Первый метод создает новое подключение. Второй выполняет запросы INSERT. Если подключение не было создано, создает его. PDO умеет выбрасывать исключения, так что желательно их перехватить. Можно передавать как массивы, так и объекты. Лично я чаще предпочитаю вторые.
За обработку форм назначим класс PostController.
class PostController { const INSERT = "INSERT INTO `posts` (`name`, `text`, `date`) VALUES (:name, :text, :date)"; public static function post(){ if (isset($_POST["new_post"])) { $insertObject = NULL; $insertObject->name = $_POST["name"]; $insertObject->text = $_POST["text"]; $insertObject->date = $_POST["date"]; DB::insert(self::INSERT, $insertObject); } } }
А теперь представьте, что у нас достаточно много форм, или таблицы состоят из 10 — 20 полей. А если и то и другое? Записи вида $insertObject->name = $_POST[«name»]; будут захламлять объемную часть кода. Если честно, первая идея, которая мне пришла в голову, была написать нечто подобное:
DB::insert(self::INSERT, $_POST);
Конечно, необходимо чтобы имена элементов формы соответствовали именам параметров (может оно и к лучшему?). «Пусть PDO сам найдет и подставит необходимые параметры», — так я думал и ошибался. Как оказалось, число элементов массива должно быть равным числу параметров, иначе PDO выкинет исключение. Временным решением стало удаление не интересующих меня данных. Например так:
class PostController { const INSERT = "INSERT INTO `posts` (`name`, `text`, `date`) VALUES (:name, :text, :date)"; public static function post(){ if (isset($_POST["new_post"])) { $insertArray = $_POST; unset($insertArray["new_post"]); DB::insert(self::INSERT, $insertArray); } } }
Решение действительно работало, код сократился, хотя и стал менее понятным. Однако, в этом году в рамках курсовой работы мне пришлось трудиться над одним WEB сервисом для университета. Проблема заключалась в том, что была одна огромная форма с множеством элементов. В базе было много таблиц, каждая из которых, в свою очередь, содержала множество полей. Выбор таблиц и полей для вставки зависел от махинаций на форме. И первый, и второй способы требовали написания солидных кусков кода, чего из-за ограниченности сроков делать совершенно не хотелось. Спустя 10 минут размышлений в голову пришел один метод, который бы, разбирая строку запроса SQL, сам находил данные для параметров, сопоставлял их, и возвращал готовый объект для вставки.
class PostController { const INSERT = "INSERT INTO `posts` (`name`, `text`, `date`) VALUES (:name, :text, :date)"; #Шаблон поиска параметров. #Если кто-то использует и другие символы, можно их легко добавить const PATTERN = "|:(([-A-Za-z1-9_])*?)|U"; public static function findObjectInPost($queryString) { $fields = array(); $postObject = NULL; preg_match_all(self::PATTERN, $queryString, $fields); foreach ($fields[1] as $value) { if (isset($_POST[$value])) { $sender = $_POST[$value]; if (strcasecmp($sender, "") == 0) { $sender = NULL; } $postObject->$value = $sender; } } return $postObject; } public static function post(){ if (isset($_POST["new_post"])) { unset($_POST["new_post"]); DB::insert(self::INSERT, $_POST); } } }
Суть метода findObjectInPost в следующем: регулярным выражением находим параметры, перебираем полученные параметры, ищем совпадения в массиве $_POST, если такой элемент будет найден, добавляем его, как новое поле объекта, данные записываем в это поле.
В результате получаем быструю обработку запроса в одну строку:
public static function post(){ if (isset($_POST["new_post"])) { DB::insert(self::INSERT_POST, $insertObject = self::findObjectInPost(self::INSERT_POST)); } if (isset($_POST["new_company"])) { DB::insert(self::INSERT_COMPANY, $insertObject = self::findObjectInPost(self::INSERT_COMPANY)); } if (isset($_POST["new_author"])) { DB::insert(self::INSERT_AUTHOR, $insertObject = self::findObjectInPost(self::INSERT_AUTHOR)); } }
Резюме.
Таким образом, можно автоматизировать процесс задания именных параметров для выполнения SQL запроса, тем самым сократив код и время, затрачиваемое на разработку. Разумеется, решение применимо к любым запросам с именными параметрами.
Главным минусом является то, что имена элементов формы должны в точности соответствовать именам параметров, хотя я считаю, что, возможно, так и должно быть, поскольку это упрощает проектирование.
Вероятно, мое решение не является оптимальным. Применительно к данной проблеме, я даже уверен, что существуют более эффективные и удобные способы добиться похожего результата, однако, оно помогло мне сэкономить несколько часов, которые позже были потрачены на долгожданный сон. Надеюсь оно принесет пользу и вам.
ссылка на оригинал статьи http://habrahabr.ru/post/168479/
Добавить комментарий