Controlador
Crie um novo arquivo de controlador 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');
}
}
Quando acessar http://127.0.0.1:8787/foo, a página retornará hello index.
Quando acessar http://127.0.0.1:8787/foo/hello, a página retornará hello webman.
É claro que você pode alterar as regras de roteamento através da configuração de roteamento, consulte Roteamento.
Dica
Se você encontrar um erro 404 e não conseguir acessar, abraconfig/app.php, definacontroller_suffixcomoControllere reinicie.
Sufixo do Controlador
O webman a partir da versão 1.3 suporta a configuração de sufixo de controlador em config/app.php. Se controller_suffix em config/app.php estiver definido como vazio '', o controlador será semelhante ao seguinte
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');
}
}
É altamente recomendável definir o sufixo do controlador como Controller, pois isso pode evitar conflitos de nomes entre controladores e modelos, além de aumentar a segurança.
Nota
- O framework irá automaticamente passar o objeto
support\Requestao controlador, através do qual você pode obter os dados de entrada do usuário (get, post, cabeçalho, cookie, etc.), consulte Requisição - O controlador pode retornar números, strings ou objetos
support\Response, mas não pode retornar outros tipos de dados. - O objeto
support\Responsepode ser criado através das funções auxiliaresresponse(),json(),xml(),jsonp(),redirect(), etc.
Vinculação de Parâmetros do Controlador
Exemplo
O webman suporta a vinculação automática de parâmetros de requisição através dos parâmetros de método do controlador, por exemplo
<?php
namespace app\controller;
use support\Response;
class UserController
{
public function create(string $name, int $age): Response
{
return json(['name' => $name, 'age' => $age]);
}
}
Você pode passar os valores de name e age através dos métodos GET ou POST, ou passar os parâmetros name e age através dos parâmetros de rota, por exemplo
Route::any('/user/{name}/{age}', [app\controller\UserController::class, 'create']);
A prioridade é parâmetros de rota > GET > parâmetros POST
Valores padrão
Suponha que acessamos /user/create?name=tom, obteremos o seguinte erro
Missing input parameter age
A razão é que não passamos o parâmetro age. Podemos resolver esse problema definindo um valor padrão para o parâmetro, por exemplo
<?php
namespace app\controller;
use support\Response;
class UserController
{
public function create(string $name, int $age = 18): Response
{
return json(['name' => $name, 'age' => $age]);
}
}
Tipo de Parâmetro
Quando acessamos /user/create?name=tom&age=not_int, obteremos o seguinte erro
Dica
Aqui, para facilitar os testes, inserimos diretamente os parâmetros na barra de endereço do navegador. Na prática de desenvolvimento, os parâmetros devem ser passados via métodoPOST.
Input age must be of type int, string given
Isso ocorre porque os dados recebidos serão convertidos conforme o tipo. Se a conversão não for possível, será lançada uma exceção support\exception\InputTypeException, pois o parâmetro age passado não pode ser convertido para o tipo int, resultando no erro acima.
Erros Personalizados
Podemos utilizar o suporte a múltiplos idiomas para personalizar erros como Missing input parameter age e Input age must be of type int, string given, consulte o comando a seguir
composer require symfony/translation
mkdir resource/translations/zh_CN/ -p
echo "<?php
return [
'Input :parameter must be of type :exceptType, :actualType given' => 'O parâmetro de entrada :parameter deve ser do tipo :exceptType, foi passado o tipo :actualType',
'Missing input parameter :parameter' => 'Parâmetro de entrada :parameter ausente',
];" > resource/translations/zh_CN/messages.php
php start.php restart
Outros Tipos
Os tipos de parâmetro suportados pelo webman incluem int, float, string, bool, array, object, instância de classe, etc., por exemplo
<?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,
]);
}
}
Quando acessamos /user/create?name=tom&age=18&balance=100.5&vip=true&extension[foo]=bar, obteremos o seguinte resultado
{
"name": "tom",
"age": 18,
"balance": 100.5,
"vip": true,
"extension": {
"foo": "bar"
}
}
Instância de Classe
O webman suporta a passagem de instâncias de classe através de sugestões de tipo de parâmetro, por exemplo
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());
}
}
Quando acessamos /blog/create?blog[title]=hello&blog[content]=world, obteremos o seguinte resultado
{
"title": "hello",
"content": "world"
}
Instância de Modelo
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;
// Aqui é necessário adicionar os campos preenchíveis, para evitar que campos inseguros sejam passados do 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;
}
}
Quando acessamos /user/create?user[name]=tom&user[age]=18, obteremos um resultado semelhante a este
1
Ciclo de Vida do Controlador
Quando controller_reuse em config/app.php estiver definido como false, uma nova instância do controlador correspondente será inicializada para cada requisição. Após o término da requisição, a instância do controlador será destruída, o que é semelhante ao mecanismo de execução dos frameworks tradicionais.
Quando controller_reuse em config/app.php estiver definido como true, todas as requisições reutilizarão a instância do controlador, ou seja, uma vez que a instância do controlador é criada, ela permanece na memória, e todas as requisições reutilizarão essa instância.
Nota
Ao habilitar a reutilização do controlador, a requisição não deve alterar nenhuma propriedade do controlador, pois essas alterações afetarão as requisições subsequentes. Por exemplo
<?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)
{
// Este método irá reter o model após a primeira requisição update?id=1
// Se uma nova requisição delete?id=2 for feita, deletará os dados de 1
if (!$this->model) {
$this->model = Model::find($id);
}
return $this->model;
}
}
Dica
Retornar dados na função construtora__construct()do controlador não terá efeito, por exemplo
<?php
namespace app\controller;
use support\Request;
class FooController
{
public function __construct()
{
// Retornar dados na função construtora não terá efeito, o navegador não receberá essa resposta
return response('hello');
}
}
Diferença entre Não Reutilizar e Reutilizar Controlador
As diferenças são as seguintes
Não Reutilizar Controlador
Cada requisição cria uma nova instância do controlador. Após a requisição término, essa instância é liberada e a memória é recuperada. O não reuso do controlador é semelhante aos frameworks tradicionais, o que é mais familiar para a maioria dos desenvolvedores. Devido à criação e destruição repetidas do controlador, o desempenho será ligeiramente inferior ao de controladores reutilizados (a diferença de desempenho no teste de carga "helloworld" é de cerca de 10%, em carga real pode ser basicamente ignorada).
Reutilizar Controlador
No caso de reutilização, um processo cria a instância do controlador apenas uma vez. Após o término da requisição, a instância do controlador não é liberada e será reutilizada nas requisições subsequentes desse processo. O desempenho do controlador reutilizado é melhor, mas não é o que a maioria dos desenvolvedores está acostumada.
Caso em que não se pode usar Reutilização do Controlador
Quando uma requisição altera as propriedades do controlador, a reutilização do controlador não deve ser ativada, pois essas mudanças afetarão as requisições subsequentes.
Alguns desenvolvedores gostam de fazer algumas inicializações para cada requisição no construtor __construct() do controlador, nesse caso, a reutilização do controlador não deve ser usada, pois o construtor do processo atual será chamado apenas uma vez, e não a cada requisição.