Contrôleur
Créez le fichier de contrôleur 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');
}
}
Lors de l'accès à http://127.0.0.1:8787/foo, la page renvoie hello index.
Lors de l'accès à http://127.0.0.1:8787/foo/hello, la page renvoie hello webman.
Vous pouvez modifier les règles de routage via la configuration des routes, voir Routes.
Conseil
En cas d'erreur 404, ouvrezconfig/app.php, définissezcontroller_suffixsurControlleret redémarrez.
Suffixe du contrôleur
À partir de la version 1.3, webman permet de définir un suffixe de contrôleur dans config/app.php. Si controller_suffix est défini sur une chaîne vide '', le contrôleur ressemblera à ceci :
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');
}
}
Il est fortement recommandé de définir le suffixe du contrôleur sur Controller afin d'éviter les conflits avec les noms de classes de modèles et d'améliorer la sécurité.
Explication
- Le framework transmet automatiquement l'objet
support\Requestau contrôleur, permettant d'obtenir les données d'entrée utilisateur (get, post, header, cookie, etc.), voir Requête. - Le contrôleur peut renvoyer des nombres, des chaînes ou des objets
support\Response, mais pas d'autres types de données. - Les objets
support\Responsepeuvent être créés avec les fonctions d'aideresponse(),json(),xml(),jsonp(),redirect(), etc.
Liaison des paramètres du contrôleur
Exemple
webman supporte la liaison automatique des paramètres de requête aux paramètres des méthodes du contrôleur. Par exemple :
<?php
namespace app\controller;
use support\Response;
class UserController
{
public function create(string $name, int $age): Response
{
return json(['name' => $name, 'age' => $age]);
}
}
Vous pouvez transmettre les valeurs de name et age via GET ou POST, ou via les paramètres de route. Par exemple :
Route::any('/user/{name}/{age}', [app\controller\UserController::class, 'create']);
La priorité est : paramètres de route > GET > POST.
Valeurs par défaut
Si vous accédez à /user/create?name=tom, vous obtiendrez l'erreur suivante :
Missing input parameter age
Cela vient du fait que nous n'avons pas transmis le paramètre age. Vous pouvez définir une valeur par défaut pour résoudre ce problème. Par exemple :
<?php
namespace app\controller;
use support\Response;
class UserController
{
public function create(string $name, int $age = 18): Response
{
return json(['name' => $name, 'age' => $age]);
}
}
Types de paramètres
Si vous accédez à /user/create?name=tom&age=not_int, vous obtiendrez l'erreur suivante :
Conseil
Pour faciliter les tests, nous passons les paramètres directement dans la barre d'adresse. En développement, les paramètres devraient être transmis viaPOST.
Input age must be of type int, string given
Les données reçues sont converties selon le type. En cas d'échec de conversion, une exception support\exception\InputTypeException est levée. Comme age ne peut pas être converti en int, cette erreur apparaît.
Messages d'erreur personnalisés
Vous pouvez personnaliser des messages comme Missing input parameter age et Input age must be of type int, string given via la traduction. Référez-vous aux commandes suivantes :
composer require symfony/translation
mkdir resource/translations/zh_CN/ -p
echo "<?php
return [
'Input :parameter must be of type :exceptType, :actualType given' => 'Le paramètre d\'entrée :parameter doit être de type :exceptType, le type transmis est :actualType',
'Missing input parameter :parameter' => 'Paramètre d\'entrée :parameter manquant',
];" > resource/translations/zh_CN/messages.php
php start.php restart
Autres types
webman supporte les types int, float, string, bool, array, object et les instances de classe. Par exemple :
<?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,
]);
}
}
En accédant à /user/create?name=tom&age=18&balance=100.5&vip=true&extension[foo]=bar, vous obtiendrez :
{
"name": "tom",
"age": 18,
"balance": 100.5,
"vip": true,
"extension": {
"foo": "bar"
}
}
Instance de classe
webman permet de transmettre des instances de classes via le typage des paramètres. Par exemple :
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());
}
}
En accédant à /blog/create?blog[title]=hello&blog[content]=world, vous obtiendrez :
{
"title": "hello",
"content": "world"
}
Instance de modèle
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;
// Définir ici les champs remplissables pour éviter les champs non sécurisés depuis le frontend
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;
}
}
En accédant à /user/create?user[name]=tom&user[age]=18, vous obtiendrez un résultat similaire à :
1
Cycle de vie du contrôleur
Lorsque controller_reuse dans config/app.php est false, chaque requête initialise une fois une instance du contrôleur, qui est détruite après la fin de la requête. C'est le comportement des frameworks traditionnels.
Lorsque controller_reuse dans config/app.php est true, toutes les requêtes réutilisent la même instance du contrôleur, qui reste en mémoire une fois créée.
Attention
Quand la réutilisation est activée, les requêtes ne doivent pas modifier les propriétés du contrôleur, car ces modifications affecteraient les requêtes suivantes. Par exemple :
<?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)
{
// Cette méthode conserve le modèle après la première requête update?id=1
// Une requête delete?id=2 supprimera les données de l'id 1
if (!$this->model) {
$this->model = Model::find($id);
}
return $this->model;
}
}
Conseil
Retourner des données dans le constructeur__construct()du contrôleur n'a aucun effet. Par exemple :
<?php
namespace app\controller;
use support\Request;
class FooController
{
public function __construct()
{
// Le return dans le constructeur n'a aucun effet ; le navigateur ne recevra pas cette réponse
return response('hello');
}
}
Différence entre non-réutilisation et réutilisation du contrôleur
Sans réutilisation
Chaque requête crée une nouvelle instance du contrôleur, libérée après la requête. Comportement traditionnel, familier à la plupart des développeurs. Performance légèrement inférieure (environ 10 % en benchmark helloworld, souvent négligeable en pratique).
Avec réutilisation
Une instance est créée une fois par processus et conservée. Les requêtes suivantes la réutilisent. Meilleure performance, mais moins courant pour beaucoup de développeurs.
La réutilisation n'est pas possible si :
Une requête modifie les propriétés du contrôleur – ces changements affecteraient les requêtes suivantes.
Des initialisations sont faites dans __construct() pour chaque requête – le constructeur n'est appelé qu'une fois par processus, pas à chaque requête.