تخمین زمان مطالعه


برای آشنایی بیشتر شما با نحوه‌ی کار با سیستم داوری کوئرا و قابلیت‌های آن برای اجرای سؤالات PHP می‌توانید از این ویدئو نیز کمک بگیرید. همچنین این سوال به عنوان نمونه برای شما حل می‌شود.

بر اساس آمار گزارش‌شده، میانگین سرعت مطالعه‌ی افراد در اینترنت بین ۲۰۰ تا ۲۵۰ واژه در هر دقیقه است. احتمالاً وبلاگ‌هایی را دیده‌اید که در آن‌ها زمان تقریبی مطالعه‌ی هر پست زیر عنوان آن نوشته شده است. از شما می‌خواهیم این قابلیت را پیاده‌سازی کنید.

جزئیات پروژه🔗

تابعی با نام estimateReadingTime پیاده‌سازی کنید که یک رشته از کاربر دریافت کرده و زمان مطالعه‌ی پست را برحسب دقیقه برگرداند. این تابع باید تعداد کلمات موجود در متن را تقسیم بر ۲۰۰ کرده و سقف آن را برگرداند. هم‌چنین، کاراکترهای .، ?، !، ,، ; و : باید نادیده گرفته شوند. کلمات با یک یا چند کاراکتر ' '، '\t' یا '\n' از یکدیگر جدا شده‌اند. هم‌چنین، تفاوتی برای طول کلمات قائل نمی‌شویم.

امضای تابع estimateReadingTime به‌صورت زیر خواهد بود:

function estimateReadingTime(string $text): int
{
    // TODO: Implement
}
PHP

مثال🔗

<?php

function estimateReadingTime(string $text): int
{
    // TODO: Implement
}

function randomText(int $wordsCount): string
{
    $words = [];
    for ($i = 0; $i < $wordsCount; $i++) {
        $words[] = randomWord();
    }
    $text = implode(" ", $words);

    return $text;
}

function randomWord(): string
{  
    $vowels = ["a","e","i","o","u"];  
    $consonants = [
        "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", 
        "n", "p", "r", "s", "t", "v", "w", "x", "y", "z"
    ];  
    $string = "";
    $max = intdiv(rand(4, 8), 2);
    for ($i = 1; $i <= $max; $i++) {
        $string .= $consonants[array_rand($consonants)];
        $string .= $vowels[array_rand($vowels)];
    }

    return $string;
}

echo estimateReadingTime(randomText(200)); // 1
echo "\n";
echo estimateReadingTime(randomText(201)); // 2
echo "\n";
echo estimateReadingTime(randomText(50)); // 1
echo "\n";
echo estimateReadingTime(randomText(1895)); // 10
PHP

خروجی موردانتظار:

1
2
1
10
Plain text

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

یک فایل PHP که تابع estimateReadingTime در آن پیاده‌سازی شده است آپلود کنید.

تا نوروز


بخش فروش دیجی‌کالا تصمیم گرفته است که تعدادی offer استثنایی ارائه دهد. آن‌ها می‌خواهند تا عید نوروز سال آینده تخفیف ۸۰٪ روی برخی از اجناس اعمال کنند! حتی ممکن است چنین offer هایی در سال‌های آینده نیز ارائه شوند؛ لذا آن‌ها نیاز به برنامه‌ای برای محاسبه‌ی خودکار تعداد روزهای باقی‌مانده تا عید نوروز دارند.

از شما می‌خواهیم برنامه‌ای بنویسید که یک تاریخ شمسی از ورودی دریافت کرده و تعداد روزهای باقی‌مانده تا عید نوروز سال بعد، با محاسبه روز فعلی، را محاسبه کند.

نکته: فرض کنید که سال کبیسه نداریم؛ یعنی همه‌ی سال‌ها ۳۶۵ روزه هستند و شش ماه اول سال ۳۱ روزه، ۵ ماه بعدی، ۳۰ روزه و ماه آخر ۲۹ روزه است.

ورودی🔗

در یک خط از ورودی استاندارد (stdin)، رشته‌ی تاریخ (به صورت شمسی) با فرمت yyyy/mm/dd وارد می‌شود.

برای دریافت ورودی، می‌توانید از تابع readline استفاده کنید:

$date = readline();
PHP

خروجی🔗

در یک خط از خروجی استاندارد، تعداد روزهای باقی‌مانده تا عید نوروز سال بعد ورودی را چاپ کنید.

