控制器注解

PHP 注解可用于在控制器类和方法上定义过滤器及其他元数据。这样能让配置紧邻受影响的代码,且一眼即可看出特定控制器或方法应用了哪些过滤器。此方式适用于所有路由方式(包含自动路由),使得自动路由在功能上几乎能与更为强大的路由声明相媲美。

快速入门

控制器注解既可应用于整个类,也可应用于特定方法。以下示例展示了如何在控制器类上应用 Filters 注解:

<?php

namespace App\Controllers;

use CodeIgniter\Router\Attributes\Filter;

#[Filter(by: 'auth')]
class AdminController extends BaseController
{
    public function index()
    {
        return view('welcome_message');
    }
}

在此示例中,Auth 过滤器将应用于 AdminController 中的所有方法。

也可以将 Filters 注解应用于控制器内的特定方法。这样可以仅对部分方法应用过滤器,而不影响其他方法。示例如下:

<?php

namespace App\Controllers;

use CodeIgniter\Router\Attributes\Filter;

#[Filter(by: 'group', having: ['admin', 'superadmin'])]
class AdminController extends BaseController
{
    #[Filter(by: 'permission', having: ['users.manage'])]
    public function users()
    {
        // Will have 'group' filter with ['admin', 'superadmin']
        // and 'permission' filter with ['users.manage']
    }
}

类级别注解和方法级别注解可协同工作,为控制器层级的路由管理提供灵活方案。

禁用注解

如果确认应用中不使用注解,可将 app/Config/Routing.php 文件中的 $useControllerAttributes 注解设置为 false 以禁用此功能。

内置注解

过滤器

Filters 注解允许指定一个或多个过滤器,并将其应用于控制器类或方法。可指定在控制器动作执行前或执行后运行过滤器,并为过滤器传递参数。以下是 Filters 注解的使用示例:

<?php

namespace App\Controllers;

use CodeIgniter\Router\Attributes\Filter;

class HomeController extends BaseController
{
    // Apply the filter by it's alias name
    #[Filter(by: 'csrf')]
    public function index()
    {
    }

    // Apply a filter with arguments
    #[Filter(by: 'throttle', having: ['60', '1'])]
    public function api()
    {
    }

    // Multiple filters can be applied by repeating the attribute
    #[Filter(by: 'auth')]
    #[Filter(by: 'csrf')]
    public function admin()
    {
    }
}

备注

当注解和过滤器配置文件中同时定义了过滤器时,两者都会生效,但可能会产生非预期结果。

备注

请注意,传递给过滤器的所有参数都会被转换为字符串。此行为仅影响过滤器。

Restrict

Restrict 注解允许根据域名、子域名或应用运行环境来限制对类或方法的访问。以下是 Restrict 注解的使用示例:

<?php

namespace App\Controllers;

use CodeIgniter\Router\Attributes\Restrict;

// Restrict access by environment
#[Restrict(environment: ['development', '!production'])]
class HomeController extends BaseController
{
    // Restrict access by hostname
    #[Restrict(hostname: 'localhost')]
    public function index()
    {
    }

    // Multiple allowed hosts
    #[Restrict(hostname: ['localhost', '127.0.0.1', 'dev.example.com'])]
    public function devOnly()
    {
    }

    // Restrict to subdomain, e.g. admin.example.com
    #[Restrict(subdomain: 'admin')]
    public function deleteItem($id)
    {
    }
}

缓存

Cache 注解允许将控制器方法的输出缓存指定时长。可以以秒为单位指定时长,并可选择性地设置缓存键。以下是 Cache 注解的使用示例:

<?php

namespace App\Controllers;

use CodeIgniter\Router\Attributes\Cache;

class HomeController extends BaseController
{
    // Cache this method's response for 2 hours
    #[Cache(for: 2 * HOUR)]
    public function index()
    {
        return view('welcome_message');
    }

    // Custom cache key
    #[Cache(for: 10 * MINUTE, key: 'custom_cache_key')]
    public function custom()
    {
        return 'This response is cached with a custom key for 10 minutes.';
    }
}

自定义注解

也可以创建自定义注解,为控制器和方法添加元数据或行为。自定义注解必须实现 CodeIgniter\Router\Attributes\RouteAttributeInterface 接口。以下示例展示了如何通过自定义注解在响应中添加自定义标头:

<?php

namespace App\Attributes;

use Attribute;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Router\Attributes\RouteAttributeInterface;

/**
 * Custom Header Attribute
 *
 * Adds custom headers to the response. This is useful for:
 * - Adding security headers
 * - Setting API version information
 * - Adding custom metadata to responses
 */
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class AddHeader implements RouteAttributeInterface
{
    /**
     * @param string $name  The header name
     * @param string $value The header value
     */
    public function __construct(
        private readonly string $name,
        private readonly string $value,
    ) {
    }

    /**
     * Called before the controller method executes.
     * Return null to continue to the controller.
     */
    public function before(RequestInterface $request): RequestInterface|ResponseInterface|null
    {
        // We don't need to do anything before the controller runs
        return null;
    }

    /**
     * Called after the controller method executes.
     * Add the custom header to the response.
     */
    public function after(RequestInterface $request, ResponseInterface $response): ?ResponseInterface
    {
        $response->setHeader($this->name, $this->value);

        return $response;
    }
}

随后可以像使用内置注解一样,将此自定义注解应用于控制器类或方法:

<?php

namespace App\Controllers;

use App\Attributes\AddHeader;
use CodeIgniter\Controller;
use CodeIgniter\Router\Attributes\Cache;

class Api extends Controller
{
    /**
     * Add a single custom header
     */
    #[AddHeader('X-API-Version', '2.0')]
    public function userInfo()
    {
        return $this->response->setJSON([
            'name'  => 'John Doe',
            'email' => 'john@example.com',
        ]);
    }

    /**
     * Add multiple custom headers using the IS_REPEATABLE attribute option.
     * Each AddHeader attribute will be executed in order.
     */
    #[AddHeader('X-API-Version', '2.0')]
    #[AddHeader('X-Rate-Limit', '100')]
    #[AddHeader('X-Content-Source', 'cache')]
    public function statistics()
    {
        return $this->response->setJSON([
            'users' => 1500,
            'posts' => 3200,
        ]);
    }

    /**
     * Combine custom attributes with built-in attributes.
     * The Cache attribute will cache the response,
     * and AddHeader will add the custom header.
     */
    #[AddHeader('X-Powered-By', 'My Custom API')]
    #[Cache(for: 3600)]
    public function dashboard()
    {
        return $this->response->setJSON([
            'status' => 'operational',
            'uptime' => '99.9%',
        ]);
    }
}