标签: ValueResolverInterface

  • 利用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对象耦合的重复代码,将预处理的流程都放在解析中!