跳到内容

@ParamConverter

编辑此页
在当前的 Symfony 应用中,不再推荐使用此扩展包。此扩展包提供的所有注解现在都内置在 Symfony 中,作为 PHP 属性。查看 Symfony 属性的完整列表

用法

@ParamConverter 注解调用*转换器*将请求参数转换为对象。这些对象存储为请求属性,因此可以作为控制器方法参数注入

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

/**
 * @Route("/blog/{id}")
 * @ParamConverter("post", class="SensioBlogBundle:Post")
 */
public function show(Post $post)
{
}

幕后发生了一些事情

  • 转换器尝试从请求属性中获取 SensioBlogBundle:Post 对象(请求属性来自路由占位符 -- 这里是 id);
  • 如果未找到 Post 对象,则生成 404 响应;
  • 如果找到 Post 对象,则定义一个新的 post 请求属性(可通过 $request->attributes->get('post') 访问);
  • 对于其他请求属性,当方法签名中存在时,它会自动注入到控制器中。

如果您像上面的示例一样使用类型提示,您甚至可以省略 @ParamConverter 注解

1
2
3
4
// automatic with method signature
public function show(Post $post)
{
}

您可以通过将 auto_convert 标志设置为 false 来禁用类型提示方法参数的自动转换功能

1
2
3
4
5
# config/packages/sensio_framework_extra.yaml
sensio_framework_extra:
    request:
        converters: true
        auto_convert: false

您还可以按名称显式禁用某些转换器

1
2
3
4
5
# config/packages/sensio_framework_extra.yaml
sensio_framework_extra:
    request:
        converters: true
        disable: ['doctrine.orm', 'datetime']

要检测在参数上运行哪些转换器,将运行以下过程

  • 如果使用 @ParamConverter(converter="name") 显式选择了转换器,则选择具有给定名称的转换器。
  • 否则,所有已注册的参数转换器都按优先级迭代。调用 supports() 方法来检查参数转换器是否可以将请求转换为所需的参数。如果它返回 true,则调用参数转换器。

内置转换器

此扩展包有两个内置转换器,Doctrine 转换器和 DateTime 转换器。

Doctrine 转换器

转换器名称: doctrine.orm

Doctrine 转换器尝试将请求属性转换为从数据库中获取的 Doctrine 实体。有几种不同的方法是可能的

1) 自动获取

如果您的路由通配符与实体上的属性匹配,则转换器将自动获取它们

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * Fetch via primary key because {id} is in the route.
 *
 * @Route("/blog/{id}")
 */
public function showByPk(Post $post)
{
}

/**
 * Perform a findOneBy() where the slug property matches {slug}.
 *
 * @Route("/blog/{slug}")
 */
public function show(Post $post)
{
}

自动获取在以下情况下有效

  • 如果 {id} 在您的路由中,则使用它通过 find() 方法按主键获取。
  • 转换器将尝试通过使用路由中*所有*实际上是实体属性的通配符(非属性将被忽略)来执行 findOneBy() 获取。

您可以通过实际*添加* @ParamConverter 注解并使用 @ParamConverter 选项来控制此行为。

2) 通过表达式获取

如果自动获取不起作用,请使用表达式

1
2
3
4
5
6
7
8
9
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity;

/**
 * @Route("/blog/{post_id}")
 * @Entity("post", expr="repository.find(post_id)")
 */
public function show(Post $post)
{
}

使用特殊的 @Entity 注解和 expr 选项,通过调用存储库上的方法来获取对象。repository 方法将是您实体的 Repository 类,任何路由通配符(如 {post_id})都可用作变量。

提示

@Entity 注解是使用 expr 的快捷方式,并且具有与 @ParamConverter 相同的所有选项。

这也可以用于帮助解决多个参数

1
2
3
4
5
6
7
/**
 * @Route("/blog/{id}/comments/{comment_id}")
 * @Entity("comment", expr="repository.find(comment_id)")
 */
public function show(Post $post, Comment $comment)
{
}

在上面的示例中,$post 参数是自动处理的,但 $comment 是使用注解配置的,因为它们不能都遵循默认约定。

DoctrineConverter 选项

@ParamConverter 或 (@Entity) 注解上提供了许多 options 来控制行为

  • id: 如果配置了 id 选项并与路由参数匹配,则转换器将按主键查找

    1
    2
    3
    4
    5
    6
    7
    /**
     * @Route("/blog/{post_id}")
     * @ParamConverter("post", options={"id" = "post_id"})
     */
    public function showPost(Post $post)
    {
    }
  • mapping: 配置与 findOneBy() 方法一起使用的属性和值:键是路由占位符名称,值是 Doctrine 属性名称

    1
    2
    3
    4
    5
    6
    7
    8
    /**
     * @Route("/blog/{date}/{slug}/comments/{comment_slug}")
     * @ParamConverter("post", options={"mapping": {"date": "date", "slug": "slug"}})
     * @ParamConverter("comment", options={"mapping": {"comment_slug": "slug"}})
     */
    public function showComment(Post $post, Comment $comment)
    {
    }
  • exclude 配置应在 findOneBy() 方法中使用的属性,方法是*排除*一个或多个属性,以便不使用*所有*属性

    1
    2
    3
    4
    5
    6
    7
    /**
     * @Route("/blog/{date}/{slug}")
     * @ParamConverter("post", options={"exclude": {"date"}})
     */
    public function show(Post $post, \DateTime $date)
    {
    }
  • strip_null 如果为 true,则当使用 findOneBy() 时,任何值为 null 的值将不会用于查询。
  • entity_manager 默认情况下,Doctrine 转换器使用*默认*实体管理器,但您可以配置它

    1
    2
    3
    4
    5
    6
    7
    /**
     * @Route("/blog/{id}")
     * @ParamConverter("post", options={"entity_manager" = "foo"})
     */
    public function show(Post $post)
    {
    }
  • evict_cache 如果为 true,则强制 Doctrine 始终从数据库而不是缓存中获取实体。

DateTime 转换器

转换器名称: datetime

datetime 转换器将任何路由或请求属性转换为 datetime 实例

1
2
3
4
5
6
/**
 * @Route("/blog/archive/{start}/{end}")
 */
public function archive(\DateTime $start, \DateTime $end)
{
}

默认情况下,接受 DateTime 构造函数或 unix 时间戳可以解析的任何日期格式。您可以通过选项对给定的输入进行更严格的限制

1
2
3
4
5
6
7
8
/**
 * @Route("/blog/archive/{start}/{end}")
 * @ParamConverter("start", options={"format": "!Y-m-d"})
 * @ParamConverter("end", options={"format": "!Y-m-d"})
 */
public function archive(\DateTime $start, \DateTime $end)
{
}

格式错误的日期(如 2017-21-22)将返回 404。

创建转换器

所有转换器都必须实现 ParamConverterInterface

1
2
3
4
5
6
7
8
9
10
11
namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\HttpFoundation\Request;

interface ParamConverterInterface
{
    function apply(Request $request, ParamConverter $configuration);

    function supports(ParamConverter $configuration);
}

supports() 方法能够转换给定的配置(ParamConverter 实例)时,它必须返回 true

ParamConverter 实例具有关于注解的三个信息

  • name: 属性名称;
  • class: 属性类名(可以是表示类名的任何字符串);
  • options: 选项数组。

每当支持配置时,都会调用 apply() 方法。基于请求属性,它应设置一个名为 $configuration->getName() 的属性,该属性存储一个类为 $configuration->getClass() 的对象。

如果您正在使用服务自动注册和自动配置,那么您就完成了!您的转换器将自动被使用。

您可以按优先级、按名称(属性 "converter")或两者都注册转换器。如果您未指定优先级或名称,则会将转换器添加到转换器堆栈,优先级为 0。要显式禁用按优先级注册,您必须在标记定义中设置 priority="false"

提示

如果您想将服务或附加参数注入到自定义参数转换器中,则优先级不应高于 1。否则,服务将无法加载。

提示

使用 DoctrineParamConverter 类作为您自己的转换器的模板。

本作品,包括代码示例,均根据 Creative Commons BY-SA 3.0 许可证获得许可。
TOC
    版本