คอนโทรลเลอร์

สร้างไฟล์คอนโทรลเลอร์ใหม่ app/controller/FooController.php

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function index(Request $request)
    {
        return response('hello index');
    }

    public function hello(Request $request)
    {
        return response('hello webman');
    }
}

เมื่อเข้าถึง http://127.0.0.1:8787/foo หน้าจะตอบกลับด้วย hello index

เมื่อเข้าถึง http://127.0.0.1:8787/foo/hello หน้าจะตอบกลับด้วย hello webman

แน่นอนว่าคุณสามารถเปลี่ยนแปลงกฎการ routing ผ่านการตั้งค่า routing ได้ โปรดอ้างอิงที่การ routing

提示
หากเกิดข้อผิดพลาด 404 ไม่สามารถเข้าถึงได้ โปรดเปิด config/app.php และตั้งค่า controller_suffix เป็น Controller จากนั้นรีสตาร์ท。

คอนโทรลเลอร์ ซัฟฟิกซ์

webman ตั้งแต่เวอร์ชัน 1.3 เป็นต้นไป รองรับการตั้งค่าซัฟฟิกซ์ของคอนโทรลเลอร์ใน config/app.php ถ้าหาก controller_suffix ใน config/app.php ตั้งค่าเป็นค่าว่าง '' คอนโทรลเลอร์จะมีรูปร่างดังต่อไปนี้

app\controller\Foo.php

<?php
namespace app\controller;

use support\Request;

class Foo
{
    public function index(Request $request)
    {
        return response('hello index');
    }

    public function hello(Request $request)
    {
        return response('hello webman');
    }
}

ขอแนะนำอย่างยิ่งให้ตั้งค่าซัฟฟิกซ์ของคอนโทรลเลอร์ให้เป็น Controller เพื่อหลีกเลี่ยงความขัดแย้งระหว่างชื่อคอนโทรลเลอร์และโมเดล พร้อมกับเพิ่มความปลอดภัย。

คำอธิบาย

  • เฟรมเวิร์กจะส่งวัตถุ support\Request ไปยังคอนโทรลเลอร์โดยอัตโนมัติ ซึ่งสามารถใช้เพื่อดึงข้อมูลที่ผู้ใช้ส่งมา (เช่น get post header cookie ฯลฯ) โปรดอ้างอิงที่การร้องขอ
  • คอนโทรลเลอร์สามารถคืนค่าหมายเลข สตริง หรือวัตถุ support\Response ได้ แต่ไม่สามารถคืนค่าเป็นชนิดข้อมูลอื่น ๆ ได้
  • วัตถุ support\Response สามารถสร้างได้โดยใช้ฟังก์ชันช่วยเช่น response() json() xml() jsonp() redirect() เป็นต้น

การจับคู่พารามิเตอร์ของคอนโทรลเลอร์

ตัวอย่าง

webman สนับสนุนการจับคู่พารามิเตอร์ request โดยอัตโนมัติผ่านพารามิเตอร์ของฟังก์ชันของคอนโทรลเลอร์ เช่น

<?php
namespace app\controller;
use support\Response;

class UserController
{
    public function create(string $name, int $age): Response
    {
        return json(['name' => $name, 'age' => $age]);
    }
}

คุณสามารถส่งค่าของ name และ age ผ่านวิธี GET หรือ POST หรือผ่านพารามิเตอร์ routing เช่น

Route::any('/user/{name}/{age}', [app\controller\UserController::class, 'create']);

ลำดับความสำคัญคือ พารามิเตอร์ routing > GET > พารามิเตอร์ POST

ค่าตั้งต้น

สมมุติว่าเราถึง /user/create?name=tom เราจะได้รับข้อผิดพลาดดังนี้

Missing input parameter age

สาเหตุเพราะเราไม่ได้ส่งพารามิเตอร์ age สามารถแก้ปัญหานี้ได้โดยการตั้งค่าตัวแปรพารามิเตอร์ที่มีค่าเริ่มต้น เช่น

<?php
namespace app\controller;
use support\Response;

class UserController
{
    public function create(string $name, int $age = 18): Response
    {
        return json(['name' => $name, 'age' => $age]);
    }
}

ประเภทของพารามิเตอร์

เมื่อเข้าถึง /user/create?name=tom&age=not_int เราจะได้รับข้อผิดพลาดดังนี้