ورودی نمونه ۱:🔗

1398/11/10
Plain text

خروجی نمونه ۱:🔗

50
Plain text

ورودی نمونه ۲:🔗

1399/05/03
Plain text

خروجی نمونه ۲:🔗

239
Plain text

ورودی نمونه ۳:🔗

1396/01/01
Plain text

خروجی نمونه ۳:🔗

365
Plain text

پسر J


مهدی طرفدار پروژه‌های خاص و سخت است. اخیراً یکی از دوستان صمیمی او، نیما، سفارش نوشتن یک سایت تبلیغاتی را به او داده است. از آن‌جا که مهدی نمایندگی فروش هاست و سرور ندارد، از نیما درخواست یک هاست برای میزبانی پروژه کرد. نیما هم این درخواست را با کمال میل قبول کرد و دسترسی یک هاست اشتراکی ساده با کم‌ترین امکانات ممکن را برای مهدی فرستاد. مهدی پس از بررسی‌های فراوان، متوجه شد که این هاست حتی قابلیت اتصال به MySQL را هم ندارد! لذا تصمیم گرفت که خودش اطلاعات را در قالب JSON درون فایل‌های مختلف نگه‌داری کند و از آن‌ها استفاده کند.

مهدی فرصت کمی برای انجام این پروژه دارد؛ بنابراین از شما می‌خواهیم که بخش ذخیره‌سازی اطلاعات را برای مهدی بنویسید.

جزئیات پروژه🔗

ساختار فایل‌هایی که اطلاعات در آن‌ها ذخیره می‌شوند به صورت زیر است:

db_files
├── table1.json
├── table2.json
└── table3.json
Plain text

همه‌ی جداول دیتابیس در یک دایرکتوری مشخص قرار می‌گیرند. نام هر فایل، نمایانگر نام جدول است. در مثال بالا، سه جدول با نام‌های table1، table2 و table3 وجود دارد.

هر جدول شامل خانه‌ای به نام schema است و مشخصات مربوط به ستون‌های جدول در آن قرار دارند. در schema هر جدول، مقدار پیش‌فرض ستون‌ها و امکان null بودن آن‌ها تعریف می‌شود. مقدار پیش‌فرض هر ستون در خانه‌ای به نام default و امکان null بودن مقدار ستون به صورت boolean در خانه‌ای به نام nullable ذخیره می‌شود. لزوماً خانه‌ی default برای ستون تعریف نمی‌شود، امّا خانه‌ی nullable برای تمامی ستون‌ها موجود است.

مثالی از schema یک جدول:🔗

{
    "first_name": {
        "nullable": false
    },
    "last_name": {
        "nullable": true
    },
    "country": {
        "nullable": true,
        "default": "Iran"
    }
}
JSON

هم‌چنین هر جدول خانه‌ای به نام data دارد که شامل آرایه‌ای از سطرهای موجود در جدول است.

مثالی از یک جدول:🔗

{
    "schema": {
        "first_name": {
            "nullable": false
        },
        "last_name": {
            "nullable": true
        },
        "country": {
            "nullable": true,
            "default": "Iran"
        }
    },
    "data": [{
        "first_name": "John",
        "last_name": "Smith",
        "country": "U.S."
    }, {
        "first_name": "Ali",
        "last_name": null,
        "country": "Iran"
    }]
}
JSON

کل پروژه را در قالب کلاسی به نام 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:🔗

$db = new JsonDB(__DIR__ . '/db');

$db->insert('users', ['first_name' => 'Ali', 'last_name' => 'AliZadeh', 'country' => 'Iran']);

$db->insert('users', ['first_name' => 'Ali', 'last_name' => 'AliZadeh']);

$db->insert('users', ['last_name' => 'AliZadeh', 'country' => 'Iran']); // Exception: No value provided for column first_name
PHP
  • متد select را به گونه‌ای پیاده‌سازی کنید که نام جدول و آرایه‌ای از ستون‌ها و مقادیر متناظرشان را دریافت کرده و سطرهایی که مقادیر ستون‌هایشان با مقادیر ستون‌های ورودی یکسان است را در قالب آرایه برگرداند. لزوماً مقادیر همه‌ی ستون‌ها به‌عنوان ورودی به متد داده نمی‌شوند. فرض بر این است که بین شرط‌ها جهت یافتن سطرهای خروجی AND وجود دارد. در صورتی که ستونی به‌عنوان ورودی به متد داده نشود، باید همه‌ی سطرها به‌عنوان خروجی تابع return شود. در صورتی که ستونی به متد داده شود و آن ستون در schema جدول موجود نباشد، باید یک Exception با پیام Column column_name not found (column_name نام ستون موردنظر است) throw شود.

