前言:备忘录说明
一直用Yii2,期待yii3的新设计模式,N多年yii3完成近90%左右,主包也已发布并可生产环境使用,但是未正式发布。看github上还在讨论如何兼容yii2.2,php>8.1等问题,可以看出yii3可能任然遥遥无期,团队仍旧无法摈弃低版本的兼容而彻底拥抱php8.2-8.3,肯定会冗余,转而学习symfony7。 基于对yii2的使用,新学习symfony 任然有较大不同,所以做一些关键日志,为实际项目提供较快的查阅帮助。
可能部分备注不准确,请指正。
1. 基于配置、自动注入、注解等多重方式并行
symfony 基于yaml等格式的配置,服务(事件、监听器)等都可以直接配置。同时,在配置了自动载入目录后系统可以系统读取并且载入从而不用特定在配置文件中配置。从而要求 目录结构、服务等需要规范化,否则无法有效的去管理代码。
重点提醒: 1、规范目录、划分明显的服务模块 2、全局服务等尽量在配置中约定、并且做好注释
2. 监听器
//自建监听器
class AnyListener
{
//event 监听的事件类型依据事务确定
public function onDo1(ControllerEvent $event){}
public function onDo2(ExceptionEvent $event){}
//__invoke 在没有明确的处理方法时调用
public function __invoke(ExceptionEvent $event): void {}
}
services:
#service.yaml 配置监听器
App\EventListener\ExceptionListener:
tags:
# name 类型为事件监听器,event 监听的事件,method 处理方法(如果没有会调用__invoke)
- { name: kernel.event_listener, event: kernel.controller, method:onDo1 }
# kernel.exception 异常事件,kernel.controller 事件,等等。。。
- { name: kernel.event_listener, event: kernel.exception, method:onDo2 }
经过以上配置即可生效
也可以通过 attribute 注入AsEventListener 产生同样效果
#[AsEventListener]
#[AsEventListener(event: CustomEvent::class, method: 'onCustomEvent')]
#[AsEventListener(event: 'foo', priority: 42)]
#[AsEventListener(event: 'bar', method: 'onBarEvent')]
class ExceptionListener
3.订阅器
//自建订阅器
class TestSubscriber implements EventSubscriberInterface
{
//如果自动注入有参数,需要在配置中配置参数,如果没有参数,则可以不
//public function __construct(private array $tokens){}
public static function getSubscribedEvents()
{
return [
//监听的事件名称
KernelEvents::CONTROLLER => 'onKernelController'
//等等其他事件
KernelEvents::RESPONSE => 'onKernelController'
];
//多个处理器
return [
KernelEvents::EXCEPTION => [
['processException', 10],
['logException', 0],
['notifyException', -10],
],
];
}
public function onKernelController(ControllerEvent $event){}
}
订阅器可以被系统自动识别产生监听效果,不用配置服务也行。这个就非常的灵活和简单,所以规范好目录后就可以马不停蹄的添加订阅器了,相比监听器便捷。
但是,如果有特别参数等,就需要特殊配置,例如:
class TestSubscriber implements EventSubscriberInterface
{
//如果自动注入有参数,需要在配置中配置参数
//public function __construct(private array $tokens){}
配置:
params:
tokens:
client1: pass1
client2: pass2
services:
App\EventSubscriber\TestSubscriber:
# 注入参数
arguments:
$tokens: '%tokens%'
tags:
- { name: kernel.event_subscriber }
以下非常棒的设计:
namespace App\Controller;
use App\Controller\TokenAuthenticatedController;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class FooController extends AbstractController implements TokenAuthenticatedController
{
// An action that needs authentication
public function bar(): Response
{
// ...
}
}
// src/EventSubscriber/TokenSubscriber.php
namespace App\EventSubscriber;
use App\Controller\TokenAuthenticatedController;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
class TokenSubscriber implements EventSubscriberInterface
{
public function __construct(
private array $tokens
) {
}
public function onKernelController(ControllerEvent $event): void
{
$controller = $event->getController();
// when a controller class defines multiple action methods, the controller
// is returned as [$controllerInstance, 'methodName']
if (is_array($controller)) {
$controller = $controller[0];
}
if ($controller instanceof TokenAuthenticatedController) {
$token = $event->getRequest()->query->get('token');
if (!in_array($token, $this->tokens)) {
throw new AccessDeniedHttpException('This action needs a valid token!');
}
}
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::CONTROLLER => 'onKernelController',
];
}
}
通过创建接口然后控制器继承,然后在事件监听器中去识别接口对象,来处理权限等逻辑,是非常棒的设计,根据不同的权限或者业务创建不同的接口,再在监听器中去判断处理业务,很灵活。
后续内容随着学习完善…