提示
ที่นี่เพื่อความสะดวกในการทดสอบ เราจะป้อนพารามิเตอร์ในแถบที่อยู่ของเบราว์เซอร์โดยตรง ในการพัฒนาจริงควรส่งพารามิเตอร์ผ่านวิธี POST

Input age must be of type int, string given

เนื่องจากข้อมูลที่รับจะถูกแปลงตามประเภท หากไม่สามารถแปลงได้จะเกิด support\exception\InputTypeException ขึ้น เนื่องจากพารามิเตอร์ age ที่ส่งเข้าไม่สามารถแปลงเป็นประเภท int ได้ จึงได้รับข้อผิดพลาดดังกล่าว。

ข้อผิดพลาดที่กำหนดเอง

เราสามารถใช้การแปลหลายภาษาเพื่อตั้งค่าข้อผิดพลาด Missing input parameter age และ Input age must be of type int, string given ได้ ดูคำสั่งด้านล่าง

composer require symfony/translation
mkdir resource/translations/zh_CN/ -p
echo "<?php
return [
    'Input :parameter must be of type :exceptType, :actualType given' => '输入参数 :parameter 必须是 :exceptType 类型,传递的类型是 :actualType',
    'Missing input parameter :parameter' => '缺少输入参数 :parameter',
];" > resource/translations/zh_CN/messages.php
php start.php restart

ประเภทอื่น ๆ

พารามิเตอร์ประเภทต่าง ๆ ที่รองรับโดย webman มี int float string bool array object class instance เป็นต้น เช่น

<?php
namespace app\controller;
use support\Response;

class UserController
{
    public function create(string $name, int $age, float $balance, bool $vip, array $extension): Response
    {
        return json([
            'name' => $name,
            'age' => $age,
            'balance' => $balance,
            'vip' => $vip,
            'extension' => $extension,
        ]);
    }
}

เมื่อเข้าถึง /user/create?name=tom&age=18&balance=100.5&vip=true&extension[foo]=bar เราจะได้รับผลลัพธ์ดังนี้

{
  "name": "tom",
  "age": 18,
  "balance": 100.5,
  "vip": true,
  "extension": {
    "foo": "bar"
  }
}

อินสแตนซ์คลาส

webman รองรับการส่งผ่านอินสแตนซ์คลาสผ่านการชี้พารามิเตอร์ประเภท เช่น

app\service\Blog.php

<?php
namespace app\service;
class Blog
{
    private $title;
    private $content;
    public function __construct(string $title, string $content)
    {
        $this->title = $title;
        $this->content = $content;
    }
    public function get()
    {
        return [
            'title' => $this->title,
            'content' => $this->content,
        ];
    }
}

app\controller\BlogController.php

<?php
namespace app\controller;
use app\service\Blog;
use support\Response;

class BlogController
{
    public function create(Blog $blog): Response
    {
        return json($blog->get());
    }
}

เมื่อเข้าถึง /blog/create?blog[title]=hello&blog[content]=world เราจะได้รับผลลัพธ์ดังนี้

{
  "title": "hello",
  "content": "world"
}

อินสแตนซ์โมเดล

app\model\User.php

<?php
namespace app\model;
use support\Model;
class User extends Model
{
    protected $connection = 'mysql';
    protected $table = 'user';
    protected $primaryKey = 'id';
    public $timestamps = false;
    // ตรงนี้ต้องเพิ่มฟิลด์ที่สามารถกรอกได้เพื่อป้องกันฟิลด์ที่ไม่ปลอดภัยจากฟรอนต์เอนด์
    protected $fillable = ['name', 'age'];
}

app\controller\UserController.php

<?php
namespace app\controller;
use app\model\User;
class UserController
{
    public function create(User $user): int
    {
        $user->save();
        return $user->id;
    }
}

เมื่อเข้าถึง /user/create?user[name]=tom&user[age]=18 เราจะได้รับผลลัพธ์ที่คล้ายคลึงกันนี้

1

วงจรชีวิตของคอนโทรลเลอร์

เมื่อ controller_reuse ใน config/app.php เป็น false คอนโทรลเลอร์ที่เกี่ยวข้องจะมีการสร้างขึ้นใหม่ในแต่ละคำขอ และจะถูกทำลายเมื่อคำขอสิ้นสุดลง ซึ่งเหมือนกับกลไกการทำงานของเฟรมเวิร์กทั่วไป

