لینک‌های مفید برای شرکت در مسابقه:

در زمان مسابقه می‌توانید سوال‌های خود را از قسمت "سوال بپرسید" مطرح کنید.

سری سوم راهنمایی‌ها به سؤالات اضافه شد.

مدیریت کتاب‌خانه


مدیر کتاب‌خانه‌ی شهر کدنشین‌ها دستور داده است تا از این پس مدیریت کتاب‌های موجود در کتاب‌خانه توسط یک سیستم برخط صورت گیرد. قرار بود که یکی از شهروندان شهر کدنشین‌ها این سیستم را طراحی کند، اما ظاهر این سیستم آن‌قدر پیچیده به‌نظرشان آمد که همه‌ی آن‌ها در حین پیاده‌سازی این پروژه آن را ترک کردند! اکنون از شما می‌خواهیم تا بخشی از این سیستم را پیاده‌سازی کنید.

ساختار پروژه🔗

پروژه‌ی اولیه را از این‌جا دانلود کنید.

پایگاه داده🔗

قرار است در این پروژه از پایگاه داده‌ی MySQL استفاده شود. سه جدول با مشخصات زیر از قبل طراحی شده‌اند و شامل سطرهایی به‌عنوان مقادیر اولیه هستند:

  1. جدول کتاب‌ها (books):
نام ستون نوع توضیح ملاحظات
id INT(11) شناسه‌ی کتاب UNSIGNED AUTO_INCREMENT PRIMARY KEY
name VARCHAR(255) عنوان کتاب NOT NULL
author_id INT(11) شناسه‌ی نویسنده‌ی کتاب UNSIGNED NOT NULL
publisher_id INT(11) شناسه‌ی ناشر کتاب UNSIGNED NOT NULL
quantity INT(11) موجودی کتاب UNSIGNED NOT NULL
  1. جدول نویسندگان (authors):
نام ستون نوع توضیح ملاحظات
id INT(11) شناسه‌ی نویسنده UNSIGNED AUTO_INCREMENT PRIMARY KEY
name VARCHAR(255) نام نویسنده NOT NULL
  1. جدول ناشران (publishers):
نام ستون نوع توضیح ملاحظات
id INT(11) شناسه‌ی ناشر UNSIGNED AUTO_INCREMENT PRIMARY KEY
name VARCHAR(255) نام ناشر NOT NULL

دسترسی به پایگاه داده از طریق نمونه‌ای از کلاس PDO صورت می‌گیرد. این نمونه از طریق کلید DB توسط کلاس Base قابل دسترسی است:

$db = Base::getInstance()->get('DB');
PHP

فایل موردنیاز برای ساخت جدول‌ها را می‌توانید از این‌جا دانلود کنید.

آدرس‌دهی🔗

در این پروژه، همه‌ی درخواست‌ها به فایل index.php ارسال می‌شوند و متد مناسب از یک کنترلر بر اساس URL صدا زده می‌شود. چندین route از قبل در پروژه تعریف شده‌اند که به‌شرح زیر هستند:

  • GET /: صفحه‌ی پیشخوان
  • GET /books: صفحه‌ی لیست کتاب‌ها
  • GET /books/add: فرم افزودن کتاب
  • GET /books/reserve/:id: رزرو کردن کتاب
  • GET /books/unreserve/:id: افزودن موجودی کتاب
  • GET /books/delete/:id: حذف کتاب
  • GET /authors: صفحه‌ی لیست نویسندگان
  • GET /publishers: صفحه‌ی لیست ناشران

تابعی با نام redirect در پروژه تعریف شده است که با استفاده از آن کاربری را به آدرس موردنظر هدایت کرد. مثال:

redirect('/books');
PHP

پیاده‌سازی🔗

کلاس Flash🔗

از این کلاس برای نمایش پیغام به کاربر پس از هدایت شدن به صفحات دیگر استفاده می‌شود. متدهای این کلاس را مطابق موارد زیر پیاده‌سازی کنید:

  1. set($type, $message): پیامی با محتوای $message از نوع $type (که به‌صورت رشته است) را در session کاربر ذخیره می‌کند.
  2. get(): پیام ذخیره‌شده در session کاربر را به‌صورت یک آرایه‌ی انجمنی برمی‌گرداند. هر پیام فقط یک بار پس از redirect شدن کاربر به سایر صفحات نمایش داده می‌شود. در صورتی که پیامی ذخیره نشده بود، این متد باید مقدار NULL را برگرداند. نمونه‌ای از خروجی این متد:
