در این سوال قرار است شما یک فایل `text` را با اندکی ایجاد تغییر به یک فایل `json` تبدیل کنید.
# توضیحات ورودی
+ هر سطر از فایل text ای که در اختیار شما قرار میگیرد شامل دو قسمت است که با کارکتر `:` از هم جدا شدهاند.
+ قسمت اول نام یک فرد(به صورت یک رشته) و قسمت دوم شامل یکی از سه کلمه "today", "tomorrow" و "yesterday" است.
+ در خط اول فایل هم یک تاریخ با فرمت`d F Y` قرار دارد که روز نوشتن این سند را مشخص میکند.
برنامهای که شما قرار است بنویسید باید فایل text داده شده را به یک فایل JSON به شکل زیر درآورد:
```
[{"user": "quera" , "time": "2005-10-03"}, {"user": "quora", "time": "2005-10-04"}, ... ]
```
که `user` در واقع همان نام فرد در فایل text و `time` تبدیل شده کلمات "today", "tomorrow" و "yesterday" به تاریخشان با فرمت `Y-m-d`هستند.
# مثال
فایل text ورودی بدین صورت است:
```
3 October 2005
quera1:today
quora2:tomorrow
quara3:yesterday
```
خروجی برنامه باید یک فایل json به صورت زیر باشد:
```
[{"user": "quera1" , "time": "2005-10-03"}, {"user": "quora2", "time": "2005-10-04"}, {"user": "quara3" , "time": "2005-10-02"} ]
```
# جزئیات
+ نام فایل text در `url` و با کلید `path` به اسکریپت شما داده می شود. یعنی باید از `$_GET['path']` استفاده کنید.
+ به عبارتی دیگر مقدار `$_GET['path']` مستقیما برای توابع کار با فایل در php قابل استفاده است.
برای مثال اگر نام فایل file.txt باشد اسکریپت شما به این صورت صدا زده می شود:
```
convert.php?path=file.txt
```
+ فایل JSON نهایی را به نام `INFO.json` ذخیره کنید.
+ نیاز به چاپ کردن چیزی ندارید. پاسخ شما همان فایل INFO.json است.
+ میتوانید فایل نمونه text را از [اینجا](http://bayanbox.ir/info/5946568611253040836/path) دریافت کنید.
+ فایل نمونه دوم را از [اینجا](http://bayanbox.ir/info/3591161407332271126/json-test1) دریافت کنید.
+ کد شما از طریق خط فرمان `commandline` اجرا نمی شود. در نتیجه شما نیازی به ارتباط با ورودی و خروجی استاندارد (`STDIN , STDOUT`) ندارید.
#### آنچه باید آپلود کنید
فایل پاسخ خود را با نام `convert.php` ذخیره کرده و به صورت فایل `zip.` آپلود کنید.
PHP - تبدیل
میخواهیم برنامهای بنویسیم تا بتوانیم با فایل نمرات دانشجویان کار کرده
و کارهایی که پیش از این توسط مسئولین آموزش به صورت دستی بر روی این فایلها
انجام میشد را خودکار کنیم. هر سطر از این فایل دارای سه بخش است که با
کاراکتر فاصله (`" "`) از هم جدا شدهاند. این سه بخش به ترتیب عبارتند از:
1. شماره دانشجویی (عدد صحیح)
2. کد درس (عدد صحیح)
3. نمره (عدد اعشاری)
یعنی هر سطر از این فایل مشخص میکند که یک دانشجو در یک درس چه نمرهای را
گرفته است.
چند نیاز اساسی در رابطه با این فایلها وجود دارد:
+ میخواهیم بتوانیم یک سطر دلخواه از این فایل را در قالب یک شئ از جنس کلاس `Grade` بخوانیم.
+ میخواهیم بتوانیم یک شئ از جنس `Grade` را به صورت یک سطر از فایل نمرات و در انتهای فایل ذخیره کنیم.
+ میخواهیم بتوانیم معدل دانشجویان در یک درس خاص را محاسبه کنیم.
+ میخواهیم بتوانیم معدل یک دانشجو را محاسبه کنیم.
# جزئیات
یک کلاس به نام `Grade` شامل سه خصوصیت با اسامی زیر بنویسید.
+ شماره دانشجویی: `student_id`
+ کد درس: `course_code`
+ نمره: `score`
کلاس شما باید دارای متد __construct باشد که این سه خصوصیت را به همین ترتیب دریافت و مقدار دهی کند.
با توجه به نیازمندیهایی که در بالا گفته شد، یک کلاس با نام `CourseUtil`
تعریف کنید که همه متدهای جدول زیر را طبق رفتار توضیح داده شده پیادهسازی کند.
| رفتار |خروجی| متد |
|:------------------:|:-------:|:-----------:|
|آدرس فایل نمرات به ورودی این متد داده میشود.|`-`| `set_file($address)`|
|یک شماره خط از فایل را در ورودی میگیرد و اطلاعات موجود در آن خط از فایل را در قالب یک شئ `Grade` برمیگرداند.|`Grade`| `load($line_number)`|
|یک شئ `Grade` در ورودی میگیرد و طبق فرمت مورد نظر، آن را در انتهای فایل اضافه میکند.|`-`|`save($grade)`|
|میانگین نمرات دانشجویان در درس با کد `course_code` را برمیگرداند. |`float`|`calc_course_average($course_code)`|
|میانگین نمرات دانشجو با شماره دانشجویی `student_id` در درسهای مختلف را برمیگرداند.|`float`|`calc_student_average($student_id)`|
|تعداد کل نمرات موجود در فایل نمرات را برمیگرداند.|`int`|`count()`|
# نکات
+ آدرس فایل با کمک متد `set_file` در اختیار کلاس قرار داده میشود. شما باید خودتان فایل را به نحوه دلخواه باز کنید. دقت کنید که فایل لزوما وجود ندارد. تنها زمانی میتوانید فرض کنید فایل وجود دارد که از شما خواسته شود یک خط از آن را بخوانید.
+ تضمین میشود در متد `load` شماره خطی که داده میشود حتما در فایل وجود دارد.
+ فرض کنید به جز برنامه شما، برنامههای دیگری نیز به فایل داده شده دسترسی دارند و ممکن است بین ۲ فراخوانی متوالی متدی مانند `load` محتویات فایل تغییر کرده باشد.
+ در فایل نمرات برای هر دانشجو در هر درس فقط یک نمره وجود دارد. بنابراین اگر برای دانشجو و درسی که نمره اش در فایل وجود دارد نمره جدیدی با متد `save` ثبت کنیم، نباید در فایل تغییری ایجاد شود.
+ در انتهای فایل `\n` وجود ندارد. شما نیز باید طوری فایل را تغییر دهید که هیچ گاه در انتهای فایل `\n` وجود نداشته باشد.
+ تضمین میشود که در هنگام محاسبه میانگینها شماره دانشجویی یا شماره درس داده شده در فایل موجود است.
+ تضمین می شود که مقدار وردی به عنوان `file_address$` مستقیما به عنوان ورودی توابع `file_get_contents` و `file_put_contents` قابل استفاده است.
در کد زیر یک فایل شامل دو سطر به عنوان ورودی داده شده است.
```php
$util = new CourseUtil();
$util->set_file($file_address);
echo $util->count();
$grade = new Grade(445612, 1234, 12);
$util->save($grade);
echo $util->count();
$util->set_file($file_address);
echo $util->count();
```
خروجی زیر مورد انتظار است:
```
2
3
3
```
#### آنچه باید آپلود کنید:
یک فایل Zip شامل یک فایل به نام `source.php` که کلاسهای `Grade` و `CourseUtil` در آن قرار دارد آپلود کنید.
منبع سؤال: مسابقات جاواکاپ
PHP - فایل نمرات
جهت ارائه ی اطلاعات شناسنامه ای یک فرد ، نیاز داریم آرایه ای به شکل زیر داشته باشیم :
```php
$person = [
'firstName' => 'Soobaasaa',
'lastName' => 'Ozaaraa',
'age' => 17,
'father' => [
'firstName' => 'Esaaro',
'lastName' => 'Ozaaraa',
'age' => 42
]
];
```
اما برای جلوگیری از نفوذ اطلاعات غلط به سیستم (مثلا کمتر بودن سن پدر از فرزند ، یا یکی نبودن نام خانوادگی پدر و فرزند) از ما خواسته شده که دو کلاس به نام های Person و Father را به شکلی طراحی کنیم که به صورت زیر قابل استفاده باشند :
```php
$father = Father::firstName('Esaaro')->lastName('Ozaaraa')->age(42);
Person::firstName("Soobaasaa")->lastName( "Ozaaraa")->age(17)
->setFather( $father )-> toArray();
```
```php
// will output:
[
'firstName' => 'Soobaasaa',
'lastName' => 'Ozaaraa',
'age' => 17,
'father' => [
'firstName' => 'Esaaro',
'lastName' => 'Ozaaraa',
'age' => 42,
],
];
```
# جزئیات
شروطی که برای مشخصات پدر و فرزند مد نظر است عبارت اند از :
+ نام و نام خانوادگی باید از جنس string و حداقل 3 و حداکثر 15 حرف باشد و شامل کاراکترهای عددی نباشد.
مثلا : 'kaakero12'قابل قبول نیست
+ سن فرزند باید از جنس int و از 1 تا 130 باشد. (مثلا عدد 0 یا 131 به عنوان مقدار ورودی متد age قابل قبول نیست.)
+ سن پدر حداقل باید 18 و حداکثر 130 سال باشد. (مثلا عدد 17 یا 131 به عنوان مقدار ورودی متد age قابل قبول نیست.)
+ مقدار ورودی به متد setFatherباید یک objectاز کلاسFather باشد.
+ سن پدر و فرزند باید حداقل 18 سال تفاوت داشته باشد.
+ دقت کنید که سن پدر و فرزند هر دو باید معین باشد( فرزندی که سن نداشته باشد نمیتواند پدر داشته باشد و بلعکس)
+ نام خانوادگی lastName پدر و فرزند باید معین و یکسان باشند.
# نکات
ویژگی های کلاس های فوق :
+ متد firstName به عنوان اولین متد به صورت static و متد toArray به عنوان آخرین متد صدا زده می شوند و ترتیب صدا زدن بقیه متد ها اهمیتی ندارد.
+ اگر مقادیر ورودی به متد ها با شرط های بالا هم خوانی نداشتند از آن ها کاملا صرف نظر می شود و نباید باعث ایجاد هر گونه ارور شوند.
+ هر دو کلاس باید متدی به نام toArray داشته باشند که با صدا زدن آن در آخر، بتوان آرایه ای شامل اطلاعات فرد را به دست آورد.
```php
$f = Father::firstName('Esaaro')->lastName()->age(22) ->toArray();
// Will output :
[ 'firstName' => 'Esaaro' , 'age' => 22, ]
```
+ صدا زدن متد ها بدون مقدار ورودی نباید تاثیری در مقدار خروجی داشته باشد یا به هر ترتیب باعث ایجاد ارور شود.
```php
->lasName() // Does not cause any php errors.
```
+ برای سادگی کار فرض کنید هیچ گاه متدها را بیش از یک بار صدا نمی زنیم
```php
->lasName('foo')->lastName('Bar') // never happens
```
***
```php
$f = Father::firstName('Esaaro')->lastName('Ozaaraa')->age(17)-> toArray();
// Will output :
[ 'firstName' => 'Esaaro', 'lastName' => 'Ozaaraa' ]
```
چون حداقل سن پدر باید 18 باشد مقدارage در خروجی مشاهده نمی شود.
***
```php
$f = Father::firstName('Esaaro')->lastName('222')->age(40)-> toArray();
// Will output :
[ 'firstName' => 'Esaaro', 'age' => 40 ],
```
چون نام خانوادگی نباید شامل عدد باشد مقدار lastName در خروجی مشاهده نمی شود.
***
```php
$fatherObj = Father::firstName('Esaaro') -> lastName('Ozaaraa') -> age(22);
Person::firstName('Soobaasaa') -> lastName('Ozaaraa') -> age(20) -> setFather( $fatherObj ) -> toArray();
// Will output :
[ 'firstName' => 'Soobaasaa' , 'lastName' => 'Ozaaraa', 'age' => 20, ]
```
در این مورد چون تفاوت سن پدر و پسر کمتر از 18 سال بوده پارامتر father در خروجی مشاهده نمی شود.
***
#### آنچه باید آپلود کنید:
یک فایل Zip شامل یک فایل به نام `solution.php` که کلاسهای `Father` و `Person` در آن قرار دارد.
یعنی هر دو کلاس داخل یک فایل تعریف شوند.
استفاده از trait ها در صورت مجاز و بلامانع است
## برای شروع کار میتوانید از لینک زیر یک فایل اولیه را دانلود کنید.
[solution.php](http://bayanbox.ir/info/576322194781329658/solution)
PHP - شناسنامهساز
با تعریف یک middle به نام minifier ترتیبی بدهید که html ارسال شده از سمت سرور برای کاربران minify شده باشد.
برای مثال بتوان از آن به شکل زیر استفاده کرد
```php
Route::middleware('minifier')->view('welcome.blade.php');
```
# نکات
شما فقط مجاز به ایجاد تغییرات در دو فایل زیرهستید و توجه داشته باشید که از تغییرات موجود در سایر فایل ها به هنگام داوری صرف نظر خواهد شد.
```
app/Http/Kernel.php
app/Http/middlewares/Minifier.php
```
از قطعه کد زیر میتوانید جهت فشرده سازی html استفاده کنید.
ورودی و خروجی این تابع از جنس string هستند.
```php
function minifyHTML($htmlString)
{
$replace = [
'<!--(.*?)-->' => '', //remove comments
"/<\?php/" => '<?php ',
"/\n([\S])/" => '$1',
"/\r/" => '', // remove carriage return
"/\n/" => '', // remove new lines
"/\t/" => '', // remove tab
"/\s+/" => ' ', // remove spaces
];
return preg_replace(array_keys($this->replace), array_values($this->replace), $htmlString);
}
```
محتوای اولیه ی فایل
`app/Http/middlewares/Minifier.php`
```php
<?php
namespace App\Http\Middleware;
use Closure;
class Minifier
{
public function handle($request, Closure $next)
{
}
}
```
#### آنچه باید برای ما بفرستید
برای حل سوال ابتدا فریم ورک لاراول را باید روی سیستم خود دانلود کنید.
در نهایت پس از اعمال تغییرات، تمامی فایل ها و فولدرهای لاراول (به جز پوشه ی vendor) را به صورت zip در آورده و آپلود کنید.
Laravel - فشردهساز HTML
همان طوری که می دانید فریم ورک لاراول برای لاگین کردن کاربر، تابع زیر را در اختیار ما قرار می دهد
```php
auth()->attempt(['email' => 'hello@gmail.com', 'password' => 123456]);
```
که تنها در صورت صحیح بودن رمز عبور ، کاربر لاگین می شود.
ما میخواهیم با تعریف یک provider جدید برای session guard و ست کردن آن در فایل config/auth.php، رفتار تابع attempt را طوری تغییر دهیم که هر پسوردی را به عنوان پسورد صحیح کاربر از ما قبول کند و یوزر لاگین شود.
با این کار برنامه نویس در مراحل کدنویسی پروژه مجبور نخواهد بود برای تست کردن پروژه اش، پسورد کاربران را به خاطر بسپارد و لاگین کردن در پنل برای او ساده تر می شود.
و در نهایت قبل از لانچ کردن پروژه از طریق فایل config/auth.phpرفتار تابع attempt را به حالت عادی باز گرداند تا با پسورد های واقعی کار کند.
# نکات
حتی الامکان از آخرین نسخه ی فریم ورک لاراول استفاده کنید.
در شروع کار جهت داشتن یک نمونه ی اولیه از UserProvider می توانید از کپی فایلی که در مسیر زیر در هسته ی لاراول وجود دارد استفاده کنید
و آن را طبق نیازتان تغییر دهید.
`/vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php`
شما مجاز به تغییر دادن و یا ایجاد هر فایل به دلخواه خودتان هستید.
#### آنچه باید آپلود کنید:
تمامی فایل ها و پوشه های فریم ورک لاراول به جز پوشه vendor را به صورت zip در آورده و آپلود کنید.
شامل پوشه های:
app, bootstrap, config, database, resources, public, routes, storage, composer.json, ...
Laravel - رمز عبور جعلی
میخواهیم یک سایت برای خودکار کردن فرایند فروش بلیتهای سینما بنویسیم.
در این سایت امکان مشاهده فیلمهای در حال اکران وجود دارد.
کاربران میتوانند عضو سایت شوند و پس از ورود به سایت
برای هر فیلم صندلی موردنظر را رزرو کند.
بخشی از این پروژه نوشته شده است. از شما میخواهیم این پروژه را تکمیل کنید.
# پروژه اولیه
پروژه اولیه را از [اینجا](http://bayanbox.ir/download/2962970233113283136/Blit-initial.zip) دانلود کنید. ساختار این پروژه به شرح زیر است:
```
cinema
├── app
│ ├── ...
│ ├── Http
│ │ └── Controllers
│ │ ├── MovieController.php
│ │ ├── StatsController.php
│ │ └── ...
│ ├── User.php
│ ├── Movie.php
│ ├── Seat.php
│ ├── Ticket.php
├── ...
├── datbase
│ ├── ...
│ ├── seeds
│ ├── migrations
│ └── ...
├── routes
│ ├── ...
│ └── web.php
...
```
# جزئیات
در این سوال لازم است علاوه بر ایجاد seed ها، تغییراتی در Controller ها و route ها ایجاد کنید.
سه مدل به شرح زیر وجود دارد:
۱. مدل `Movie` شامل فیلدهای زیر:
* `title`: نام فیلم
* `release_year`: سال میلادی انتشار فیلم
* `play_time`: زمان اکران فیلم در سالن
۲. مدل `Seat` شامل فیلد زیر:
* `number`: شماره صندلی
۳. مدل `Ticket`شامل فیلدهای زیر:
* `movie`: فیلمی که این بلیت برای آن فروخته شده است
* `user`: کاربری که این بلیت را خریده است
* `seat`: صندلی مربوط به این بلیت
* `date_bought`: تاریخی که بلیت خریده شده است
قرار است همه صندلیهای سالن و لیست فیلمها در ابتدا با استفاده از seed
به پایگاه داده اضافه شود. سپس به ازای هر بلیتی که فروخته میشود
یک شیٔ از مدل `Ticket` ساخته میشود.
مواردی که باید انجام دهید:
### ۱. نوشتن seed
از شما میخواهیم در پوشه `database/seeds` دو seed با نام کلاس
`Movies` و `Seats`
ایجاد کنید.
+ بعد از اجرای `seed` ها میخواهیم مقادیر زیر برای مدل `Movie` در دیتابیس ایجاد شده باشد:
زمان اکران را به صورت native (بدون TimeZone) تعریف کنید.
| id | نام فیلم | سال انتشار | تاریخ اکران | ساعت اکران |
|:---:|:----------:|:-------------:|:-------------:|:-------------------:|
| 1 | Children of heaven | 1997 | 2018/4/20 | 22:00 |
| 2 | About Elly | 2009 | 2018/4/20 | 20:00 |
| 3 | A separation | 2011 | 2018/4/22 | 18:00 |
| 4 | The salesman | 2016 | 2018/4/21 | 18:00 |
| 5 | The Elephant king | 2017 | 2018/4/21 | 20:00 |
+ برای `Seat` نیز میخواهیم بعد از اجرای `seed` مربوطهاش ۱۰ صندلی با آیدی ۱ تا ۱۰ و شمارهصندلی ۳۱ تا ۴۰ ایجاد شود.
توجه کنید به هنگام داوری `seed` ها با دستور
`artisan db:seed --class=CLASS_NAME`
اجرا میشوند پس حتما اسم کلاسها را مطابق اسمی که در صورت سوال گفته شده است قرار دهید.
### ۲. نمایش صندلیها
در این قسمت باید `Controller` مربوط به قسمت نمایش صندلیها را به نحوی تغییر دهید که فقط صندلیهایی که برای آن فیلم هنوز رزرو نشدهاند را نمایش دهد نه همه صندلیها را.
### ۳. رزرو صندلی
با توجه به توضیحات زیر، Controller ها را تکمیل کنید.
برای رزرو صندلی، کاربر مراحل زیر را انجام میدهد:
+ ابتدا از آدرس `/movies` بازدید میکند که لیست فیلمهایی که در حال اکران هستند
را نمایش میدهد. سپس روی فیلم مورد نظر خود کلیک کرده و صفحهی بعدی صندلیهای رزرو
نشده برای آن فیلم را نمایش میدهد. تا این مرحله کاربر نیازی به login بودن ندارد.
+ وقتی کاربر روی یکی از صندلیها کلیک کرد:
+ اگر کاربر login است، صندلی برای کاربر
رزرو شده و دوباره به صفحهی صندلیهای همان فیلم *redirect* میشود تا
بتواند صندلیهای دیگری را نیز رزرو کند.
+ اگر کاربر login نیست،
به صفحهی *login* هدایت میشود و پس از وارد شدن به سایت،
بلافاصله به صفحهی قبلی (صفحه لیست صندلیها) *redirect* میشود،
و صندلی رزرو میشود.
+ در صفحهی *login* اگر کاربر روی لینک *register* کلیک کرد و در سایت
عضو شد، باید بلافاصله پس از عضویت به طور خودکار در سایت login شود
و به صفحه لیست فیلمها *redirect* شود.
### ۴. گزارش گیری سایت
در این قسمت شما باید view مربوط به آدرس `stats` را به نحوی کامل کنید
که در پاسخ برای همه صندلیهای که حداقل
برای یک فیلم رزرو شدهاند (به ترتیب `id` صندلی)،
یک خروجی JSON به شکل زیر بازگردد:
```json
[{"seat__number": 31, "total": 3}, {"seat__number": 32, "total": 1}, ... ]
```
+ مقدار *total*، تعداد رزروهای صندلی مشخص شده است.
+ این *view* تنها باید برای افرادی که لاگین کردهاند فعال باشد و برای سایر افراد
خطای ۴۰۳ (Forbidden) برگرداند.
# نکات
+ برای حل سوال تنها فایلهایی که باید تغییر کنند فایلهای مربوط به `Controller` ها و در صورت نیاز فایل مربوط به `route` ها هستند.
+ فایلهای مربوط به `seed` ها را با اسم گفته شده در پوشه `database/seeds` قرار دهید.
+ اگر فایل `route` را تغییر دادید، نام یا آدرس `route` های موجود در فایل را تغییر ندهید. تغییراتی که شما روی پروژه انجام میدهید نباید باعث شود کاربری اصلی پروژه مختل شود.
+ همانطور که در سوال مشخص شده است، کاربر باید امکان ورود و خروج و ثبتنام در سایت را داشته باشد. برای اینکار از سیستم `Auth` از پیش آماده شده لاراول استفاده کنید و `route` های مربوطهاش را در فایل روتها اضافه کنید.
+ در قسمتهایی از سوال که گفته شده `redirect` انجام شود، حتما عملیات را به صورت `redirect` انجام دهید.
+ بدون پوشهی vendor به صورت پس از اعمال تغییرات، کل پروژه را Zip ارسال کنید.
+ نام فایل Zip اهمیت ندارد.