เมื่อ controller_reuse ใน config/app.php เป็น true คอนโทรลเลอร์ทั้งหมดจะถูกใช้ซ้ำ ซึ่งคือตัวอย่างคอนโทรลเลอร์จะถูกสร้างขึ้นและอยู่ในหน่วยความจำ คำขอทั้งหมดจะใช้ซ้ำอินสแตนซ์นี้

注意
เมื่อเปิดใช้งานการใช้ซ้ำคอนโทรลเลอร์ คำขอไม่ควรเปลี่ยนแปลงคุณสมบัติใด ๆ ของคอนโทรลเลอร์ เนื่องจากการเปลี่ยนแปลงเหล่านี้จะส่งผลกระทบต่อคำขอถัดไป เช่น

<?php
namespace app\controller;

use support\Request;

class FooController
{
    protected $model;

    public function update(Request $request, $id)
    {
        $model = $this->getModel($id);
        $model->update();
        return response('ok');
    }

    public function delete(Request $request, $id)
    {
        $model = $this->getModel($id);
        $model->delete();
        return response('ok');
    }

    protected function getModel($id)
    {
        // วิธีนี้จะเก็บ model ไว้หลังจากคำขอครั้งแรก update?id=1
        // หากคำขอ delete?id=2 จะลบข้อมูลของ 1
        if (!$this->model) {
            $this->model = Model::find($id);
        }
        return $this->model;
    }
}

提示
การคืนค่าข้อมูลในคอนโทรลเลอร์ __construct() จะไม่มีผลใด ๆ เช่น

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function __construct()
    {
        // การคืนค่าข้อมูลในฟังก์ชันสร้างไม่มีผลใด ๆ เบราว์เซอร์จะไม่ได้รับการตอบสนองนี้
        return response('hello'); 
    }
}

ความแตกต่างระหว่างการไม่ใช้งานและการใช้งานซ้ำคอนโทรลเลอร์

ความแตกต่างมีดังนี้

ไม่ใช้งานซ้ำคอนโทรลเลอร์

แต่ละคำขอจะสร้างอินสแตนซ์คอนโทรลเลอร์ใหม่ และเมื่อคำขอสิ้นสุดก็จะปล่อยอินสแตนซ์นั้นและคืนพื้นที่หน่วยความจำ การไม่ใช้ซ้ำนั้นเหมือนกับเฟรมเวิร์กทั่วไป ซึ่งเป็นแนวทางที่สอดคล้องกับนักพัฒนาส่วนใหญ่ เนื่องจากการสร้างและทำลายคอนโทรลเลอร์ซ้ำ ๆ ดังนั้นประสิทธิภาพจะด้อยกว่าการใช้ซ้ำเล็กน้อย (การทดสอบประสิทธิภาพ helloworld มีความแตกต่างประมาณ 10% ส่วนในงานที่มีการใช้งานจริงสามารถละเลยได้)

ใช้งานซ้ำคอนโทรลเลอร์

ในกรณีของการใช้ซ้ำ กระบวนการจะสร้างคอนโทรลเลอร์เพียงครั้งเดียว คำขอจะไม่ทำลายอินสแตนซ์นี้ในครั้งที่สิ้นสุด คำขอถัดไปในกระบวนการปัจจุบันจะใช้ซ้ำอินสแตนซ์นี้ ใช้งานซ้ำคอนโทรลเลอร์มีประสิทธิภาพดีกว่า แต่ไม่สอดคล้องกับแนวทางของนักพัฒนาส่วนใหญ่

กรณีต่อไปนี้ไม่สามารถใช้ซํ้าได้

เมื่อคำขอเปลี่ยนแปลงคุณสมบัติของคอนโทรลเลอร์ จะไม่สามารถเปิดใช้งานการใช้งานซ้ำ เนื่องจากการเปลี่ยนแปลงดังกล่าวจะส่งผลกระทบต่อคำขอถัดไป

นักพัฒนาบางคนชอบทำสิ่งต่าง ๆ ในฟังก์ชันสร้าง __construct() เพื่อเริ่มต้นสำหรับแต่ละคำขอ ในกรณีนี้ไม่สามารถใช้ซ้ำคอนโทรลเลอร์ได้ เนื่องจากฟังก์ชันสร้างจะถูกเรียกเพียงครั้งเดียวในกระบวนการปัจจุบันและจะไม่ถูกเรียกสำหรับแต่ละคำขอ。