[
    'type' => 'success',
    'message' => 'کتاب با موفقیت افزوده شد!'
]
PHP

مدل‌ها🔗

سه مدل در قالب سه کلاس در دایرکتوری app/Models موجود هستند که باید متدهای درون آن‌ها را پیاده‌سازی کنید. همه‌ی این مدل‌ها از کلاس Model ارث‌بری می‌کنند و می‌توان فیلدهای آن‌ها را از طریق یک آرایه‌ی انجمنی در constructor آن‌ها مقداردهی کرد. این مدل‌ها و متدهای موردنیاز هر کدام به‌شرح زیر هستند:

  1. مدل Book:
    • فیلدها:
      • id: شناسه‌ی کتاب (از نوع عدد)
      • name: نام کتاب (از نوع رشته)
      • author: نویسنده‌ی کتاب (از نوع آبجکتی از مدل Author)
      • publisher: ناشر کتاب (از نوع آبجکتی از مدل Publisher)
      • quantity: موجودی کتاب (از نوع عدد صحیح)
    • متدها:
      • all(): همه‌ی کتاب‌های موجود در جدول books را در قالب آرایه‌ای از آبجکت‌های مدل Book برمی‌گرداند.
      • count(): تعداد همه‌ی کتاب‌ها (صرف‌نظر از موجودی‌شان) را برمی‌گرداند.
      • find($id: کتابی که شناسه‌ی آن برابر با مقدار $id است را برمی‌گرداند. در صورتی که چنین کتابی موجود نباشد، باید یک Exception با پیغام Book not found پرتاب شود.
      • save(): تغییرات مشخصات کتاب را در جدول ذخیره می‌کند. تضمین می‌شود که شناسه‌ی کتاب، شناسه‌ی نویسنده و شناسه‌ی ناشر از قبل موجود است.
      • delete(): کتابی که شناسه‌ی آن با شناسه‌ی کتاب فعلی برابر است را از جدول حذف می‌کند. در صورتی که چنین کتابی در جدول موجود نباشد، نباید تغییری صورت گیرد.
  2. مدل Author:
    • فیلدها:
      • id: شناسه‌ی نویسنده (از نوع عدد)
      • name: نام نویسنده (از نوع رشته)
      • books_count: تعداد کتاب‌های متمایز از این نویسنده (از نوع عدد صحیح)
    • متدها:
      • all(): همه‌ی نویسندگان موجود در جدول authors که حداقل یک کتاب از آن‌ها در لیست کتاب‌ها موجود است را در قالب آرایه‌ای از آبجکت‌های مدل Author برمی‌گرداند.
      • count(): تعداد همه‌ی نویسندگانی که حداقل یک کتاب از آن‌ها در لیست کتاب‌های کتاب‌خانه موجود است را برمی‌گرداند.
  3. مدل Publisher:
    • فیلدها:
      • id: شناسه‌ی ناشر (از نوع عدد)
      • name: نام ناشر (از نوع رشته)
      • books_count: تعداد کتاب‌های متمایز از این ناشر (از نوع عدد صحیح)
    • متدها:
      • all(): همه‌ی ناشران موجود در جدول publishers که حداقل یک کتاب از آن‌ها در لیست کتاب‌ها موجود است را در قالب آرایه‌ای از آبجکت‌های مدل Publisher برمی‌گرداند.
      • count(): تعداد همه‌ی ناشرانی که حداقل یک کتاب از آن‌ها در لیست کتاب‌های کتاب‌خانه موجود است را برمی‌گرداند.

کنترلرها🔗

کنترلرها وظیفه‌ی دریافت اطلاعات از مدل‌ها، پردازش آن‌ها و ارسال نتایج به viewها را دارند. چهار کنترلر در قالب چهار کلاس در این پروژه موجود هستند که خوشبختانه سه کنترلر از قبل به‌طور کامل پیاده‌سازی شده‌اند. متد add از کنترلر BooksController را مطابق موارد زیر پیاده‌سازی کنید:

این متد زمانی فراخوانی می‌شود که متد درخواست POST باشد. اطلاعات زیر از طریق $_POST قابل دسترسی خواهند بود:

  • name: نام کتاب
  • author: نام نویسنده‌ی کتاب
  • publisher: نام ناشر کتاب

اگر حداقل یکی از فیلدهای بالا خالی باشند، باید پیغامی از نوع danger و با محتوای همه‌ی اطلاعات باید وارد شوند. در session کاربر ذخیره شده و کاربر به آدرس /books/add هدایت شود.

در صورت مقداردهی شدن همه‌ی فیلدها، کتابی با اطلاعات ورودی در جدول books با موجودی اولیه‌ی 1 درج کنید. اگر نام نویسنده‌ی کتاب یا نام ناشر کتاب از قبل در جدول authors یا publishers موجود باشند، این مقادیر نباید مجدداً به این جداول اضافه شوند و باید از شناسه‌ی قبلی آن‌ها برای درج استفاده شود. پس از درج اطلاعات، باید پیغامی از نوع success و با محتوای کتاب با موفقیت افزوده شد! در session کاربر ذخیره شده و کاربر به آدرس /books هدایت شود.

نمایی از صفحه‌ی اصلی پروژه:

پیشخوان

نمایی از صفحه‌ی لیست کتاب‌ها:

لیست کتاب‌ها

آن‌چه باید آپلود کنید🔗

فایل‌ها و فولدرهای زیر را بدون تغییر در ساختار فولدربندی به‌صورت یک فایل Zip ارسال کنید. از سایر فایل‌ها صرف‌نظر خواهد شد:

app
│
├───Controllers
│       BooksController.php
│
├───helpers
│       Flash.php
│
└───Models
        Author.php
        Book.php
        Publisher.php
Plain text

راهنمایی ۱

برای پیاده‌سازی کلاس Flash می‌توان هر کلید دلخواهی را در $_SESSION در نظر گرفت. متد set این کلید را مقداردهی خواهد کرد و متد get پس از دریافت مقدار کلید، مقدار پیام را برابر با NULL قرار می‌دهد. البته قبل از دریافت مقدار کلید، باید با استفاده از تابع isset بررسی کرد که آیا این کلید از قبل موجود است یا خیر. کد کلاس Flash به‌صورت زیر خواهد بود:

<?php

class Flash
{
    public static function set($type, $message)
    {
        $_SESSION['flash'] = compact('type', 'message');
    }

    public static function get()
    {
        $flash = null;
        if (isset($_SESSION['flash'])) {
            $flash = $_SESSION['flash'];
            $_SESSION['flash'] = null;
        }

        return $flash;
    }
}
PHP
راهنمایی ۲

کوئری دریافت تعداد نویسندگانی که حداقل یک کتاب از آن‌ها ثبت شده به‌صورت زیر است:

SELECT COUNT(DISTINCT author_id) AS authors_count FROM books
SQL

بنابراین، کد متد count از کلاس Author به‌صورت زیر خواهد بود:

public function count()
{
    $sql = 'SELECT
            COUNT(DISTINCT author_id) AS authors_count FROM books';
    $result = Base::getInstance()->get('DB')->prepare($sql); 
    $result->execute(); 
    $count = $result->fetchColumn();

    return $count;
}
PHP

از آن‌جا که پس از فراخوانی متد save اطلاعات نویسنده و ناشر موجود در مدل نیز باید به‌روزرسانی شوند، بنابراین کد متد save در کلاس Book به‌صورت زیر خواهد بود:

public function save()
{
    $stmt = Base::getInstance()->get('DB')->prepare(
        'UPDATE books SET name = :name, author_id = :author_id,
        publisher_id = :publisher_id, quantity = :quantity WHERE id = :id'
    );
    $stmt->execute([
        ':id' => $this->id,
        ':name' => $this->name,
        ':author_id' => $this->author->id,
        ':publisher_id' => $this->publisher->id,
        ':quantity' => $this->quantity
    ]);
    $book = $this->find($this->id);
    $this->author = $book->author;
    $this->publisher = $book->publisher;
}
PHP
ارسال پاسخ برای این سؤال
در حال حاضر شما دسترسی ندارید.