Contrôleur

Créez un 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');
    }
}

Lorsque vous accédez à http://127.0.0.1:8787/foo, la page renvoie hello index.

Lorsque vous accédez à http://127.0.0.1:8787/foo/hello, la page renvoie hello webman.

Bien sûr, vous pouvez modifier les règles de routage via la configuration des routes, voir Routage.

Avertissement
Si un 404 apparaît et que vous ne pouvez pas accéder, ouvrez config/app.php, définissez controller_suffix sur Controller, puis redémarrez.

Suffixe du contrôleur

webman à partir de la version 1.3 prend en charge la définition du suffixe du contrôleur dans config/app.php, si controller_suffix est défini comme vide '' dans config/app.php, 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, cela permet d'éviter les conflits de noms entre les contrôleurs et les modèles, tout en augmentant la sécurité.

Remarques

  • Le framework transmet automatiquement un objet support\Request au contrôleur, à travers lequel vous pouvez obtenir les données saisies par l'utilisateur (données get post header cookie, etc.), voir Requête
  • Le contrôleur peut retourner des nombres, des chaînes ou des objets support\Response, mais ne peut pas retourner d'autres types de données.
  • L'objet support\Response peut être créé via les fonctions d'assistance response(), json(), xml(), jsonp(), redirect(), etc.

Liaison des paramètres du contrôleur

Exemple

webman prend en charge la liaison automatique des paramètres de requête via les paramètres de méthode 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 name et age via les méthodes GET ou POST, ou les transmettre via des paramètres de route, par exemple

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

La priorité est paramètres de route > GET > paramètres POST

Valeurs par défaut

Supposons que nous accédions à /user/create?name=tom, nous obtiendrons l'erreur suivante

Missing input parameter age

La raison en est que nous n'avons pas transmis le paramètre age, ce problème peut être résolu en définissant une valeur par défaut pour le paramètre, 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]);
    }
}

Type de paramètre

Lorsque nous accédons à /user/create?name=tom&age=not_int, nous obtiendrons l'erreur suivante

Avertissement
Ici, pour des raisons de commodité de test, nous avons directement saisi les paramètres dans la barre d'adresse du navigateur, dans un développement réel, les paramètres devraient être transmis par la méthode POST

Input age must be of type int, string given

C'est parce que les données acceptées seront converties en fonction du type, et si la conversion échoue, une exception support\exception\InputTypeException sera levée,
comme le paramètre age transmis ne peut pas être converti en type int, l'erreur ci-dessus est donc renvoyée.

Erreurs personnalisées

Nous pouvons personnaliser des erreurs comme Missing input parameter age et Input age must be of type int, string given en utilisant plusieurs langues, voir la commande suivante

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, :actualType donné',
    'Missing input parameter :parameter' => 'Paramètre d’entrée manquant :parameter',
];" > resource/translations/zh_CN/messages.php
php start.php restart

Autres types

Les types de paramètres supportés par webman comprennent int, float, string, bool, array, object, instances de classe, etc., 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,
        ]);
    }
}

Lorsque nous accédons à /user/create?name=tom&age=18&balance=100.5&vip=true&extension[foo]=bar, nous obtiendrons le résultat suivant

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

Instances de classe

webman prend en charge le passage d'instances de classe via des indices de type de paramètre, 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());
    }
}

Lorsque vous accédez à /blog/create?blog[title]=hello&blog[content]=world, nous allons obtenir le résultat suivant

{
  "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;
    // Ici, il faut ajouter les champs remplissables pour éviter que des champs non sécurisés soient transmis par le front-end
    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;
    }
}

Lorsque nous accédons à /user/create?user[name]=tom&user[age]=18, nous obtiendrons un résultat similaire à celui-ci

1

Cycle de vie du contrôleur

Lorsque controller_reuse dans config/app.php est false, chaque requête initialise une fois l'instance de contrôleur correspondante, une fois la requête terminée, l'instance de contrôleur est détruite, ce qui est identique au mécanisme d'exécution des frameworks traditionnels.

Lorsque controller_reuse dans config/app.php est true, toutes les requêtes réutiliseront l'instance de contrôleur, ce qui signifie que l'instance de contrôleur, une fois créée, restera en mémoire, toutes les requêtes la réutilisent.

Avertissement
Lorsque la réutilisation du contrôleur est activée, les requêtes ne doivent pas modifier les propriétés du contrôleur, car ces modifications affecteront 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 conservera le modèle après la première requête update?id=1
        // Si une requête delete?id=2 est faite par la suite, cela supprimera les données de 1
        if (!$this->model) {
            $this->model = Model::find($id);
        }
        return $this->model;
    }
}

Avertissement
Dans le constructeur __construct() du contrôleur, retourner des données n'aura aucun effet, par exemple

<?php
namespace app\controller;

use support\Request;

class FooController
{
    public function __construct()
    {
        // Retourner des données 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

Les différences sont les suivantes

Non-réutilisation du contrôleur

Chaque requête crée une nouvelle instance de contrôleur, l'instance est libérée après la fin de la requête et la mémoire est récupérée. La non-réutilisation du contrôleur est conforme à la plupart des habitudes des développeurs, similaire aux frameworks traditionnels. En raison de la création et de la destruction répétées du contrôleur, les performances sont légèrement inférieures à celles des contrôleurs réutilisés (environ 10% de différence sur le test de performance helloworld, négligeable en cas de charge métier).

Réutilisation du contrôleur

Avec la réutilisation, une instance de contrôleur n'est créée qu'une seule fois par processus, et après la fin de la requête, cette instance de contrôleur n'est pas libérée, les requêtes suivantes du processus actuel réutiliseront cette instance. La réutilisation des contrôleurs offre de meilleures performances, mais ne correspond pas à la plupart des habitudes des développeurs.

Situations où la réutilisation du contrôleur ne peut pas être utilisée

Lorsque les requêtes modifient les propriétés du contrôleur, la réutilisation du contrôleur ne doit pas être activée, car ces modifications affecteront les requêtes suivantes.

Certains développeurs aiment effectuer certaines initialisations pour chaque requête dans le constructeur du contrôleur __construct(), dans ce cas, le contrôleur ne peut pas être réutilisé, car le constructeur de l'actuel processus ne sera appelé qu'une seule fois, pas à chaque requête.