Doctrine DBAL PHP: دليل شامل مع أمثلة عملية
1. ما هو Doctrine DBAL ولماذا تحتاجه
Doctrine DBAL (Database Abstraction Layer) هي مكتبة PHP قوية توفر واجهة موحدة للتعامل مع أنظمة قواعد البيانات العلائقية المختلفة. وهي جزء من نظام Doctrine البيئي، ولكن يمكن استخدامها كمكون مستقل. المهمة الأساسية لـ DBAL هي تجريد المطور من تفاصيل نظام إدارة قواعد البيانات المحدد (MySQL, PostgreSQL, SQLite, Oracle, SQL Server وغيرها)، مما يسمح بكتابة كود قابل للنقل بين هذه الأنظمة.
لماذا تحتاج إلى Doctrine DBAL؟ أولاً، تُبسّط بشكل كبير العمليات النمطية: الاتصال بقاعدة البيانات، تنفيذ الاستعلامات، التعامل مع المعاملات (Transactions). ثانياً، توفر الأمان من خلال الاستعلامات المُعدة مسبقاً (prepared statements) والتعليق التلقائي للمعاملات، مما يحمي من هجمات SQL Injection. ثالثاً، توفر DBAL أداة بناء استعلامات (Query Builder) سهلة الاستخدام لإنشاء استعلامات معقدة دون الحاجة لكتابة SQL خام. على عكس ORM (Object-Relational Mapper) الكامل، لا تتطلب DBAL تعيين الكائنات والكيانات، مما يجعلها الخيار الأمثل للمشاريع التي تحتاج تحكماً مباشراً في SQL مع مزايا إضافية.
المكتبة مدعومة بنشاط، ولها وثائق ممتازة، وتستخدم على نطاق واسع في التطوير الصناعي. وهي أساس Doctrine ORM والعديد من أطر عمل PHP الشهيرة (Symfony, Laravel - من خلال عمليات الدمج).
2. التثبيت
يتم تثبيت Doctrine DBAL عبر Composer - مدير الحزم القياسي لـ PHP. قم بتنفيذ الأمر التالي في terminal داخل مجلد مشروعك:
composer require doctrine/dbal
بعد التثبيت، سيظهر مجلد vendor/ وملف composer.json مع إضافة التبعية. للعمل مع نظام إدارة قواعد بيانات محدد، قد تحتاج إلى تثبيت مشغل PDO المناسب (مثل ext-pdo_mysql لـ MySQL).
3. بداية سريعة - مثال عملي بسيط
أنشئ ملفاً باسم test.php وقم بتضمين أداة التحميل التلقائي لـ Composer. مثال على الاتصال بـ SQLite (قاعدة بيانات مدمجة، لا تتطلب تثبيت خادم):
<?php
require_once 'vendor/autoload.php';
use Doctrine\DBAL\DriverManager;
// معاملات الاتصال
$connectionParams = [
'dbname' => 'test.db',
'driver' => 'pdo_sqlite',
];
// إنشاء الاتصال
$conn = DriverManager::getConnection($connectionParams);
// إنشاء جدول
$conn->executeStatement('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, email TEXT)');
// إدراج بيانات
$conn->insert('users', ['name' => 'John Doe', 'email' => 'john@example.com']);
// استعلام وجلب البيانات
$users = $conn->fetchAllAssociative('SELECT * FROM users');
print_r($users);
يقوم هذا الكود بإنشاء قاعدة بيانات SQLite، وجدول users، وإدراج سجل واحد، ثم عرض جميع الصفوف.
4. أهم الدوال / الوظائف / الكلاسات
4.1. DriverManager::getConnection()
التوقيع: public static function getConnection(array $params, ?Configuration $config = null, ?EventManager $eventManager = null): Connection
الوظيفة: تنشئ وتعيد كائن الاتصال بقاعدة البيانات بناءً على المعاملات المُرسلة. هذه هي نقطة الدخول إلى DBAL.
$connectionParams = [
'dbname' => 'mydb',
'user' => 'root',
'password' => 'secret',
'host' => 'localhost',
'driver' => 'pdo_mysql',
];
$conn = DriverManager::getConnection($connectionParams);
4.2. Connection::executeStatement()
التوقيع: public function executeStatement(string $sql, array $params = [], array $types = []): int
الوظيفة: تنفذ استعلام SQL لا يُرجع مجموعة صفوف (INSERT, UPDATE, DELETE, DDL). تُعيد عدد الصفوف المتأثرة.
$affectedRows = $conn->executeStatement('UPDATE users SET name = ? WHERE id = ?', ['Jane Doe', 1]);
echo "تم تحديث $affectedRows صف(وف)";
4.3. Connection::fetchAllAssociative()
التوقيع: public function fetchAllAssociative(string $sql, array $params = [], array $types = []): array
الوظيفة: تنفذ استعلام SELECT وتُعيد جميع الصفوف كمصفوفة ترابطية (associative array).
$users = $conn->fetchAllAssociative('SELECT * FROM users WHERE active = ?', [1]);
foreach ($users as $user) {
echo $user['name'] . ' - ' . $user['email'] . '
';
}
4.4. Connection::fetchOne()
التوقيع: public function fetchOne(string $sql, array $params = [], array $types = []): mixed
الوظيفة: تنفذ استعلام وتُعيد قيمة العمود الأول من الصف الأول فقط. مثالية لاستعلامات التجميع (aggregate queries).
$count = $conn->fetchOne('SELECT COUNT(*) FROM users');
echo "عدد المستخدمين: $count";
4.5. Connection::insert()
التوقيع: public function insert(string $table, array $data): int
الوظيفة: طريقة ملائمة لإدراج صف في جدول. تأخذ اسم الجدول ومصفوفة ترابطية من البيانات (أسماء الأعمدة => القيم).
$conn->insert('users', [
'name' => 'Ahmed Ali',
'email' => 'ahmed@example.com',
'created_at' => date('Y-m-d H:i:s'),
]);
4.6. Connection::update()
التوقيع: public function update(string $table, array $data, array $criteria): int
الوظيفة: تُحدّث الصفوف المطابقة للمعايير (criteria) بالقيم الجديدة في المصفوفة $data.
$affectedRows = $conn->update('users', ['name' => 'Khaled Omar'], ['id' => 5]);
echo "تم تحديث $affectedRows مستخدم(ين)";
4.7. Connection::delete()
التوقيع: public function delete(string $table, array $criteria): int
الوظيفة: تحذف الصفوف المطابقة للمعايير من الجدول.
$deletedRows = $conn->delete('users', ['status' => 'inactive']);
echo "تم حذف $deletedRows مستخدم(ين) غير نشط(ين)";
4.8. Connection::createQueryBuilder()
التوقيع: public function createQueryBuilder(): QueryBuilder
الوظيفة: تُنشئ كائن QueryBuilder لبناء استعلامات SQL معقدة بطريقة برمجية وآمنة.
$queryBuilder = $conn->createQueryBuilder();
$queryBuilder
->select('u.id', 'u.name', 'p.title')
->from('users', 'u')
->innerJoin('u', 'posts', 'p', 'u.id = p.user_id')
->where('u.active = :active')
->setParameter('active', true)
->orderBy('u.name', 'ASC');
$results = $queryBuilder->fetchAllAssociative();
5. التعامل مع المعاملات (Transactions)
تدعم DBAL المعاملات لضمان سلامة البيانات. استخدم beginTransaction()، commit()، و rollBack():
$conn->beginTransaction();
try {
$conn->insert('accounts', ['user_id' => 1, 'balance' => 100]);
$conn->update('accounts', ['balance' => 50], ['user_id' => 2]);
$conn->commit();
echo "تمت المعاملة بنجاح";
} catch (\Exception $e) {
$conn->rollBack();
echo "فشلت المعاملة: " . $e->getMessage();
}
6. الخلاصة
Doctrine DBAL هي أداة أساسية لمطوري PHP الذين يحتاجون إلى طبقة تجريد قوية وآمنة للتعامل مع قواعد البيانات. توفر توازناً مثالياً بين التحكم الكامل في SQL والراحة التي توفرها الأدوات المساعدة. سواء كنت تعمل على مشروع صغير أو تطبيق مؤسسي كبير، فإن DBAL تمنحك المرونة والأمان والأداء الذي تحتاجه.
للاستفادة القصوى من المكتبة، يُنصح بقراءة الوثائق الرسمية واستكشاف الميزات المتقدمة مثل أنواع البيانات المخصصة، والسجلات (Logging)، والتخزين المؤقت (Caching).