# 控制器注解

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%',
            ]);
        }
    }