控制器

为了替代在路由文件中以闭包形式定义的所有的请求处理逻辑,你可能想要使用控制类来组织这些行为。控制器能将相关的请求处理逻辑组成一个单独的类。

定义控制器

通过运行 make:controller Artisan 命令来创建新的控制器

php artisan make:controller UserController

看一个基础控制器的例子,需要注意的是,该控制器继承了 Laravel 的基础控制器 App\Http\Controllers\Controller

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\User;

class UserController extends Controller
{
    /**
     * 显示指定用户的简介
     *
     * @param  int  $id
     * @return \Illuminate\View\View
     */
    public function show($id)
    {
        return view('user.profile', [
            'user' => User::findOrFail($id)
        ]);
    }
}

你可以像这样定义一个指向控制器行为的路由

use App\Http\Controllers\UserController;

Route::get('/user/{id}', [UserController::class, 'show']);

单行为控制器

如果控制器操作特别复杂,可能会发现将整个控制器类专用于单个操作会很方便。为此,可以在控制器内定义一个单一的 __invoke 方法

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\User;

class ProvisionServer extends Controller
{
    /**
     * 设置新的 web 服务器
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke()
    {
        // ...
    }
}

为单个行为控制器注册路由时,无需指定控制器方法。相反,可以简单的将控制器的名称传递给路由

use App\Http\Controllers\ProvisionServer;

Route::post('/server', ProvisionServer::class);

可以通过 Artisan 命令工具里的 make:controller 命令中的 --invokable 选项来生成可调用的控制器

php artisan make:controller ProvisionServer --invokable

控制器中间件

中间件 可以在路由文件中分配给控制器的路由

Route::get('profile', [UserController::class, 'show'])->middleware('auth');

然而,在控制器的构造函数中指定中间件更为方便。使用控制器构造函数中的 middleware 方法,可以轻松的将中间件分配给控制器。甚至可以将中间件限制为只在控制器中的某些方法生效

class UserController extends Controller
{
    /**
     * 实例化一个新的控制器实例
     *
     * @return void
     */
    public function __construct()
    {
        // 所有方法都会应用auth的中间件
        $this->middleware('auth');

        // 只有index方法应用了log的中间件
        $this->middleware('log')->only('index');

        // 除了store方法,其他方法都应用subscribed的中间件
        $this->middleware('subscribed')->except('store');
    }
}

同时,控制器还允许使用一个闭包来注册中间件,这为不定义整个中间件类的情况下为单个控制器定义中间件提供了一种便捷的方法

$this->middleware(function ($request, $next) {
    return $next($request);
});

资源型控制器

Laravel 的资源路由通过单行代码即可将典型的「CURD (增删改查)」路由分配给控制器。首先,我们可以使用 Artisan 命令 make:controller--resource 选项来快速创建一个控制器

php artisan make:controller PhotoController --resource

这个命令将会生成一个控制器 app/Http/Controllers/PhotoController.php。其中包括每个可用资源操作的方法。接下来,你可以给控制器注册一个资源路由

use App\Http\Controllers\PhotoController;

Route::resource('photos', PhotoController::class);

这个命令会生成一个控制器 app/Http/Controllers/PhotoController.php 。其中包含了每个可用资源的操作方法。 接下来,你可以给控制器注册一个资源路由

use App\Http\Controllers\PhotoController;

Route::resource('photos', PhotoController::class);

这个单一路由声明创建多个路由来处理资源上的各种行为。生成的控制器为每个行为保留了方法,包括了关于处理 HTTP 动作和 URIs 的声明注释。 可以通过将一个数组传入到resources方法中的方式来一次性的创建多个资源控制器

Route::resources([
    'photos' => PhotoController::class,
    'posts' => PostController::class,
]);

资源控制器操作处理

Verb URI Action Route Name
GET /photos index photos.index
GET /photos/create create photos.create
POST /photos store photos.store
GET /photos/{photo} show photos.show
GET /photos/{photo}/edit edit photos.edit
PUT/PATCH /photos/{photo} update photos.update
DELETE /photos/{photo} destroy photos.destroy

指定资源模型

如果你使用了路由模型的绑定 路由模型绑定 并且想在资源控制器的方法中使用类型提示,你可以在生成控制器的时候使用 --model 选项

php artisan make:controller PhotoController --resource --model=Photo

API 资源路由

当声明用于 APIs 的资源路由时,通常需要排除显示 HTML 模板的路由。例如 create and edit。为了方便起见 apiResource 方法自动排除这两个路由

use App\Http\Controllers\PhotoController;

Route::apiResource('photos', PhotoController::class);

你也可以传递一个数组给 apiResources 方法来同时注册多个 API 资源控制器

use App\Http\Controllers\PhotoController;
use App\Http\Controllers\PostController;

Route::apiResources([
    'photos' => PhotoController::class,
    'posts' => PostController::class,
]);

要快速生成不包含 createedit 方法的用于开发接口的资源控制器,请在执行 make:controller 命令时使用 --api 参数

php artisan make:controller PhotoController --api

依赖注入 & 控制器

构造注入

Laravel 服务容器 用于解析所有 Laravel 控制器。因此,你可以在控制器的构造函数中使用类型提示需要的依赖项。声明的解析会自动解析并注入到控制器实例中去

<?php

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    /**
     * 用户 repository 实例
     */
    protected $users;

    /**
     * 创建一个新的控制器实例
     *
     * @param  \App\Repositories\UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }
}

方法注入

除了构造器注入以外,你还可以在控制器方法中类型提示依赖项。最常见的用法便是注入 Illuminate\Http\Request 到你的控制器方法中

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * 保存一个新用户
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $name = $request->name;

        //
    }
}

如果你的控制器方法要从路由参数中获取输入内容,请在你的依赖项之后列出你的路由参数。例如,你可以像这样定义路由

use App\Http\Controllers\UserController;

Route::put('/user/{id}', [UserController::class, 'update']);

如下所示,你依然可以类型提示 Illuminate\Http\Request 并通过定义你的控制器方法访问 id 参数

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * 修改制定的用户
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  string  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        // 输出id
        dd($id);
    }
}
powered by GitbookEdit Time: 2023-04-08 10:28:32