مثالی از فراخوانی متد select:🔗

$db = new JsonDB(__DIR__ . '/db');

$db->select('users');
/*
[
    [
        'first_name' => 'Ali',
        'last_name' => 'AliZadeh',
        'country' => 'Iran'
    ],
    [
        'first_name' => 'John',
        'last_name' => 'Smith',
        'country' => null
    ]
]
*/

$db->select('users', ['first_name' => 'Ali']);
/*
[
    [
        'first_name' => 'Ali',
        'last_name' => 'AliZadeh',
        'country' => 'Iran'
    ]
]
*/

$db->select('users', ['first_name' => 'Ali', 'country' => null]);
/*
[]
*/

$db->insert('users', ['invalid_column' => 'Sample Value', 'country' => 'Iran']); // Exception: Column invalid_column not found
PHP
  • متد update مقدار یک یا چند ستون را در سطرهایی که مشخص می‌کنیم تغییر می‌دهد. این متد شامل سه آرگومان بوده که آرگومان اول نام جدول موردنظر برای به‌روزرسانی است، آرگومان دوم شامل مقادیر جدید ستون‌هایی است که قرار است تغییر کنند و آرگومان سوم مشخص می‌کند که ستون‌های چه سطرهایی باید تغییر کنند؛ به طوری که هر سطری که مقادیر ستون‌هایش برابر با مقادیر ستون‌های آرگومان سوم باشد باید به‌روزرسانی شود. لزوماً مقادیر همه‌ی ستون‌های جدول در آرگومان‌های دوم و سوّم موجود نیستند. اگر آرگومان سوّم به متد داده نشد، باید همه‌ی سطرهای جدول به‌روزرسانی شوند. فرض بر این است که بین شرط‌ها جهت یافتن سطرها جهت به‌روزرسانی AND وجود دارد. در صورتی که ستونی در آرگومان دوم یا سوّم موجود باشد و آن ستون در schema جدول موجود نباشد، باید یک Exception با پیام Column column_name not found (column_name نام ستون موردنظر است) throw شود.

مثالی از فراخوانی متد update:🔗

$db = new JsonDB(__DIR__ . '/db');

$db->select('users');
/*
[
    [
        'first_name' => 'Ali',
        'last_name' => 'AliZadeh',
        'country' => 'Iran'
    ],
    [
        'first_name' => 'John',
        'last_name' => 'Smith',
        'country' => null
    ]
]
*/

$db->update('users', ['first_name' => 'Mohammad'], ['first_name' => 'Ali']);

$db->select('users');
/*
[
    [
        'first_name' => 'Mohammad',
        'last_name' => 'AliZadeh',
        'country' => 'Iran'
    ],
    [
        'first_name' => 'John',
        'last_name' => 'Smith',
        'country' => null
    ]
]
*/

$db->update('users', ['first_name' => 'Mohammad']);

$db->select('users');
/*
[
    [
        'first_name' => 'Mohammad',
        'last_name' => 'AliZadeh',
        'country' => 'Iran'
    ],
    [
        'first_name' => 'Mohammad',
        'last_name' => 'Smith',
        'country' => null
    ]
]
*/

$db->update('users', ['invalid_column' => 'Test']); // Exception: Column invalid_column not found
PHP
  • متد delete را به گونه‌ای پیاده‌سازی کنید که نام جدول و آرایه‌ای از ستون‌ها و مقادیر متناظرشان را دریافت کرده و سطرهایی که مقادیر ستون‌هایشان با مقادیر ستون‌های ورودی یکسان است را از جدول حذف کند. لزوماً مقادیر همه‌ی ستون‌ها به‌عنوان ورودی به متد داده نمی‌شوند. فرض بر این است که بین شرط‌ها جهت یافتن سطرها برای حذف AND وجود دارد. در صورتی که ستونی به‌عنوان ورودی به متد داده نشود، باید همه‌ی سطرها از جدول حذف شوند. در صورتی که ستونی به متد داده شود و آن ستون در schema جدول موجود نباشد، باید یک Exception با پیام Column column_name not found (column_name نام ستون موردنظر است) throw شود.

