طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 132 · تقنيات تطوير الواجهات الخلفية
الدرس 21 · الوحدة 9: ربط الكود من جانب الخادم مع قواعد البيانات

تطبيق متكامل: إدارة المستخدمين

كل ما تعلمته في تطبيق واحد: المشروع الرسمي للمقرر. ⏱ نحو 45 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تخطط تطبيق CRUD: الصفحات والطلبات والطرق.
  • تبني وحدة بيانات تجمع استعلامات الكيان وقواعده.
  • تنفّذ القراءة والبحث والإضافة والتعديل والحذف بأمان مع PRG.
  • تستفيد من قيود القاعدة (UNIQUE) وتحوّل مخالفتها رسالة مفهومة.

١من الطلب إلى التطبيق

المشروع الرسمي لهذا المقرر في الخطة: «واجهة خلفية لإدارة بيانات مستخدمين: إضافتهم وتعديل بياناتهم وحذفهم». في هذا الدرس نبنيه كاملًا بكل ما تعلمته: الوحدات، والتحقق، والجلسات، وقاعدة البيانات الآمنة، ونمط PRG. وهذه العمليات الأربع لها اسم مشهور: CRUD.

الحرفالعمليةSQLالصفحةالطلب
CCreate إنشاءINSERTcreate.phpGET للنموذج، POST للحفظ
RRead قراءةSELECTindex.phpGET (مع ?q= للبحث)
UUpdate تعديلUPDATEedit.phpGET للنموذج، POST للحفظ
DDelete حذفDELETEdelete.phpPOST فقط

لماذا الحذف بـ POST لا برابط GET؟ لأن الروابط يتبعها أي شيء: محركات البحث، ومعاينة الروابط في تطبيقات المحادثة، وتحميل الصفحات المسبق. فرابط حذف قد يحذف بياناتك دون أن يضغطه أحد!

٢بنية التطبيق

users-app/├── db.php        ← الاتصال (الدرس 19)├── users.php     ← كل استعلامات المستخدمين وقواعدهم (وحدة البيانات)├── index.php     ← القائمة والبحث       (R)├── create.php    ← نموذج الإضافة وحفظها  (C)├── edit.php      ← نموذج التعديل وحفظه   (U) ← تحدّي الدرس└── delete.php    ← الحذف                 (D)

الصفحات لا تكتب SQL بنفسها، بل تستدعي دوال users.php. فإن انتقلنا من SQLite إلى MySQL، أو أضفنا عمودًا، نعدّل وحدة واحدة.

٣التطبيق يعمل

تتبّع السجل: نعرض القائمة، ثم نحاول إضافة مستخدم ببريد مكرر (422 مع رسالة)، ثم نضيف مستخدمًا صحيحًا (303 إلى القائمة)، ثم نبحث، ثم نحذف:

<?phprequire __DIR__ . '/users.php';$q = trim($_GET['q'] ?? '');$users = all_users($pdo, $q);$e = fn($s) => htmlspecialchars((string) $s);?><h2>المستخدمون (<?= count($users) ?>)</h2><form><input name="q" value="<?= $e($q) ?>" placeholder="بحث بالاسم أو البريد"> <button>بحث</button></form><p><a href="create.php">➕ مستخدم جديد</a></p><table border="1" cellpadding="5">  <tr><th>#</th><th>الاسم</th><th>البريد</th><th>الصلاحية</th><th></th></tr>  <?php foreach ($users as $u): ?>  <tr>    <td><?= $u['id'] ?></td><td><?= $e($u['name']) ?></td><td><?= $e($u['email']) ?></td><td><?= ROLES[$u['role']] ?></td>    <td>      <form method="post" action="delete.php" style="display:inline">        <input type="hidden" name="id" value="<?= $u['id'] ?>"><button>🗑 حذف</button>      </form>    </td>  </tr>  <?php endforeach; ?></table>

