وحدة التحكم
قم بإنشاء ملف وحدة التحكم 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
.
بالطبع يمكنك تغيير قواعد التوجيه من خلال إعدادات التوجيه، راجع التوجيه.
تنبيه
إذا كنت تواجه خطأ 404، يرجى فتحconfig/app.php
، وتعيينcontroller_suffix
إلىController
، ثم أعد تشغيل التطبيق.
لاحقة وحدة التحكم
من الإصدار 1.3، يدعم Webman تعيين لاحقة وحدة التحكم في 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 ربط معلمات الطلب تلقائيًا بمعلمات وظيفة وحدة التحكم، على سبيل المثال
<?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
، أو يمكنك تمرير معلمات name
و age
من خلال معلمات التوجيه، على سبيل المثال
Route::any('/user/{name}/{age}', [app\controller\UserController::class, 'create']);
الأولوية هي معلمات التوجيه
> 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
, كائنات الفئات
، على سبيل المثال
<?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()
، ولن يظل هذا ممكنًا مع إعادة استخدام وحدة التحكم، لأن دالة الإنشاء في العملية الحالية ستدعى مرة واحدة فقط، وليس لكل طلب.