مثالی از فراخوانی متد delete:🔗

$db = new JsonDB(__DIR__ . '/db');

$db->select('users');
/*
[
    [
        'first_name' => 'Ali',
        'last_name' => 'AliZadeh',
        'country' => 'Iran'
    ],
    [
        'first_name' => 'John',
        'last_name' => 'Smith',
        'country' => null
    ]
]
*/

$db->delete('users', ['first_name' => 'Mohammad']);

$db->select('users');
/*
[
    [
        'first_name' => 'Ali',
        'last_name' => 'AliZadeh',
        'country' => 'Iran'
    ],
    [
        'first_name' => 'John',
        'last_name' => 'Smith',
        'country' => null
    ]
]
*/

$db->delete('users', ['first_name' => 'Ali']);

$db->select('users');
/*
[
    [
        'first_name' => 'John',
        'last_name' => 'Smith',
        'country' => null
    ]
]
*/

$db->delete('users');

$db->select('users');
/*
[]
*/

$db->delete('users', ['invalid_column' => 'Test']); // Exception: Column invalid_column not found
PHP

نکته: در صورتی که جدول موردنظر در هر یک از متدهای insert، select، update یا delete یافت نشود، باید یک Exception با پیام Table table_name not found (table_name نام جدول موردنظر است) throw شود.

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

یک فایل PHP که کلاس JsonDB درون آن قرار دارد آپلود کنید.

ورود


در این سوال قصد داریم تغییر کوچکی در سیستم ورود لاراول ایجاد کنیم.

Authentication پیش‌فرض لاراول ورود را با ایمیل بررسی می‌کند، اما ما دوست داریم کاربران با نام کاربری‌ای که در هنگام ثبت‌نام وارد می‌کنند وارد سایت شوند، به همین دلیل در این امر از شما کمک می‌خواهیم.

پروژه اولیه🔗

پروژه اولیه را از اینجا دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است:

authentication_initial
├─ app
│   ├─ Console
│   │   └─ Kernel.php
│   ├─ Exceptions
│   │   └─ Handler.php
│   ├─ Http
│   │   ├─ Controllers
│   │   │   ├─ Auth
│   │   │   │   ├─ ForgotPasswordController.php
│   │   │   │   ├─ LoginController.php
│   │   │   │   ├─ RegisterController.php
│   │   │   │   ├─ ResetPasswordController.php
│   │   │   │   └─ VerificationController.php
│   │   │   ├─ Controller.php
│   │   │   └─ HomeController.php
│   │   ├─ Middleware
│   │   │   ├─ Authenticate.php
│   │   │   ├─ CheckForMaintenanceMode.php
│   │   │   ├─ EncryptCookies.php
│   │   │   ├─ RedirectIfAuthenticated.php
│   │   │   ├─ TrimStrings.php
│   │   │   ├─ TrustProxies.php
│   │   │   └─ VerifyCsrfToken.php
│   │   └─ Kernel.php
│   ├─ Providers
│   │   ├─ AppServiceProvider.php
│   │   ├─ AuthServiceProvider.php
│   │   ├─ BroadcastServiceProvider.php
│   │   ├─ EventServiceProvider.php
│   │   └─ RouteServiceProvider.php
│   └─ User.php
├─ bootstrap
│   ├─ cache
│   └─ app.php
├─ config
│   ├─ app.php
│   ├─ auth.php
│   ├─ broadcasting.php
│   ├─ cache.php
│   ├─ database.php
│   ├─ filesystems.php
│   ├─ hashing.php
│   ├─ logging.php
│   ├─ mail.php
│   ├─ queue.php
│   ├─ services.php
│   ├─ session.php
│   └─ view.php
├─ database
│   ├─ factories
│   │   └─ UserFactory.php
│   ├─ migrations
│   │   ├─ 2014_10_12_000000_create_users_table.php
│   │   └─ 2014_10_12_100000_create_password_resets_table.php
│   └─ seeds
│       └─ DatabaseSeeder.php
├─ public
│   ├─ css
│   │   └─ app.css
│   ├─ js
│   │   └─ app.js
│   ├─ svg
│   │   ├─ 403.svg
│   │   ├─ 404.svg
│   │   ├─ 500.svg
│   │   └─ 503.svg
│   ├─ .htaccess
│   ├─ favicon.ico
│   ├─ index.php
│   └─ robots.txt
├─ resources
│   ├─ js
│   │   ├─ components
│   │   │   └─ ExampleComponent.vue
│   │   ├─ app.js
│   │   └─ bootstrap.js
│   ├─ lang
│   │   └─ en
│   │       ├─ auth.php
│   │       ├─ pagination.php
│   │       ├─ passwords.php
│   │       └─ validation.php
│   ├─ sass
│   │   ├─ _variables.scss
│   │   └─ app.scss
│   └─ views
│       ├─ auth
│       │   ├─ passwords
│       │   │   ├─ email.blade.php
│       │   │   └─ reset.blade.php
│       │   ├─ login.blade.php
│       │   ├─ register.blade.php
│       │   └─ verify.blade.php
│       ├─ layouts
│       │   └─ app.blade.php
│       ├─ home.blade.php
│       └─ welcome.blade.php
├─ routes
│   ├─ api.php
│   ├─ channels.php
│   ├─ console.php
│   └─ web.php
├─ storage
│   ├─ app
│   ├─ framework
│   │   ├─ cache
│   │   ├─ sessions
│   │   ├─ testing
│   │   └─ views
│   └─ logs
├─ tests
│   ├─ CreatesApplication.php
│   └─ TestCase.php
├─ .editorconfig
├─ .env
├─ .env.example
├─ .gitattributes
├─ artisan
├─ composer.json
├─ composer.lock
├─ database.sqlite
├─ package.json
├─ phpunit.xml
├─ server.php
├─ webpack.mix.js
└─ yarn.lock
Plain text