البريد المكرر رفضته قاعدة البيانات نفسها بقيد UNIQUE، فالتقطنا الاستثناء وحوّلناه رسالة مفهومة. قيود القاعدة خط دفاع أخير حتى لو نسي الكود فحصًا.

🧪 مختبر الخادمجرّب التطبيق كاملًا: ابحث، وأضف مستخدمًا، واحذف، وجرّب بريدًا مكررًا أو اسمًا قصيرًا. وافتح السجل لترى كل طلب.

٤تفاصيل تستحق الانتباه

توقّع وتحقّق

حرف U في CRUD يقابل في SQL:

Update.

لماذا يكون الحذف بطلب POST؟

محركات البحث ومعاينات الروابط.

رمز SQLSTATE لمخالفة قيد UNIQUE:

Integrity constraint violation.

['a' => 1] + ['a' => 9, 'b' => 2] تعطي:

يُضاف الناقص فقط.

الخلاصة

تحدٍّ برمجي: أكمل حرف U: صفحة التعديل

متقدم

التطبيق ينقصه التعديل. اكتب edit.php مستخدمًا دوال users.php.

المطلوب:
  • GET edit.php?id=3 يعرض <h2>تعديل: خالد العتيبي</h2> ونموذجًا معبأً ببياناته الحالية. ومستخدم غير موجود ← 404.
  • POST صحيح ← UPDATE ثم تحويل 303 إلى index.php، وتظهر القيم الجديدة في القائمة.
  • POST ببيانات خاطئة ← 422 (validate_user)، وبريد مستخدم آخر ← 422 والنص «هذا البريد مسجّل من قبل».
  • استعلام مُعدّ فقط.
👀 اعرض الاستجابة المطلوبة
✓ التحقق الآلي: يرسل المختبر هذه الطلبات إلى خادمك بالترتيب ثم يفحص الاستجابات
  1. GET /edit.php?id=3
  2. GET /edit.php?id=99
  3. POST /edit.php?id=3 (name=خالد المطيري&email=khalid.m@tvtc.sa&role=trainer&city=ينبع)
  4. GET /index.php
  5. POST /edit.php?id=3 (name=خ&email=bad&role=trainee)
  6. POST /edit.php?id=3 (name=خالد&email=noura@tvtc.sa&role=trainee)
  • الكود يعمل بلا أخطاء أو تحذيرات
  • GET ← عنوان التعديل والقيم الحالية
  • مستخدم غير موجود ← 404
  • POST صحيح ← 303
  • التحويل إلى index.php
  • القائمة تعرض البيانات الجديدة
  • بيانات خاطئة ← 422
  • بريد مكرر ← الرسالة
  • UPDATE باستعلام مُعدّ

💡 تلميح 1
ابدأ مثل create.php، لكن القيم الأولية من find_user: $in = $_POST + $user في POST.
💡 تلميح 2
لا تنسَ WHERE id = ? في UPDATE.

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

<?phprequire __DIR__ . '/users.php';$q = trim($_GET['q'] ?? '');$users = all_users($pdo, $q);$e = fn($s) => htmlspecialchars((string) $s);?><h2>المستخدمون (<?= count($users) ?>)</h2><form><input name="q" value="<?= $e($q) ?>" placeholder="بحث بالاسم أو البريد"> <button>بحث</button></form><p><a href="create.php">➕ مستخدم جديد</a></p><table border="1" cellpadding="5">  <tr><th>#</th><th>الاسم</th><th>البريد</th><th>الصلاحية</th><th></th></tr>  <?php foreach ($users as $u): ?>  <tr>    <td><?= $u['id'] ?></td><td><?= $e($u['name']) ?></td><td><?= $e($u['email']) ?></td><td><?= ROLES[$u['role']] ?></td>    <td>      <form method="post" action="delete.php" style="display:inline">        <input type="hidden" name="id" value="<?= $u['id'] ?>"><button>🗑 حذف</button>      </form>    </td>  </tr>  <?php endforeach; ?></table>
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

📝 معلم؟ أرسل ملاحظة للمؤلف عن هذا الدرس