بخش فروش دیجیکالا تصمیم گرفته است که تعدادی offer استثنایی ارائه دهد. آنها میخواهند تا عید نوروز سال آینده تخفیف ۸۰٪ روی برخی از اجناس اعمال کنند! حتی ممکن است چنین offer هایی در سالهای آینده نیز ارائه شوند؛ لذا آنها نیاز به برنامهای برای محاسبهی خودکار تعداد روزهای باقیمانده تا عید نوروز دارند.
از شما میخواهیم برنامهای بنویسید که یک تاریخ شمسی از ورودی دریافت کرده و تعداد روزهای باقیمانده تا عید نوروز سال بعد، با محاسبه روز فعلی، را محاسبه کند.
نکته: فرض کنید که سال کبیسه نداریم؛ یعنی همهی سالها ۳۶۵ روزه هستند و شش ماه اول سال ۳۱ روزه، ۵ ماه بعدی، ۳۰ روزه و ماه آخر ۲۹ روزه است.
در یک خط از ورودی استاندارد (stdin)، رشتهی تاریخ (به صورت شمسی) با فرمت yyyy/mm/dd
وارد میشود.
برای دریافت ورودی، میتوانید از تابع readline
استفاده کنید:
در یک خط از خروجی استاندارد، تعداد روزهای باقیمانده تا عید نوروز سال بعد ورودی را چاپ کنید.
میلاد بهتازگی در دیجیکالا بهعنوان توسعهدهندهی junior استخدام شده است. اولین task ای که به او واگذار شده، بازنویسی بخش pagination وبسایت دیجیاستایل است. از آنجا که میلاد تجربهی انجام این کار را ندارد، از شما میخواهیم تا این بخش را برای او پیادهسازی کنید.
پروژهی اوّلیه را از اینجا دانلود کنید. ساختار پروژه بهصورت زیر است:
pagination.tpl
: این فایل شامل قالب HTML بخش pagination بوده و محتوای آن بهصورت زیر است:pagination.php
: شامل دو تابع زیر است:renderPagination
: این تابع بهترتیب یک رشته حاوی قالب HTML ، تعداد مطالب موجود در وبسایت، حداکثر تعداد مطالب در هر صفحه، شمارهی صفحهی فعلی و لینک پایهی صفحات را دریافت میکند. در نهایت، بخش pagination را بهصورت یک رشته برمیگرداند.
getPaginationButtons
: این تابع بهترتیب تعداد مطالب موجود در وبسایت، حداکثر تعداد مطالب در هر صفحه و شمارهی صفحهی فعلی را دریافت کرده و آرایهای شامل دکمهها جهت نمایش در بخش pagination را برمیگرداند. هر دکمه یک آرایهی associative است که شامل دو کلید text
و number
است. مقدار کلید text
برای دکمهی رفتن به صفحهی قبلی prev
و برای دکمهی رفتن به صفحهی بعدی next
است. همچنین، مقدار کلید text
برای دکمهی ...
همان ...
است. مقدار کلید number
بیانگر شمارهی صفحهی موجود در لینک دکمه است؛ برای مثال اگر ۴ صفحه داشته باشیم و در حال حاضر در صفحهی ۳ باشیم، مقدار کلید number
برای دکمههای prev
و next
بهترتیب برابر با 2
و 4
خواهد بود. بدیهی است که مقدار کلید number
برای سایر دکمهها (بهجز دکمهی ...
) باید برابر با مقدار کلید text
باشد.
توجه: دکمهی ...
نباید کلید number
را داشته باشد.
محتویات فایل pagination.php
بهصورت زیر است:
قوانین صفحهبندی بهشرح زیر هستند:
...
نمایش داده میشوند....
دکمهی شمارهی صفحهی بین آنها قرار میگیرد؛ برای مثال، بین دکمههای ۵ و ۷ هیچگاه دکمهی ...
نمیآید.prev
باید در صورتی نمایش داده شود که شمارهی صفحهی فعلی ۱ نباشد.next
باید در صورتی نمایش داده شود که شمارهی صفحهی فعلی برابر با تعداد صفحات نباشد.توجه: ترتیب آرایههای خروجی تابع getPaginationButtons
باید بهصورت زیر باشد:
prev
(در صورت وجود)...
نیز باشد.)next
(در صورت وجود) خروجی مورد انتظار:
خروجی مورد انتظار:
خروجی مورد انتظار:
خروجی مورد انتظار:
خروجی مورد انتظار:
index.php
: این فایل توابع موجود در فایل pagination.php
را فراخوانی کرده و از طریق آن میتوان خروجی بخش pagination را مشاهده کرد. محتوای آن بهصورت زیر است:پس از پیادهسازی تابع getPaginationButtons
، فایل pagination.php
را آپلود کنید.
اخیراً کارمندان دیجیکالا تصمیم گرفتهاند که پستهای وبلاگشان را با فرمت مارکداون بنویسند. مارکداون یک زبان نشانهگذاری برای قالببندی متن با امکان تبدیل به فرمتهای مختلف از جمله HTML است. با استفاده از مارکداون بهراحتی میتوان تیتر، متنهای bold ، italic ، نقلقول و... ایجاد کرد. از مارکداون در وبسایتهایی نظیر GitHub نیز استفاده میشود. برای کسب اطلاعات بیشتر دربارهی مارکداون به اینجا مراجعه کنید.
از شما میخواهیم کلاسی برای تبدیل مارکداون به HTML با بهرهگیری از عبارات باقاعده (Regex) پیادهسازی کنید.
پروژهی اولیه را میتوانید از اینجا دانلود کنید.
RuleInterface
🔗برای مدیریت روشهای تبدیل مارکداون به HTML ، اینترفیسی با نام RuleInterface
ایجاد کردهایم؛ زیرا ممکن است در آینده با روشی غیر از عبارات باقاعده فرایند تبدیل را انجام دهیم. این اینترفیس شامل یک متد با نام parse
است که باید رشتهای شامل محتوای مارکداون را دریافت کرده و خروجی موردنظر را برگرداند.
RegexRuleInterface
🔗این اینترفیس از اینترفیس RuleInterface
پیروی کرده و وظیفهی آن، مدیریت قواعد مختلف برای تبدیل مارکداون به HTML است. متدی با نام rule
در این اینترفیس وجود دارد که باید رشتهای شامل یک عبارت باقاعده برای تشخیص یکی از عناصر مارکداون را برگرداند.
RegexRule
🔗این کلاس، اینترفیس RegexRuleInterface
را پیادهسازی میکند. متدی انتزاعی با نام replacement
در این کلاس موجود است که باید رشتهای شامل عبارتی که قرار است جایگزین نتایج اجرای عبارت باقاعده روی محتوای مارکداون شود را برگرداند.
MarkdownParser
🔗این کلاس با استفاده از نمونههایی از کلاسهای مختلف که از کلاس RegexRule
ارثبری میکنند، محتوای مارکداون را به HTML تبدیل میکند. متدی با نام render
در این کلاس وجود دارد که یک رشتهی مارکداون دریافت کرده و خروجی HTML آن را برمیگرداند.
در حال حاضر از هفت عنصر مختلف در مارکداون استفاده میکنیم که باید قوانین استخراج و جایگزینی آنها را پیادهسازی کنید. همهی این قوانین باید تحت قالب کلاسهایی مجزا که از کلاس RegexRule
ارثبری میکنند باشند. هر کدام از این کلاسها، دو متد rule
و replacement
را خواهند داشت و هر کلاس باید در فایلی همنام با نام کلاس پیادهسازی شود.
Header
): این کلاس باید تیترهای موجود در متن را پردازش کند. تیترها در مارکداون از یک الی شش کاراکتر #
بههمراه فضای خالی در ادامهی آنها (بهصورت اختیاری) و نام تیتر تشکیل شدهاند:تیترها را توسط کلاس Header
به تگ h3
تبدیل کنید:
Bold
): این کلاس باید متنهای bold را پردازش کند. متنهای bold در مارکداون بین دو **
یا دو __
قرار میگیرند:متنهای bold را توسط کلاس Bold
به تگ b
تبدیل کنید:
Italic
): این کلاس باید متنهای italic را پردازش کند. متنهای italic در مارکداون بین دو *
یا دو _
قرار میگیرند:متنهای italic را توسط کلاس Italic
به تگ i
تبدیل کنید:
Link
): این کلاس باید لینکها را پردازش کند. لینکها در مارکداون بهصورت زیر هستند:لینکها را توسط کلاس Link
به تگ a
تبدیل کنید:
Image
): این کلاس باید تصاویر را پردازش کند. تصاویر در مارکداون بهصورت زیر هستند:تصاویر را توسط کلاس Image
به تگ img
تبدیل کنید:
Code
): این کلاس باید کدها را پردازش کند. کدها در مارکداون بین دو ` قرار میگیرند:کدها را توسط کلاس Code
به تگ code
تبدیل کنید:
HorizontalRule
): این کلاس باید خطوط افقی را پردازش کنند. خطوط افقی در مارکداون از ۳ یا تعداد بیشتری -
پشت سر هم تشکیل میشوند:خطوط افقی را توسط کلاس HorizontalRule
به تگ hr
تبدیل کنید:
نکته: لزوماً نباید همهی کلاسهای بالا را پیادهسازی کنید. به ازای هر کلاس، امتیاز آن را بهصورت جدا دریافت خواهید کرد.
پس از پیادهسازی کلاسهای بالا، فایلهای زیر را بهصورت Zip ارسال کنید:
مهدی طرفدار پروژههای خاص و سخت است. اخیراً یکی از دوستان صمیمی او، نیما، سفارش نوشتن یک سایت تبلیغاتی را به او داده است. از آنجا که مهدی نمایندگی فروش هاست و سرور ندارد، از نیما درخواست یک هاست برای میزبانی پروژه کرد. نیما هم این درخواست را با کمال میل قبول کرد و دسترسی یک هاست اشتراکی ساده با کمترین امکانات ممکن را برای مهدی فرستاد. مهدی پس از بررسیهای فراوان، متوجه شد که این هاست حتی قابلیت اتصال به MySQL را هم ندارد! لذا تصمیم گرفت که خودش اطلاعات را در قالب JSON درون فایلهای مختلف نگهداری کند و از آنها استفاده کند.
مهدی فرصت کمی برای انجام این پروژه دارد؛ بنابراین از شما میخواهیم که بخش ذخیرهسازی اطلاعات را برای مهدی بنویسید.
ساختار فایلهایی که اطلاعات در آنها ذخیره میشوند به صورت زیر است:
همهی جداول دیتابیس در یک دایرکتوری مشخص قرار میگیرند. نام هر فایل، نمایانگر نام جدول است. در مثال بالا، سه جدول با نامهای table1
، table2
و table3
وجود دارد.
هر جدول شامل خانهای به نام schema
است و مشخصات مربوط به ستونهای جدول در آن قرار دارند. در schema
هر جدول، مقدار پیشفرض ستونها و امکان null
بودن آنها تعریف میشود. مقدار پیشفرض هر ستون در خانهای به نام default
و امکان null
بودن مقدار ستون به صورت boolean
در خانهای به نام nullable
ذخیره میشود. لزوماً خانهی default
برای ستون تعریف نمیشود، امّا خانهی nullable
برای تمامی ستونها موجود است.
schema
یک جدول:🔗همچنین هر جدول خانهای به نام data
دارد که شامل آرایهای از سطرهای موجود در جدول است.
کل پروژه را در قالب کلاسی به نام JsonDB
با موارد خواستهشدهی زیر پیادهسازی کنید:
متد __construct
را به گونهای پیادهسازی کنید که مسیر اصلی ذخیرهسازی فایلهای جداول را دریافت کند. در صورتی که آدرسی به متد داده نشد، مسیر فعلی اسکریپت بهعنوان مکان ذخیرهسازی فایلهای جداول در نظر گرفته میشود.
متد insert
را به گونهای پیادهسازی کنید که نام جدول و آرایهای از ستونهای سطر موردنظر را دریافت کرده و آن را به انتهای جدول اضافه کند. در صورتی که مقداری برای ستون خاصی تعریف نشود و مقدار پیشفرضی برای آن ستون وجود نداشته باشد و امکان null
بودن ستون وجود نداشته باشد، باید یک Exception
با پیام No value provided for column column_name
(column_name
نام ستون است) throw شود. در صورتی که مقداری برای ستون خاصی تعریف نشود و مقدار پیشفرضی برای آن ستون وجود نداشته باشد و امکان null
بودن مقدار ستون وجود داشته باشد، مقدار null
به عنوان مقدار ستون ذخیره خواهد شد. در صورتی که ستونی به متد داده شود و آن ستون در schema
جدول موجود نباشد، باید یک Exception
با پیام Column column_name not found
(column_name
نام ستون موردنظر است) throw شود.
insert
:🔗select
را به گونهای پیادهسازی کنید که نام جدول و آرایهای از ستونها و مقادیر متناظرشان را دریافت کرده و سطرهایی که مقادیر ستونهایشان با مقادیر ستونهای ورودی یکسان است را در قالب آرایه برگرداند. لزوماً مقادیر همهی ستونها بهعنوان ورودی به متد داده نمیشوند. فرض بر این است که بین شرطها جهت یافتن سطرهای خروجی AND
وجود دارد. در صورتی که ستونی بهعنوان ورودی به متد داده نشود، باید همهی سطرها بهعنوان خروجی تابع return
شود. در صورتی که ستونی به متد داده شود و آن ستون در schema
جدول موجود نباشد، باید یک Exception
با پیام Column column_name not found
(column_name
نام ستون موردنظر است) throw شود.select
:🔗update
مقدار یک یا چند ستون را در سطرهایی که مشخص میکنیم تغییر میدهد. این متد شامل سه آرگومان بوده که آرگومان اول نام جدول موردنظر برای بهروزرسانی است، آرگومان دوم شامل مقادیر جدید ستونهایی است که قرار است تغییر کنند و آرگومان سوم مشخص میکند که ستونهای چه سطرهایی باید تغییر کنند؛ به طوری که هر سطری که مقادیر ستونهایش برابر با مقادیر ستونهای آرگومان سوم باشد باید بهروزرسانی شود. لزوماً مقادیر همهی ستونهای جدول در آرگومانهای دوم و سوّم موجود نیستند. اگر آرگومان سوّم به متد داده نشد، باید همهی سطرهای جدول بهروزرسانی شوند. فرض بر این است که بین شرطها جهت یافتن سطرها جهت بهروزرسانی AND
وجود دارد. در صورتی که ستونی در آرگومان دوم یا سوّم موجود باشد و آن ستون در schema
جدول موجود نباشد، باید یک Exception
با پیام Column column_name not found
(column_name
نام ستون موردنظر است) throw شود.update
:🔗delete
را به گونهای پیادهسازی کنید که نام جدول و آرایهای از ستونها و مقادیر متناظرشان را دریافت کرده و سطرهایی که مقادیر ستونهایشان با مقادیر ستونهای ورودی یکسان است را از جدول حذف کند. لزوماً مقادیر همهی ستونها بهعنوان ورودی به متد داده نمیشوند. فرض بر این است که بین شرطها جهت یافتن سطرها برای حذف AND
وجود دارد. در صورتی که ستونی بهعنوان ورودی به متد داده نشود، باید همهی سطرها از جدول حذف شوند. در صورتی که ستونی به متد داده شود و آن ستون در schema
جدول موجود نباشد، باید یک Exception
با پیام Column column_name not found
(column_name
نام ستون موردنظر است) throw شود.delete
:🔗نکته: در صورتی که جدول موردنظر در هر یک از متدهای insert
، select
، update
یا delete
یافت نشود، باید یک Exception
با پیام Table table_name not found
(table_name
نام جدول موردنظر است) throw شود.
یک فایل PHP که کلاس JsonDB
درون آن قرار دارد آپلود کنید.
مدیر کتابخانهی شهر کدنشینها دستور داده است تا از این پس مدیریت کتابهای موجود در کتابخانه توسط یک سیستم برخط صورت گیرد. قرار بود که یکی از شهروندان شهر کدنشینها این سیستم را طراحی کند، اما ظاهر این سیستم آنقدر پیچیده بهنظرشان آمد که همهی آنها در حین پیادهسازی این پروژه آن را ترک کردند! اکنون از شما میخواهیم تا بخشی از این سیستم را پیادهسازی کنید.
پروژهی اولیه را از اینجا دانلود کنید.
قرار است در این پروژه از پایگاه دادهی MySQL استفاده شود. سه جدول با مشخصات زیر از قبل طراحی شدهاند و شامل سطرهایی بهعنوان مقادیر اولیه هستند:
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 |
authors
):نام ستون | نوع | توضیح | ملاحظات |
---|---|---|---|
id |
INT(11) |
شناسهی نویسنده | UNSIGNED AUTO_INCREMENT PRIMARY KEY |
name |
VARCHAR(255) |
نام نویسنده | NOT NULL |
publishers
):نام ستون | نوع | توضیح | ملاحظات |
---|---|---|---|
id |
INT(11) |
شناسهی ناشر | UNSIGNED AUTO_INCREMENT PRIMARY KEY |
name |
VARCHAR(255) |
نام ناشر | NOT NULL |
دسترسی به پایگاه داده از طریق نمونهای از کلاس PDO
صورت میگیرد. این نمونه از طریق کلید DB
توسط کلاس Base
قابل دسترسی است:
فایل موردنیاز برای ساخت جدولها را میتوانید از اینجا دانلود کنید.
در این پروژه، همهی درخواستها به فایل 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
در پروژه تعریف شده است که با استفاده از آن کاربری را به آدرس موردنظر هدایت کرد. مثال:
Flash
🔗از این کلاس برای نمایش پیغام به کاربر پس از هدایت شدن به صفحات دیگر استفاده میشود. متدهای این کلاس را مطابق موارد زیر پیادهسازی کنید:
set($type, $message)
: پیامی با محتوای $message
از نوع $type
(که بهصورت رشته است) را در session کاربر ذخیره میکند.get()
: پیام ذخیرهشده در session کاربر را بهصورت یک آرایهی انجمنی برمیگرداند. هر پیام فقط یک بار پس از redirect شدن کاربر به سایر صفحات نمایش داده میشود. در صورتی که پیامی ذخیره نشده بود، این متد باید مقدار NULL
را برگرداند. نمونهای از خروجی این متد:سه مدل در قالب سه کلاس در دایرکتوری app/Models
موجود هستند که باید متدهای درون آنها را پیادهسازی کنید. همهی این مدلها از کلاس Model
ارثبری میکنند و میتوان فیلدهای آنها را از طریق یک آرایهی انجمنی در constructor آنها مقداردهی کرد. این مدلها و متدهای موردنیاز هر کدام بهشرح زیر هستند:
Book
:id
: شناسهی کتاب (از نوع عدد)name
: نام کتاب (از نوع رشته)author
: نویسندهی کتاب (از نوع آبجکتی از مدل Author
)publisher
: ناشر کتاب (از نوع آبجکتی از مدل Publisher
)quantity
: موجودی کتاب (از نوع عدد صحیح)all()
: همهی کتابهای موجود در جدول books
را در قالب آرایهای از آبجکتهای مدل Book
برمیگرداند.count()
: تعداد همهی کتابها (صرفنظر از موجودیشان) را برمیگرداند.find($id
: کتابی که شناسهی آن برابر با مقدار $id
است را برمیگرداند. در صورتی که چنین کتابی موجود نباشد، باید یک Exception با پیغام Book not found
پرتاب شود.save()
: تغییرات مشخصات کتاب را در جدول ذخیره میکند. تضمین میشود که شناسهی کتاب، شناسهی نویسنده و شناسهی ناشر از قبل موجود است.delete()
: کتابی که شناسهی آن با شناسهی کتاب فعلی برابر است را از جدول حذف میکند. در صورتی که چنین کتابی در جدول موجود نباشد، نباید تغییری صورت گیرد.Author
:id
: شناسهی نویسنده (از نوع عدد)name
: نام نویسنده (از نوع رشته)books_count
: تعداد کتابهای متمایز از این نویسنده (از نوع عدد صحیح)all()
: همهی نویسندگان موجود در جدول authors
که حداقل یک کتاب از آنها در لیست کتابها موجود است را در قالب آرایهای از آبجکتهای مدل Author
برمیگرداند.count()
: تعداد همهی نویسندگانی که حداقل یک کتاب از آنها در لیست کتابهای کتابخانه موجود است را برمیگرداند.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 ارسال کنید. از سایر فایلها صرفنظر خواهد شد: