چگونه در PHP 7 بدون استفاده از فریمورک به صورت مدرن کد بزنیم – بخش دوم

چگونه در PHP 7 بدون استفاده از فریمورک به صورت مدرن کد بزنیم – بخش دوم
آفلاین
user-avatar
عرفان حشمتی
03 دی 1399, خواندن در 3 دقیقه

پیاده سازی Blog API

در این مرحله در حال اجرای API بلاگ خود هستیم. با وجود مسیریابی مراحل بعدی آسان خواهد بود.

سه کار باید انجام دهیم:

  • GET /post: لیست کردن همه post های موجود
  • POST /post: ایجاد کردن یک post جدید
  • GET /post/{id}: نمایش و مشخص کردن post

ابتدا برای مدیریت این عملیات به مدل Posts خود نیاز داریم و سپس از روتر خود فراخوانی میکنیم.

App/Model/Posts.php را ایجاد کنید.

App/Model/Posts.php

<?php namespace App\Model;

use App\Lib\Config;

class Posts
{
    private static $DATA = [];

    public static function all()
    {
        return self::$DATA;
    }

    public static function add($post)
    {
        $post->id = count(self::$DATA) + 1;
        self::$DATA[] = $post;
        self::save();
        return $post;
    }

    public static function findById(int $id)
    {
        foreach (self::$DATA as $post) {
            if ($post->id === $id) {
                return $post;
            }
        }
        return [];
    }

    public static function load()
    {
        $DB_PATH = Config::get('DB_PATH', __DIR__ . '/../../db.json');
        self::$DATA = json_decode(file_get_contents($DB_PATH));
    }

    public static function save()
    {
        $DB_PATH = Config::get('DB_PATH', __DIR__ . '/../../db.json');
        file_put_contents($DB_PATH, json_encode(self::$DATA, JSON_PRETTY_PRINT));
    }
}

یک فایل db.json در روت پروژه ایجاد کنید و آن را جایگذاری کنید تا بتوانیم از قبل محتوایی برای تست داشته باشیم.

[
   {
     "id": 1,
     "title": "My Post 1",
     "body": "My First Content"
   }
]

Config.php را به منظور افزودن DB_PATH اصلاح کنید.

<?php
return [
 'LOG_PATH' => __DIR__ . './logs',
 'DB_PATH' => __DIR__ . '/db.json'
];

با این کار ما از قبل تنظیمات "DB" خود را داریم، اکنون باید از آن در روتر خود استفاده کنیم، بیایید index.php خود را اصلاح کنیم تا به ترتیب مسیرها و فراخوانی DB را اضافه کنیم.

<?php
require __DIR__ . '/vendor/autoload.php';

use App\Lib\App;
use App\Lib\Router;
use App\Lib\Request;
use App\Lib\Response;
use App\Controller\Home;
use App\Model\Posts;

Posts::load();

Router::get('/', function () {
    (new Home())->indexAction();
});

Router::get('/post', function (Request $req, Response $res) {
    $res->toJSON(Posts::all());
});

Router::post('/post', function (Request $req, Response $res) {
    $post = Posts::add($req->getJSON());
    $res->status(201)->toJSON($post);
});

Router::get('/post/([0-9]*)', function (Request $req, Response $res) {
    $post = Posts::findById($req->params[0]);
    if ($post) {
        $res->toJSON($post);
    } else {
        $res->status(404)->toJSON(['error' => "Not Found"]);
    }
});

App::run();

در این مرحله، ()Posts::load را برای بارگیری "DB" خود از فایل db.json اضافه کردیم و سه مسیر GET / post  برای لیست، POST / post برای ایجاد و ([0–9]*)/GET /post برای دریافت یک پست مشخص، ایجاد کردیم. می‌توانید ()Posts::load را درون متد App::run انتقال دهید تا تمیزتر شود.

بیایید آن را آزمایش کنیم. می‌توانید برای شبیه‌سازی درخواست POST از postman و curl استفاده کنید.

لیست همه پست‌های curl -X GET http://localhost:8000 باید خروجی زیر را داشته باشد:

[{"id":1,"title":"My Post 1","body":"My First Content"}]

لیست پست -X GET http://localhost:8000/post/1 curl باید خروجی زیر را تولید کند:

{"id":1,"title":"My Post 1","body":"My First Content"}

یک پست ایجاد کنید

curl -X POST \
 http://localhost:8000/post \
 -H 'Content-Type: application/json' \
 -d '{"title": "Hello World", "body": "My Content"}'

کار در این مرحله تمام شده است. سرانجام ما Blog Api خود را داریم که به خوبی کار می‌کند. اگر موفق شدید این مرحله را انجام دهید، تبریک می‌گوییم.

اضافه کردن Testing

بنابراین اجازه دهید برخی از تست‌ها را انجام دهیم. برای این مرحله، فقط Router.php خود را با موارد ساده و سبک طراحی کد بر اساس استاندارد برنامه نویسی psr-2 آزمایش می‌کنیم. اما باید وقت بگذارید تا آنچه را که می‌خواهید در برنامه خود داشته باشید تست کنید. هدف این است که فقط به شما نشان دهیم که چگونه می‌توانید این مورد را به برنامه و CI اضافه کنید.

حال باید چند پکیج را به پروژه خود اضافه کنیم.

composer require --dev squizlabs/php_codesniffer
composer require --dev peridot-php/peridot
composer require --dev peridot-php/leo
composer require --dev eloquent/phony-peridot

برای بررسی اینکه آیا سینتکس کد اشتباه است در ترمینال اجرا کنید /vendor/bin/phpcs — standard=psr2 App/.

این بخشی از اسکریپت آزمایشی ما خواهد بود، اما سعی کنید آن را اجرا کنید. در صورتی که فقط خطاهایی را مشاهده کردید، می‌توانید از /vendor/bin/phpcbf - standard = psr2 App / برای حل خودکار آن‌ها استفاده کنید.

برای تست قصد داریم از peridot استفاده کنیم، اما شما می‌توانید از هر چیزی که با آن راحت هستید استفاده کنید. علاوه بر peridot ما دو پلاگین داریم، leo عملکرد expect را فراهم می‌کند و phony-peridot عملکرد  stubsرا که برای بررسی عملکرد بسیار مفید است، هنگام فراخوانی تابع فراهم می‌کند.

Test/Router.spec.php را ایجاد کنید.

Test/Router.spec.php

<?php namespace App\Test;

use App\Lib\Router;
use function Eloquent\Phony\stub;

describe("App\\Lib\\Router", function () {
    describe("->get", function () {

        it("match regex and execute the callback", function () {
            // Mock Request
            $_SERVER['REQUEST_METHOD'] = 'GET';
            $_SERVER['REQUEST_URI'] = '/post';

            $stub = stub(function () { });
            Router::get('/post', $stub);

            $stub->called();
        });


        it("shouldn't execute the callback if not GET request method", function () {
            // Mock Request
            $_SERVER['REQUEST_METHOD'] = 'POST';
            $_SERVER['REQUEST_URI'] = '/post';

            $stub = stub(function () { });
            Router::get('/post', $stub);

            expect($stub->checkCalled())->to->be->null();
        });

        it("match regex and get params", function () {
            // Mock Request
            $_SERVER['REQUEST_METHOD'] = 'GET';
            $_SERVER['REQUEST_URI'] = '/post/12';

            $stub = stub(function ($req) { });
            Router::get('/post/([0-9]*)', $stub);

            $stub->called();
            $req = $stub->firstCall()->argument();
            expect($req->params[0])->to->be->equal("12");
        });
    });

    describe("->post", function () {

        it("match regex and execute the callback", function () {
            // Mock Request
            $_SERVER['REQUEST_METHOD'] = 'POST';
            $_SERVER['REQUEST_URI'] = '/post';

            $stub = stub(function () { });
            Router::post('/post', $stub);

            $stub->called();
        });

        it("shouldn't execute the callback if not POST request method", function () {
            // Mock Request
            $_SERVER['REQUEST_METHOD'] = 'GET';
            $_SERVER['REQUEST_URI'] = '/post';

            $stub = stub(function () { });
            Router::post('/post', $stub);

            expect($stub->checkCalled())->to->be->null();
        });
    });
});

composer.json را اصلاح کرده و این بخش زیر را اضافه کنید:

"scripts": {
   "test": [
     "./vendor/bin/phpcs --standard=psr2 App/",
     "./vendor/bin/peridot Test/"
   ]
}

اکنون برای اجرای تست می‌توانید /vendor/bin/peridot Test/. را تایپ کنید یا composer run-script test یا حتی عبارت کوتاه‌تر composer test. همه اینها یک کار را انجام می‌دهند. اگر همه چیز درست پیش برود باید این را ببینید:

جمع بندی

این یک پروژه بسیار ساده بود و بسیاری از موارد برای کوتاه کردن مقاله ممکن بود کنار گذاشته شوند. اما شما می‌توانید از آنچه که گفته شد به عنوان پایه واساس کار استفاده کنید و با افزودن router بهتر، ORM، موتور قالب و ... آن را گسترش دهید.

منبع

چه امتیازی به این مقاله می دید؟
خیلی بد
بد
متوسط
خوب
عالی

دیدگاه‌ها و پرسش‌ها

برای ارسال دیدگاه لازم است، ابتدا وارد سایت شوید.

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

آفلاین
user-avatar
عرفان حشمتی @heshmati74
مهندس معماری سیستم های کامپیوتری، طراح و توسعه دهنده وب سایت
دنبال کردن

گفتگو‌ برنامه نویسان

بخشی برای حل مشکلات برنامه‌نویسی و مباحث پیرامون آن وارد شو