Абстракція БД

Коли я тільки починав писати на PHP, ООП я володів, мабуть, на рівні синтаксису, не більше. У той час мені цілком вистачало функцій mysql_*. З часом, досвіду ставало більше, я починав замислюватися про оптимізацію. Цей топік описує еволюцію мого коду.


Першим кроком стало написання простенького класу, який полегшував роботу з БД. Коду стало не на багато менше, в основному спрощувалися типові запити. Також автоматично екранувалися вхідні параметри. Бонусом, з'явилася можливість використовувати код з БД, відмінних від MySQL (написавши клас з таким же інтерфейсом). Принаймні, більшість запитів переписувати не довелося б. Код виглядав приблизно так:

$db = new MysqlDb($server, $user, $pass, $db, $prefix);

$ db- > select ($ key, $ value) ;//Можливо було багато варіантів запиту за допомогою різних параметрів.

while ($db->fetch()) {

$row = $db->getRow();

}

Або $ rows = $ db- > getResult ();

* This source code was highlighted with Source Code Highlighter.

Щоб ще спростити роботу з БД, я став використовувати Active Record. Моє рішення багато в чому програвало стороннім, але мені тоді цього вистачало. У той час з'явився Zend Framework, тому деякі ідеї взяті з нього. Самі класи працювали через PDO (хоча, бібліотека для роботи через php_mysql теж була).

Приклад коду:

$db = Cms_Db::factory('MySQL');

$db->connect($server, $user, $pass, $db, $prefix);

$element = $db->select('id', $id);

$element->name = 'New name';

$element->update();* This source code was highlighted with Source Code Highlighter.

Цей варіант прожив досить довго. Але з часом і його стало не вистачати. Клас розвивався екстенсивно, додавалися нові методи для обробки типових запитів. До того часу, вийшов стабільний реліз Zend Framework. Стало набридати постійно додавати нові типи запитів.

Згодом я почав писати моделі під основні об'єкти сайту. Всередині все ще працював мій старий клас, але зовні всі операції виглядали досить прозоро. Такий підхід мені сподобався, і щоб спростити реалізацію, я вирішив використовувати ORM. Спочатку, придивлявся до Doctrine і Propel, але в кінці вирішив написати свою реалізацію.

Робота з БД здійснюється через Zend_Db, для гнучкості також застосовується Zend_Db_Select. Опис моделі багато в чому схожий на Doctrine. Але у мене модель містить також дані, призначені для опису подання деяких даних. Наведу приклад:

class Model_News extends Cms_Essence_Model

{

public function setDefinition()

{

$ this- > addField ('name','Заголовок')

- > addField («link», «Адреса», «link»)

- > addField («date», «Дата публікації», «date»)

- > addField («description», «Короткий опис», «text, 255», array (

'validate' => 'isVoid',

'detail' => true

))

- > addField («content», «Зміст», «editor», array (

'detail' => true,

'minLength' => 40,

'validate' => array('isVoid', 'minLength'))

))

->setOption('editorTableClass', 'newsTable');

}

}

$element = Cms_Essence::get('Model_News')->getById(2);* This source code was highlighted with Source Code Highlighter.

Як і в повноцінних ORM, також можна описати зв'язки таблиць і використовувати код на зразок:

$user = Cms_Essence::get('Model_User')->getJoined('Model_Group', 'name', 'megahertz');

$groupName = $user->group->name;* This source code was highlighted with Source Code Highlighter.

Звичайно, за зручністю таких запитів мені ще далеко до повноцінних ORM, але поки мене такий варіант влаштовує.

Такий підхід дозволяє писати мінімум коду. Маючи описану модель, я можу використовувати її в адмінці, при цьому не написавши ні рядка коду. Причому адмінка може бути будь-якого типу, класична, ajax редактор на сайті, через RPC на іншому сайті і т. п. Також можна використовувати компоненти в шаблонах, щоб не писати код. Наприклад, на Smarty компонент виглядатиме так:

{state model=Model_News name=news limit=3}

<ul>

{list from=$news}

<p>

<b>{$newsList->name} {$newsList->date}</b><br />

{$newsList->description}<br />

< a href = "" {$ newsList- > getUrl ()} "> докладніше </а >

</p>

{/list}

* This source code was highlighted with Source Code Highlighter.

Ще один істотний плюс такої моделі - з'являється можливість автоматично кешувати результат вибірок. Будь-яка вибірка кешується, а при операціях зміни даних моделі автоматично чиститься кеш.

Надалі я не виключаю можливості збереження такого підходу, але на базі Doctrine. Але поки такої необхідності немає. Думаю, це далеко не останній варіант абстракції.

logo