جزئیات🔗

پروژه‌ی اولیه، پروژه‌ی لاراول خامی است که روی آن دستور php artisan make:auth اجرا شده و کمی viewهای آن تغییر کرده‌اند.

شما تنها مجاز به تغییر فایل app/Http/Controllers/Auth/LoginController.php هستید، باید کاری کنید که در کنترلر ورود به جای ایمیل از نام کاربری برای ورود استفاده شود.

نکات🔗

  • شما تنها مجاز به تغییر فایل app/Http/Controllers/Auth/LoginController.php هستید، بقیه‌ی تغییرات نادیده گرفته می‌شوند.
  • پس از اعمال تغییرات کل پروژه به غیر از پوشه‌ی vendor را Zip کرده و ارسال کنید.
  • نام فایل Zip اهمیتی ندارد.

بلاگ خیلی ساده


در این سؤال، شما باید یک بلاگ خیلی ساده را پیاده‌سازی کنید.

جزئیات🔗

پروژه‌ی اولیه را از این لینک دانلود کنید. ساختار فایل‌های این پروژه به‌صورت زیر است:

simple_blog_initial
├── app
│   ├── Console
│   │   └── Kernel.php
│   ├── Exceptions
│   │   └── Handler.php
│   ├── Http
│   │   ├── Controllers
│   │   │   ├── Controller.php
│   │   │   └── PostController.php
│   │   ├── Middleware
│   │   │   ├── Authenticate.php
│   │   │   ├── EncryptCookies.php
│   │   │   ├── PreventRequestsDuringMaintenance.php
│   │   │   ├── RedirectIfAuthenticated.php
│   │   │   ├── TrimStrings.php
│   │   │   ├── TrustHosts.php
│   │   │   ├── TrustProxies.php
│   │   │   └── VerifyCsrfToken.php
│   │   └── Kernel.php
│   ├── Models
│   │   ├── FavoritePost.php
│   │   ├── Post.php
│   │   └── User.php
│   ├── Override
│   │   ├── Connection.php
│   │   └── QueryBuilder.php
│   └── Providers
│       ├── AppServiceProvider.php
│       ├── AuthServiceProvider.php
│       ├── BroadcastServiceProvider.php
│       ├── DatabaseServiceProvider.php
│       ├── EventServiceProvider.php
│       └── RouteServiceProvider.php
├── bootstrap
│   ├── cache
│   │   ├── packages.php
│   │   └── services.php
│   └── app.php
├── config
│   ├── app.php
│   ├── auth.php
│   ├── broadcasting.php
│   ├── cache.php
│   ├── cors.php
│   ├── database.php
│   ├── filesystems.php
│   ├── hashing.php
│   ├── logging.php
│   ├── mail.php
│   ├── queue.php
│   ├── services.php
│   ├── session.php
│   └── view.php
├── database
│   ├── factories
│   │   └── UserFactory.php
│   ├── migrations
│   │   ├── 2014_10_12_000000_create_users_table.php
│   │   ├── 2014_10_12_100000_create_password_resets_table.php
│   │   ├── 2019_08_19_000000_create_failed_jobs_table.php
│   │   ├── 2020_09_27_124807_create_table_posts.php
│   │   └── 2020_09_27_133130_create_table_favorite_posts.php
│   ├── seeders
│   │   └── DatabaseSeeder.php
│   └── database.sqlite
├── public
│   ├── favicon.ico
│   ├── index.php
│   ├── robots.txt
│   └── web.config
├── resources
│   ├── css
│   │   └── app.css
│   ├── js
│   │   ├── app.js
│   │   └── bootstrap.js
│   ├── lang
│   │   └── en
│   │       ├── auth.php
│   │       ├── pagination.php
│   │       ├── passwords.php
│   │       └── validation.php
│   └── views
│       ├── posts
│       │   ├── create.blade.php
│       │   ├── edit.blade.php
│       │   ├── index.blade.php
│       │   └── show.blade.php
│       └── welcome.blade.php
├── routes
│   ├── api.php
│   ├── channels.php
│   ├── console.php
│   └── web.php
├── storage
│   ├── app
│   │   └── public
│   ├── framework
│   │   ├── cache
│   │   │   └── data
│   │   ├── sessions
│   │   ├── testing
│   │   └── views
│   └── logs
├── tests
│   ├── Feature
│   │   ├── BlogSampleTest.php
│   │   ├── BlogTest.php
│   │   └── OrderByCustomTest.php
│   ├── Unit
│   ├── CreatesApplication.php
│   └── TestCase.php
├── README.md
├── artisan
├── composer.json
├── composer.lock
├── package.json
├── phpunit.xml
├── server.php
└── webpack.mix.js
Plain text
راه‌اندازی پروژه

