利用Attribute特性和ValueResolverInterface为Symfony注入IP

PHP8发布之后越发爱不释手,尤其Attribute比Annotation强大不少,Attribute可以对单个参数进行控制,这个功能很强大。演示一下控制器中通过Attribute描述字段来获得当前IP,其实一般解析器都是用来denormalize客户端POST过来的参数,但是为了用到Attribute,我用IP来举例。

<?php
namespace App\Resolver;
use Attribute;

#[Attribute(Attribute::TARGET_PARAMETER)]
final class IP
{
}

先设计一个Attribute申明,注意TARGET_PARAMETER标识作用在参数范围。

<?php
namespace App\Resolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;

class IPValueResolver implements ValueResolverInterface
{
    public function resolve(Request $request, ArgumentMetadata $argument): iterable
    {
        $argumentType = $argument->getType();
        // 检查IP的Attribute
        $attributes = $argument->getAttributes(IP::class);
        if (count($attributes) == 0 || $argumentType !== 'string') {
            return [];
        }
        yield $request->getClientIp();
    }
}

其次,编写一个解析器,注意,Symfony 6.2开始提供ValueResolverInterface,之前版本用ArgumentValueResolverInterface

public function resolver(#[IP] string $ip): Response

最后,便是在任何控制器的方法中,只要使用了#[IP] string $ip就能方便的取得IP了。正确使用解析器,可以大大降低控制器中和Request对象耦合的重复代码,将预处理的流程都放在解析中!


已发布

分类

作者: