JMS Serializer添加EventSubscriber时遇两类错误的技术咨询
嘿,我刚好踩过这个坑!你遇到的问题核心就是混淆了JMS Serializer的EventSubscriber接口和Symfony自带的EventSubscriber接口——这俩完全是两套东西,Symfony的容器会默认对标注为事件订阅者的服务做校验,要求它实现Symfony自己的Symfony\Component\EventDispatcher\EventSubscriberInterface,但JMS的订阅者根本不需要这个。
问题到底出在哪?
当你在services.yml里注册你的NoticePostSerializeSubscriber时,大概率是加了kernel.event_subscriber标签(或者Symfony的自动配置把它识别成了Symfony事件订阅者),这时候容器就会去检查它是否符合Symfony的接口要求。但你的类实现的是JMS的\JMS\Serializer\EventDispatcher\EventSubscriberInterface,自然过不了校验,就抛出了"undefined offset 0"的错误。而你移除服务定义后,容器不再做这个校验,错误就消失了,但代价是你的JMS订阅者也不会被正确加载生效。
正确的打开方式
JMS Serializer的事件订阅者有自己的注册方式,不需要蹭Symfony核心事件订阅者的标签,要用JMS专属的jms_serializer.event_subscriber标签。
第一步:确保你的订阅者正确实现JMS的接口
先把类写对,必须实现JMS的EventSubscriberInterface,并且getSubscribedEvents()方法返回符合JMS要求的结构:
namespace AppBundle\Subscribers; use JMS\Serializer\EventDispatcher\EventSubscriberInterface; use JMS\Serializer\EventDispatcher\ObjectEvent; class NoticePostSerializeSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return [ [ 'event' => 'serializer.post_serialize', 'method' => 'onPostSerialize', 'class' => 'AppBundle\Entity\Notice', // 指定要监听的实体类 'format' => 'json', // 可选,只在指定格式下生效 ], ]; } public function onPostSerialize(ObjectEvent $event) { // 这里写你的自定义序列化逻辑 $visitor = $event->getVisitor(); $notice = $event->getObject(); $visitor->addData('extra_field', $notice->getSomeValue()); } }
第二步:在services.yml里正确注册服务
别加Symfony的kernel.event_subscriber标签,换成JMS的专属标签:
# app/config/services.yml services: AppBundle\Subscribers\NoticePostSerializeSubscriber: tags: - { name: jms_serializer.event_subscriber }
如果你的Symfony版本支持自动配置(比如Symfony 3.4+),甚至可以不用手动加标签——只要你的订阅者类在容器自动扫描的目录下(比如AppBundle\Subscribers),并且services.yml里有类似AppBundle\Subscribers\: resource: '../src/AppBundle/Subscribers'的配置,JMS Serializer的Bundle会自动识别实现了它的EventSubscriberInterface的服务,自动帮你加上标签。
为啥会出现"undefined offset 0"?
这个错误其实是Symfony的事件订阅者校验逻辑搞出来的:Symfony期望getSubscribedEvents()返回的数组结构符合它的规范,但JMS的返回结构虽然看起来类似,细节上不一样,Symfony的校验代码在解析时找不到预期的索引,就抛出了"undefined offset 0"。本质还是因为你把两个不同的接口搞混,用错了注册标签。
总之,记住一句话:JMS Serializer的订阅者有自己的注册方式,别和Symfony核心事件订阅者搞混,用对标签就一切正常啦!
内容的提问来源于stack exchange,提问作者bielu000