برای اجرای پروژه، باید php و composer را از قبل نصب کرده باشید.

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • دستور composer install را در پوشه‌ی اصلی پروژه برای نصب نیازمندی‌ها اجرا کنید.

این بلاگ شامل صفحات زیر است:

  1. صفحه‌ی نوشتن یک پست جدید (/post/create): در این صفحه با وارد کردن یک تیتر و متن محتوای یک پست، آن پست ساخته می‌شود. پس از ساخت پست، کاربر به صفحه‌ی نمایش آن پست هدایت می‌شود.
  2. صفحه‌ی ویرایش یک پست (/post/edit/{id}): در این صفحه، تیتر و محتوای فعلی پست نمایش داده می‌شود و قابل ویرایش است. پس از ویرایش، کاربر به صفحه‌ی نمایش آن پست هدایت می‌شود.
  3. صفحه‌ی نمایش یک پست (/post/show/{id}): در این صفحه، تیتر و محتوای پست نمایش داده می‌شود.
  4. صفحه لیست تمام پست‌ها (/posts): در این صفحه، تمامی پست‌ها نمایش داده می‌شوند و با کلیک بر روی تیتر هر پست، کاربر‌ وارد صفحه‌ی نمایش آن پست می‌شود.

هر پست شامل یک تیتر و یک متن محتوا است.

هر پست پس از نوشته شدن به لیست پست‌ها در صفحه لیست تمام پست‌ها اضافه می‌شود.

مدل‌ها🔗

مدل‌ها در پروژه‌ی اولیه داده شده است. هم‌چنین می‌توانید با اجرای دستور php artisan migrate مایگریشن‌ها را اجرا کنید و پایگاه داده را به‌طور کامل داشته باشید. در این پروژه از پایگاه داده‌ی SQLite استفاده شده است. در ادامه، لیست مدل‌ها و توضیحات آمده است:

  1. Post: مدل پست‌ها که دارای دو فیلد تیتر (title) و محتوا (contents) است
  2. FavoritePost: مدل پست‌های مورد علاقه که دارای یک فیلد post_id است و مشخص‌کننده‌ی پست‌های موردعلاقه است. با کلیک روی لینک «اضافه به علاقه‌مندی‌ها»، در صورتی که پست موردنظر از قبل موردعلاقه نباشد، یک ردیف به این جدول اضافه می‌شود.

