فصل 9. Zend_Db

قائمة المحتويات

9.1. Zend_Db_Adapter
9.1.1. مقدمة
9.1.2. الـ Quoting للحماية من الـ SQL Injection
9.1.3. الإستعلامات المباشرة
9.1.4. الـ Transactions
9.1.5. إدخال صفوف
9.1.6. عمل Update للصفوف
9.1.7. حذف صفوف
9.1.8. جلب الصفوف
9.2. Zend_Db_Profiler
9.2.1. Introduction
9.2.2. Using the Profiler
9.2.3. Advanced Profiler Usage
9.3. Zend_Db_Select
9.3.1. Overview of the Select Object
9.3.2. Creating a Select Object
9.3.3. Building Select queries
9.3.4. Executing Select Queries
9.3.5. Other methods
9.4. Zend_Db_Table
9.4.1. Introduction to Table Class
9.4.2. Defining a Table Class
9.4.3. Creating an Instance of a Table
9.4.4. Inserting Rows to a Table
9.4.5. Updating Rows in a Table
9.4.6. Deleting Rows from a Table
9.4.7. Finding Rows by Primary Key
9.4.8. Querying for a Set of Rows
9.4.9. Querying for a Single Row
9.4.10. Retrieving Table Metadata Information
9.4.11. Caching Table Metadata
9.4.12. Customizing and Extending a Table Class
9.5. Zend_Db_Table_Row
9.5.1. Introduction
9.5.2. Fetching a Row
9.5.3. Writing rows to the database
9.5.4. Serializing and unserializing rows
9.5.5. Extending the Row class
9.6. Zend_Db_Table_Rowset
9.6.1. Introduction
9.6.2. Fetching a Rowset
9.6.3. Retrieving Rows from a Rowset
9.6.4. Retrieving a Rowset as an Array
9.6.5. Serializing and Unserializing a Rowset
9.6.6. Extending the Rowset class
9.7. Zend_Db_Table Relationships
9.7.1. Introduction
9.7.2. Defining Relationships
9.7.3. Fetching a Dependent Rowset
9.7.4. Fetching a Parent Row
9.7.5. Fetching a Rowset via a Many-to-many Relationship
9.7.6. Cascading Write Operations

9.1. Zend_Db_Adapter

9.1.1. مقدمة

Zend_Db_Adapter هو طبقة الـ abstraction لـ API قواعد البيانات المستخدم فى إطار عمل Zend , و أعتماداً على PDO يمكنك ان تستخدم Zend_Db_Adapter للأتصال و العمل مع أى من قواعد بيانات SQL المدعومة و ذلك بأستخدام نفس الـ API , و هذا يشمل كل من Microsoft SQL Server و MySQL و PostgreSQL و SQLite و أخريات.

لتقوم بإنشاء نسخة "instance" من Zend_Db_Adapter لتستخدمه مع قاعدة البيانات خاصتك, ستحتاج إلى إستدعاء ()Zend_Db::factory مع تمرير إسم الـ Adapter و مصفوفة تحتوى بيانات الأتصال, على سبيل المثال, للأتصال بقاعدة بيانات MySQL تسمى "camelot" على الـ localhost بأسم المستخدم "malory" :

<?php

require_once 'Zend/Db.php';

$params = array ('host'     => '127.0.0.1',
                 'username' => 'malory',
                 'password' => '******',
                 'dbname'   => 'camelot');

$db = Zend_Db::factory('PDO_MYSQL', $params);

?>

بنفس الطريقة تقريبا, للأتصال بقاعدة بيانات SQLite تسمى "camelot.sq3" :

<?php

require_once 'Zend/Db.php';

$params = array ('dbname' => 'camelot.sq3');

$db = Zend_Db::factory('PDO_SQLITE', $params);

?>

بنفس الطريقة تقريبا, للأتصال بقاعدة بيانات SQLite2 تسمى "camelot.sq2" : بالنسبة إلى قواعد بيانات sqlite الـ memory-based , لا تقم بتحديد dsnprefix و إستخدم أسم قاعدة البيانات ":memory:" .

<?php

require_once 'Zend/Db.php';

$params = array ('dbname' => 'camelot.sq2',
                 'dsnprefix' => 'sqlite2');

$db = Zend_Db::factory('PDO_SQLITE', $params);

?>

فى كل الحالات, ستتمكن من إستخدام نفس الـ API بدون أى تغيير للتعامل مع قواعد البيانات.

9.1.2. الـ Quoting للحماية من الـ SQL Injection

يجب عليك أن تقوم بعمل quoting "تحديد قيم/إقتباس" للبيانات التى سيتم إستخدامها فى جمل الـ SQL, و ذلك للحماية من هجمات الـ SQL injection , يوفر Zend_Db_Adapter إثنان من الـ methods (من خلال كائن الـ PDO الداخلى) لتساعدك فى عمل quoting للقيم.

اولهم هو الـ method المسمى ()quote, سيقوم بعمل quoting للقيم ذات البعد الواحد لتتمكن من إستخدامها مع الـ Adapter الخاص بقاعدة البيانات خاصتك ; إن قمت بتمرير مصفوفة , سيتم إرجاع string عبارة عن قيم المصفوفة مفصول بين كل منها بفصلة, و كل من هذه القيم قد تم عمل quoting له (هذا مفيد فى العمليات التى تتطلب قائمة من البرامترات).

<?php

// create a $db object, assuming Mysql as the adapter.

// quote a scalar
$value = $db->quote('St John"s Wort');
// $value is now '"St John\"s Wort"' (note the surrounding quotes)

// quote an array
$value = $db->quote(array('a', 'b', 'c');
// $value is now '"a", "b", "c"' (a comma-separated string)

?>

ثانى method هو ()quoteInto , انت تقوم بتمرير string أساس يحتوى على علامة إستفهام تعمل كـ placeholder , ثم تمرر قيمة احادية البعد أو مصفوفة ليتم عمل quoting لها و وضع الناتج فى string الأساس, هذه العملية مفيدة عند إنشاء إستعلامات - على الطاير - , القيم احادية البعد و المصفوفات سيتم معاملتها تماما بنفس الطريقة المتبعة فى ()quote.

<?php
	
// create a $db object, assuming Mysql as the adapter.

// quote a scalar into a WHERE clause
$where = $db->quoteInto('id = ?', 1);
// $where is now 'id = "1"' (note the surrounding quotes)

// quote an array into a WHERE clause
$where = $db->quoteInto('id IN(?)', array(1, 2, 3));
// $where is now 'id IN("1", "2", "3")' (a comma-separated string)

?>

9.1.3. الإستعلامات المباشرة

بمجرد أن تنشئ نسخة من Zend_Db_Adapter, ستتمكن من تنفيذ إستعلامات مباشرة بإستخدام SQL , سيقوم Zend_Db_Adapter بتمرير هذه الإستعلامات إلى كائن الـ PDO الموجود داخله, و الذى بدوره يقوم بتجهيز و تنفيذ هذه الأستعلامات, و بعدها يقوم بإرجاع كائن PDOStatement إليك لتتعامل مع نتائج الأستعلام (إن وجدت).

<?php
	
// create a $db object, and then query the database
// with a properly-quoted SQL statement.
$sql = $db->quoteInto(
    'SELECT * FROM example WHERE date > ?',
    '2006-01-01'
);
$result = $db->query($sql);

// use the PDOStatement $result to fetch all rows as an array
$rows = $result->fetchAll();

?>

يمكنك أن تربط كل بياناتك بالأستعلام تلقائياً , و هذا يعنى انك من الممكن أن تقوم بإنشاء اكثر من placeholder بأسماء مختلفة داخل جملة الأستعلام, و بعدها تمرر مصفوفة من البيانات التى سيتم إحلالها مكان الـ placeholders , و سيتم عمل quoting لهذه البيانات , بحيث يتوفر تأمين أكبر بالنسبة إلى هجمات الـ SQL injection .

<?php
	
// create a $db object, and then query the database.
// this time, use placeholder binding.
$result = $db->query(
    'SELECT * FROM example WHERE date > :placeholder',
    array('placeholder' => '2006-01-01')
);

// use the PDOStatement $result to fetch all rows as an array
$rows = $result->fetchAll();

?>

إختيارياً, ربما انت تريد ان تقوم بتجهيز و ربط البيانات بجملة الـ SQL يدوياً, لتتمكن من هذا, إستخدم الـ method المسمى ()prepare ليتم إرجاع نسخة مجهزة من PDOStatement و التى يمكنك أن تتعامل معها مباشرة.

<?php
	
// create a $db object, and then query the database.
// this time, prepare a PDOStatement for manual binding.
$stmt = $db->prepare('SELECT * FROM example WHERE date > :placeholder');
$stmt->bindValue('placeholder', '2006-01-01');
$stmt->execute();

// use the PDOStatement to fetch all rows as an array
$rows = $stmt->fetchAll();

?>

9.1.4. الـ Transactions

حسب الأعدادات الأساسية , يكون PDO ( و بالطبع Zend_Db_Adapter ) فى وضعية الـ "auto-commit" أى "التأكيد-التلقائى" , هذا يعنى أن كل الأستعلامات يتم تأكيدها "commited" بمجرد تنفيذها , فإن كنت تود أن تقوم بتنفيذ إستعلام داخل عملية transaction , ببساطة إستدعى الـ method المسمى ()beginTransaction , و بعدها إما تستدعى ()commit لتأكيد العملية أو إستدعى ()rollBack للإلغاء العملية, و سيعود Zend_Db_Adapter إلى وضعية الـ auto-commit إلى أن تقوم بإستدعاء ()beginTransaction مرة ثانية .

<?php
	
// create a $db object, and then start a transaction.
$db->beginTransaction();

// attempt a query.
// if it succeeds, commit the changes;
// if it fails, roll back.
try {
    $db->query(...);
    $db->commit();
} catch (Exception $e) {
    $db->rollBack();
    echo $e->getMessage();
}

?>

9.1.5. إدخال صفوف

للتسهيل, يمكنك أن تستخدم الـ method المسمى ()insert لتنشئ جملة INSERT لك و تقوم بربط البيانات التى سيتم إدخالها إليها ( البيانات التى يتم ربطها يتم عمل quoting لها تلقائياً لتحد من هجمات الـ SQL injection ).

القيمة التى سيتم ارجاعها ليست أخر ID تم إدخاله, لأن الجدول ربما لا يحتوى على عمود auto-incremented , لذلك القيمة التى سيتم إرجاعها هى عدد الصفوف التى تم التأثير عليها (غالبا 1), إن كنت تريد الـ ID الخاص بأخر صف تم إدخاله, إستدعى الـ method المسمى ()lastInsertId بعد إتمام عملية إدخال البيانات.

<?php
	
//
// INSERT INTO round_table
//     (noble_title, first_name, favorite_color)
//     VALUES ("King", "Arthur", "blue");
//

// create a $db object, and then...
// the row data to be inserted in column => value format
$row = array (
    'noble_title'    => 'King',
    'first_name'     => 'Arthur',
    'favorite_color' => 'blue',
);

// the table into which the row should be inserted
$table = 'round_table';

// insert the row and get the row ID
$rows_affected = $db->insert($table, $row);
$last_insert_id = $db->lastInsertId();

?>

9.1.6. عمل Update للصفوف

للتسهيل, يمكنك أن تستخدم الـ method المسمى ()update لتنشئ جملة UPDATE لك و تربطها بالبيانات التى سيتم عمل update لها. (البيانات التى سيتم ربطها يتم عمل quoting لها تلقائياً للمساعدة فى الحد من هجمات الـ SQL injection )

يمكنك ان توفر شرط WHERE اختيارياً لتحدد أى الصفوف سيتم عمل update لها . (لاحظ أن فقرة WHERE ليست براميتر ربط, لذلك يجب عليك أن تقوم بعمل quoting للقيم المستخدمة فيها بنفسك )

<?php
	
//
// UPDATE round_table
//     SET favorite_color = "yellow"
//     WHERE first_name = "Robin";
//

// create a $db object, and then...
// the new values to set in the update, in column => value format.
$set = array (
    'favorite_color' => 'yellow',
);

// the table to update
$table = 'round_table';

// the WHERE clause
$where = $db->quoteInto('first_name = ?', 'Robin');

// update the table and get the number of rows affected
$rows_affected = $db->update($table, $set, $where);

?>

9.1.7. حذف صفوف

للتسهيل, يمكنك أن تستخدم الـ method المسمى ()delete لتنشئ جملة DELETE لك , و يمكنك ان توفر شرط WHERE اختيارى لتحدد أى الصفوف يتم حذفها (لاحظ أن فقرة WHERE ليست براميتر ربط, لذلك يجب عليك أن تقوم بعمل quoting للقيم المستخدمة فيها بنفسك )

<?php
	
//
// DELETE FROM round_table
//     WHERE first_name = "Patsy";
//

// create a $db object, and then...
// the table to delete from
$table = 'round_table';

// the WHERE clause
$where = $db->quoteInto('first_name = ?', 'Patsy');

// update the table and get the number of rows affected
$rows_affected = $db->delete($table, $where);

?>

9.1.8. جلب الصفوف

ايضاَ يمكنك أن تنفذ استعلامات مباشرة على قاعدة البيانات بإستخدام الـ method المسمى ()query, غالباً كل ما تحتاج إلى عمله هو ان تختار الصفوف و تأتى بالنتائج, مجموعة methods الـ ()*fetch تقوم بعمل هذا من أجلك, لكل من methods الـ ()*fetch , تمرر جملة SELECT ; و إن كنت تستخدم placeholders فى الجملة , يمكنك أن تمرر مصفوفة من قيم الربط ليتم عمل quoting لها و إحلالها فى الجملة , مجموعة methods الـ ()*fetch هم :

  • ()fetchAll

  • ()fetchAssoc

  • ()fetchCol

  • ()fetchOne

  • ()fetchPairs

  • ()fetchRow

<?php
	
// create a $db object, and then...

// fetch all columns of all rows as a sequential array
$result = $db->fetchAll(
    "SELECT * FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// fetch all columns of all rows as an associative array;
// the first column is used as the array key.
$result = $db->fetchAssoc(
    "SELECT * FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// fetch the first column of all rows returned
$result = $db->fetchCol(
    "SELECT first_name FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// fetch only the first value
$result = $db->fetchOne(
    "SELECT COUNT(*) FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// fetch a series of key-value pairs; the first column is
// the array key, the second column is the array value
$result = $db->fetchPairs(
    "SELECT first_name, favorite_color FROM round_table WHERE noble_title = :title",
    array('title' => 'Sir')
);

// fetch only the first row returned
$result = $db->fetchRow(
    "SELECT * FROM round_table WHERE first_name = :name",
    array('name' => 'Lancelot')
);

?>