6 авг. 2013
Magento использует модели для работы с данными, это обеспечивает удобный доступ к ним и обработку. Используя грамотно именованные методы и "умную" абстракцию, Varien скрывает от нас сложную SQL реализацию необходимую для операций с данными.
Это делает изучение моделей проще, увеличивает скорость операций и повышает скорость отклика сайта. Это особенно справедливо когда речь идет о моделях использующих EAV архитектуру. Однако, есть ситуации когда прямые SQL запросы могут быть быстрее и проще. Как пример можно привести массовое обновление товарных цен. Достаточно легко написать код который будет пробегаться по всем товарам и пересчитывать цены. В то время как отдельная правка каждого продукта, при большом массиве данных, будет занимать очень много времени. Чтобы это побороть, можно использовать прямые SQL запросы, что позволит обновить 1000 продуктов за 1-2 секунды.
Подключение к БД в magento.
По умолчанию magento автоматически подключается к базе данных и обеспечивает два независимых ресурса доступа к данным: core_read и core_write. Как вы можете догадаться, первый используется для чтения из БД, а второй для записи. Это особенно важно, убедиться что используется правильный ресурс, особенно при создании модулей, которые разойдутся по всему миру.
<?php /** * Получение ресурсной модели */ $resource = Mage::getSingleton('core/resource'); /** * Установка соединения для чтения */ $readConnection = $resource->getConnection('core_read'); /** * Установка соединения для записи */ $writeConnection = $resource->getConnection('core_write');
Названия таблиц и префиксы
При установке magento, можно задать опцию использовать префиксы в таблицах или нет. Префикс - это строка символов, которая добавляется в начало имени таблицы БД. Это полезно, если вы устанавливаете множественную систему в которой нужно изолировать данные приложений друг от друга. К счастью, magento имеет встроенную функцию добавления префикса к имени определенной таблицы.
Получения названия таблицы из строки
<?php /** * Получение ресурсной модели */ $resource = Mage::getSingleton('core/resource'); /** * Получение имени таблицы */ $tableName = $resource->getTableName('catalog_product_entity'); /** * Если префикс был 'mage_' то на выходе * мы получим mage_catalog_product_entity */ echo $tableName;
Получение названия таблицы из названия entity-сущности
<?php /** * Получение ресурсной модели */ $resource = Mage::getSingleton('core/resource'); /** * Получение имени таблицы */ $tableName = $resource->getTableName('catalog/product'); /** *Если префикс был 'mage_' то на выходе * мы получим mage_catalog_product_entity */ echo $tableName;
Чтение из БД
Хотя модели magento скрывают всю сложность EAV системы, они иногда запрашивают гораздо больше данных, чем нужно. Например, если у вас есть product ID и вы хотите его SKU, будет гораздо быстрее сделать простой запрос чем грузить целиком модель продукта.
метод Varien_Db_Select::fetchAll
Метод принимает запрос в качестве параметра, и возвращает результаты в качестве массива.
<?php /** * Поучение ресурсной модели */ $resource = Mage::getSingleton('core/resource'); /** * Установка соединения для чтения */ $readConnection = $resource->getConnection('core_read'); $query = 'SELECT * FROM ' . $resource->getTableName('catalog/product'); /** * Выполнение запроса и сохранение результата в $results */ $results = $readConnection->fetchAll($query); /** * Вывод результатов */ var_dump($results);
метод Varien_Db_Select::fetchCol
Этот метод похож на fetchAll за тем исключением что он возвращает первый элемент из каждой результирующей колонки. В коде примера ниже, мы используем Varien_Db_Select::fetchCol для получения всех SKU из базы в виде массива.
<?php /** * Получение ресурсной модели */ $resource = Mage::getSingleton('core/resource'); /** * Установка соединения для чтения */ $readConnection = $resource->getConnection('core_read'); /** * Получение имени таблицы */ $table = $resource->getTableName('catalog/product'); /** * Выполнение запроса и сохранение результатов в $results */ $sku = $readConnection->fetchCol('SELECT sku FROM ' . $table . '); /** * Вывод результатов */ var_dump($results);
Попробуйте оба метода и вы поймете разницу. fechCol возвращает все значения в едином массиве, тогда как значения SKU полученные методом fetchAll находятся каждое в отдельном подмассиве.
метод Varien_Db_Select::fetchOne
В отличие от предыдущих двух методов Varien_Db_Select::fetchOne возвращает только первое значение из первой колонки результатов. Оно не обернуто в массив. В примере мы получили SKU для продукта с ID равным 44.
<?php /** * Получение ресурсной модели */ $resource = Mage::getSingleton('core/resource'); /** * Установка соединения для чтения */ $readConnection = $resource->getConnection('core_read'); /** * Получение имени таблицы */ $table = $resource->getTableName('catalog/product'); /** * Установка product ID */ $productId = 44; $query = 'SELECT sku FROM ' . $table . ' WHERE entity_id = ' . (int)$productId . ' LIMIT 1'; /** * Выполнение запроса и запись результата в $sku */ $sku = $readConnection->fetchOne($query); /** * Вывод SKU на экран */ echo 'SKU: ' . $sku . '<br/>';
Запись в БД
Когда в БД сохраняется модель, происходит передача множества данных, даже таких, о которых вы могли быть не в курсе. Как пример, сохранение модели продукта может занять пару секунд из-за большого количества связанных данных и индексации. Это приемлемо, если вы хотите сохранить все данные о продукте, но если нужно только обновить артикул, это выглядит расточительно.
На следующем примере можно будет понять, как по известному ID продукта можно изменить его артикул.
<?php /** * Получение ресурсной модели */ $resource = Mage::getSingleton('core/resource'); /** * Установка соединения для записи */ $writeConnection = $resource->getConnection('core_write'); /** * Получение имени таблицы */ $table = $resource->getTableName('catalog/product'); /** * Установка product ID */ $productId = 10; /** * Установка нового значения SKU * * Если если входные данные являются статическими, рассмотрите возможность * использования объекта Varien_Db_Select для вставки данных */ $newSku = 'new-sku'; $query = "UPDATE {$table} SET sku = '{$newSku}' WHERE entity_id = " . (int)$productId; /** * Выполнение запроса */ $writeConnection->query($query);
Для тестирования используйте ранее рассмотренный метод вывода одного единственного значения
Varien_Db_Select
Varien_Db_Select, затронутый в этом примере - это еще одна очень удобная опция для извлечения/записи информации. Не только из-за простоты использования, но также по причине обеспечения уровневой безопасности, которая, будучи грамотно применена, являться непроницаемой. Более подробно Varien_Db_Select (он же Zend_Db_Select) будет рассмотрен в следующих статьях.
Заключение
Иногда прямые SQL запросов в Magento необходимы, однако пожалуйста, будьте осторожны!!! Magento модели существует в том числе по причине обеспечения слоя безопасности, который вам придется вручную добавить в свой собственный прямой SQL запрос. Будьте уверены, что не допустите любого пользовательского вмешательства, и, когда это возможно, придерживайтесь методов моделей Magento! Если вы не можете придерживаться моделей Magento , рассмотрите возможность использования Varien_Db_Select, это не убережет вас от ошибок, но это добавит почти непроницаемый слой безопасности ваших запросов к базе данных.