شما باید PostController و viewهای مربوطه را طوری کامل کنید که عملیات ساخت، ویرایش و نمایش پست‌ها (به‌صورت تکی و در لیست) به درستی کار کند.

در صفحه‌ی نمایش یک پست و هم‌چنین صفحه نمایش لیست پست‌ها، برای هر پست دکمه‌ی «اضافه کردن به علاقه‌مندی‌ها» وجود دارد. در صفحه‌ی لیست پست‌ها، ابتدا پست‌هایی که به لیست علاقه‌مندی‌ها اضافه شده‌اند به‌ترتیب زمان اضافه شدن به علاقه‌مندی نمایش داده می‌شوند و سپس بقیه‌ی پست‌ها به‌ترتیب تاریخ ایجاد.

کنترلرها🔗

متدهای زیر را در کنترلر PostController پیاده‌سازی کنید:

  1. index(): این متد باید لیست پست‌ها را با ترتیبی که قبلاً ذکر شد با نام posts به viewposts.index ارسال کند.
  2. store(Request $request): این متد باید یک پست جدید با اطلاعات ورودی (title و contents) به پایگاه داده اضافه کرده و کاربر را به صفحه‌ی /post/show/{id} هدایت کند.
  3. edit($id): این متد باید اطلاعات پست با شناسه‌ی $id را با نام post به view posts.edit ارسال کند.
  4. update($id, Request $request): این متد باید پست با شناسه‌ی $id را با اطلاعات ورودی (title و contents) به‌روزرسانی کرده و کاربر را به صفحه‌ی /post/show/{id} هدایت کند.
  5. show($id): این متد باید اطلاعات پست با شناسه‌ی $id را با نام post به view posts.show ارسال کند.
  6. favorite($id): این متد باید پست با شناسه‌ی $id را به جدول علاقه‌مندی‌ها اضافه کرده و کاربر را به صفحه‌ی قبلی‌اش هدایت کند.

برای نمایش پست‌های اضافه شده به علاقه‌مندی‌ها، شما باید در کلاس \App\Providers\DatabaseServiceProvider یک macro جدید با نام orderByCustom به QueryBuilder اضافه کنید. این macro باید به این‌صورت کار کند:

User::orderByCustom('id', 3, 7, 2, 8)->get();
PHP

کوئری معادل فراخوانی متد بالا:

select * from "users" order by (case "id" when 3 then 0 when 7 then 1 when 2 then 2 when 8 then 3 else 4 end)
SQL

هم‌چنین اگر فقط یک آرگومان به این متد داده شود (یا آرگومان‌های دوم به بعد خالی باشند)، نباید تغییری در کوئری اعمال شود.

توجه: شما تنها مجاز به تغییر فایل‌های موجود در پوشه‌ی /app هستید.

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

پس از اعمال تغییرات، کل پروژه به غیر از پوشه‌ی vendor را Zip کرده و آپلود کنید. نام فایل Zip اهمیتی ندارد.

حالت تعمیر سفارشی


محمدرضا در شرکت عدالتخانه به‌عنوان توسعه‌دهنده‌ی بک‌اند مشغول به کار است. او اخیراً با یک چالش جدید مواجه شده است. همان‌طور که مطلع هستید، در Laravel 8 قابلیت‌های جدیدی به حالت تعمیر (maintenance mode) اضافه شده است. یکی از این قابلیت‌ها، امکان تعریف کلید secret برای حالت تعمیر است که با استفاده از آن می‌توان سایت را خارج از حالت تعمیر مشاهده کرد. این قابلیت در واقع یک کوکی با نام laravel_maintenance در مرورگر ذخیره کرده و با استفاده از آن، حالت تعمیر را برای کاربر فعلی غیرفعال می‌کند.

زمان اعتبار این کوکی ۱۲ ساعت است، اما تیم فنی شرکت عدالتخانه قصد دارد یک آرگومان به دستور down موجود در Artisan اضافه کند که در صورت مقداردهی آن، کوکی laravel_maintenance با زمان اعتبار واردشده در این آرگومان ست شود.

محمدرضا این task را برعهده گرفته، اما از پس آن برنیامده است. از شما می‌خواهیم این task را برای او انجام دهید.

جزئیات پروژه🔗

پروژه‌ی اولیه را از این لینک دانلود کنید. ساختار فایل‌های این پروژه به‌صورت زیر است:

maintenance_initial
├── app
│   ├── Console
│   │   └── Kernel.php
│   ├── Exceptions
│   │   └── Handler.php
│   ├── Http
│   │   ├── Controllers
│   │   │   └── Controller.php
│   │   ├── Middleware
│   │   │   ├── Authenticate.php
│   │   │   ├── EncryptCookies.php
│   │   │   ├── PreventRequestsDuringMaintenance.php
│   │   │   ├── RedirectIfAuthenticated.php
│   │   │   ├── TrimStrings.php
│   │   │   ├── TrustHosts.php
│   │   │   ├── TrustProxies.php
│   │   │   └── VerifyCsrfToken.php
│   │   └── Kernel.php
│   ├── Models
│   │   └── User.php
│   └── Providers
│       ├── AppServiceProvider.php
│       ├── AuthServiceProvider.php
│       ├── BroadcastServiceProvider.php
│       ├── EventServiceProvider.php
│       └── RouteServiceProvider.php
├── bootstrap
│   ├── cache
│   │   ├── packages.php
│   │   └── services.php
│   └── app.php
├── config
│   ├── app.php
│   ├── auth.php
│   ├── broadcasting.php
│   ├── cache.php
│   ├── cors.php
│   ├── database.php
│   ├── filesystems.php
│   ├── hashing.php
│   ├── logging.php
│   ├── mail.php
│   ├── queue.php
│   ├── services.php
│   ├── session.php
│   └── view.php
├── database
│   ├── factories
│   │   └── UserFactory.php
│   ├── migrations
│   │   ├── 2014_10_12_000000_create_users_table.php
│   │   ├── 2014_10_12_100000_create_password_resets_table.php
│   │   └── 2019_08_19_000000_create_failed_jobs_table.php
│   └── seeders
│       └── DatabaseSeeder.php
├── public
│   ├── favicon.ico
│   ├── index.php
│   ├── robots.txt
│   └── web.config
├── resources
│   ├── css
│   │   └── app.css
│   ├── js
│   │   ├── app.js
│   │   └── bootstrap.js
│   ├── lang
│   │   └── en
│   │       ├── auth.php
│   │       ├── pagination.php
│   │       ├── passwords.php
│   │       └── validation.php
│   └── views
│       └── welcome.blade.php
├── routes
│   ├── api.php
│   ├── channels.php
│   ├── console.php
│   └── web.php
├── storage
│   ├── app
│   │   └── public
│   ├── framework
│   │   ├── cache
│   │   │   └── data
│   │   ├── sessions
│   │   ├── testing
│   │   └── views
│   └── logs
├── tests
│   ├── Feature
│   │   └── ExampleTest.php
│   ├── Unit
│   │   └── ExampleTest.php
│   ├── CreatesApplication.php
│   └── TestCase.php
├── README.md
├── artisan
├── composer.json
├── composer.lock
├── package.json
├── phpunit.xml
├── server.php
└── webpack.mix.js
Plain text
راه‌اندازی پروژه

برای اجرای پروژه، باید php و composer را از قبل نصب کرده باشید.

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • دستور composer install را در پوشه‌ی اصلی پروژه برای نصب نیازمندی‌ها اجرا کنید.

آرگومانی با نام time و مقدار پیش‌فرض 12 به دستور down در Artisan اضافه کنید که در صورت مقداردهی شدن، زمان کوکی laravel-maintenance برابر با مقدار آرگومان time باشد. مقدار آرگومان time یک عدد صحیح بوده و بیانگر زمان کوکی laravel-maintenance برحسب ساعت است. تضمین می‌شود که عدد صفر و اعداد منفی به این آرگومان داده نمی‌شوند.

دستور down به‌صورت زیر اجرا خواهد شد:

php artisan down --secret=MvYgEH651d3X4JRcys --time=24
Plain text

در این‌صورت، کاربر با ارسال درخواست به آدرس /MvYgEH651d3X4JRcys می‌تواند سایت را به مدت ۲۴ ساعت خارج از حالت تعمیر مشاهده کند.

نکات🔗

  • برای پیاده‌سازی این قابلیت، نیازمند جست‌وجو در سورس‌کد Laravel خواهید بود.
  • شما تنها مجاز به ایجاد تغییرات در پوشه‌های app و config هستید.

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

پس از اعمال تغییرات، کل پروژه به غیر از پوشه‌ی vendor را Zip کرده و آپلود کنید. نام فایل Zip اهمیتی ندارد.