Symfony2 细节小计2

配置文件

## app/config/ 下
parameter.yml  # 由于参数敏感,该文件被版本控制系统忽略
parameter.yml.dist  # 在parameter.yml中定义的参数需要也在这里添加,该文件是它的配置模板
                    # 每次部署,该文件会与之比对,如有差异,symfony会要求提供新参数在parameter.yml中


请求

$request = Request::createFromGlobals();
$request->isXmlHttpRequest();
        ->getMethod();
        ->query->get('var', 'default');
        ->request->get();
        ->files->get();
        ->cookies->get();
        ->server->get();
        ->headers->get();
        ->getSession();
        ->isSecure(); //判定https
        ->attributes->get('_controller, _route, {id} ....');
        ->getRequestFormat();
        ->getContent();

parameter bags通用方法
->get();
->has();
->all();


响应

$response = new Response($content, $Response::HTTP_OK);  //Response::HTTP_NOT_FOUND
$response->setStatusCode(Response::HTTP_OK);    
        ->headers->set('Content-Type', 'text/html');
        ->setContent('<html><body><h1>Hello world!</h1></body></html>');
        ->send();

JsonResponse,  BinaryFileResponse.

页面报错:
400 - throw Controller->createNotFoundException();
500 - throw new \Exception('Something wrong!');

FlashMessage:
Controller->addFlash('notice', 'Congratulations, your action succeeded!');

<div>
    {{ app.session.flashbag.get('notice') }}
</div>


Serializer

220912_HqDE_2400083.png

框架自带组件:Serializer
第三方bundle:JMSSerializerBundle

启用序列化组件(服务启用后默认配备JsonEncoder和XmlEncoder,但没有标准化器 normalizers)
# app/config/config.yml
framework:
    serializer:
        enabled: true
        
给服务打tag以标注其为normalizer或encoder, 从而在序列化载入时一起载入它们
# app/config/config.yml
services:
   get_set_method_normalizer:
      class: Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer
      tags:
         - { name: serializer.normalizer }
         
#使用序列化时仅需配置序列化器的可用服务:
$encoders = array(new XmlEncoder(), new JsonEncoder());
$normalizers = array(new GetSetMethodNormalizer());
$serializer = new Serializer($normalizers, $encoders);

$person = new Acme\Person();
$jsonContent = $serializer->serialize($person, 'json');  //第二参指定encoder


#忽略部分部分属性的序列化
$normalizer = new GetSetMethodNormalizer();
$normalizer->setIgnoredAttributes(array('age'));

#反序列化
$data = "<person><name>foo</name><age>99</age><sportsman>false</sportsman></person>";
$person = $serializer->deserialize($data, 'Acme\Person', 'xml'); #第二参指定需生成的类, 第三参指定encoder


常见Bundle用途

sensio/framework-extra-bundle  #提供在控制器中注解命令的支持,自带
jms/di-extra-bundle  #提供注解命令实现属性注入的支持
doctrine/doctrine-fixtures-bundle  #提供data fixture支持


Bundle创建流程

php app/console generate:bundle ------ bundle目录
                                    |-AppKernel->registerBundles(); //内核注册Bundle
                                    |-app/config/routing.yml; //路由配置
                                    |-app/config/config.yml; //Bundle配置

bundle路径格式:
@BUNDLE_NAME/path/to/file //注解命令索引bundle文件
BUNDLE_NAME:CONTROLLER_NAME:ACTION_NAME //索引action操作


安装第三方Bundle

1.composer安装bundle
2.内核注册启用bundle
3.配置bundle(app/config/config.yml及bundle内配置文件)
    app/console config:dump-reference AsseticBundle //dump出bundle配置帮助
    bundle/Resource/doc/index.md   //bundle配置帮助文件


调试

dump($articles); //控制器调试
{{ dump(articles) }} //模板调试(必须TwigBundle的debug配置为true)

debug toolbar 只有在render()调用过后才会显示


性能

1.安装apc字节码缓存拓展, 并关闭文件检查php.ini => apc.stat=0 转为手动管理 代码更新 引起的 apc缓存失效
2.web/app.php 打开 ApcClassLoader
3.使用引导文件 web/app.php 启用 require_once __DIR__.'/../app/bootstrap.php.cache' //类定义聚合文件
4.使用http反向代理缓存系统AppCache或者专业的Varnish, Squid等


服务容器

经常使用的类 及 被其他服务依赖的类 可以注册为服务

服务配置:
services:
    service_name:
        public: bool,  #false时, 该服务仅能用于配置定义依赖, 不能再容器中取出
        class: Acme\HelloBundle\Mailer
        arguments: []
        file: %kernel.root_dir%/src/path/to/file/foo.php #加载服务前提依赖文件
        tags:
            - {name: xxx}
# 一般的, service_name会定义为目录名加类名,从而避免同名冲突, 如这里的:acme.hello.mailer
# 当然, 其他合理的短名称也是可以的
                        
            
容器调用:
$controller->get($service_name);

YAML格式的数组参数定义:
方式1: 数组括号【】
方式2: 前导横线 “-    {item1}“

YAML文件导入外部资源:
方式1: imports命令
    imports:
    - { resource: "@AcmeHelloBundle/Resources/config/services.yml" }
方式2:
    使用服务拓展类导入配置
    
ServiceContainer配置:
services:
    my_mailer:        # ...
    newsletter_manager:
        class:     Acme\HelloBundle\Newsletter\NewsletterManager
        arguments: [无引号string参数,@my_mailer, @?my_mailer, "@=service('mailer_configuration').getMailerMethod()"]    #申明一个依赖(构造函数注入), 申明一个可选依赖(构造函数注入, 参数须带默认值), 申明依赖一个表达式值
        calls:
            - [setMailer, ["@my_mailer"]] #申明可选依赖(setter注入)
            
服务别名($container->get('bar'); ):
services:
   foo:     
       class: Acme\HelloBundle\Foo
   bar:
       alias: foo


DI组件

标准化并集中管理对象的初始化

############ 原始类 #############
class Mailer{
    private $transport;

    public function __construct($transport)
    {
        $this->transport = $transport;
    }
}
class NewsletterManager{
    private $mailer;

    public function __construct(\Mailer $mailer)
    {
        $this->mailer = $mailer;
    }
    
    public function setMailer(\Mailer $mailer)
    {
        $this->mailer = $mailer;
    }
}

########## AAAAAA ###########
## PHP代码来注册服务
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
$container = new ContainerBuilder();
$container->setParameter('mailer.transport', 'sendmail');
$container
    ->register('mailer', 'Mailer')
    ->addArgument('%mailer.transport%'); //或者直接传参 ->addArgument('sendmail');
$container 
    ->register('newsletter_manager', 'NewsletterManager')
    ->addArgument(new Reference('mailer')); //构造函数注入
$container
    ->register('newsletter_manager', 'NewsletterManager')
    ->addMethodCall('setMailer', array(new Reference('mailer'))); //setter注入
######## BBBBBB ##########
## 加载配置文件来注册服务
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

$container = new ContainerBuilder();
$loader = new YamlFileLoader($container, new FileLocator(__DIR__));
$loader->load('services.yml');
######## CCCCCC ##########
## 直接在配置文件中注册服务(即服务容器配置)




################################
####### 获得容器中的服务 ########
use Symfony\Component\DependencyInjection\ContainerBuilder;
$container = new ContainerBuilder();
$newsletterManager = $container->get('newsletter_manager');


Symfony内部机制

## 前端控制器
$kernel = new AppKernel('环境', '是否debug模式');


框架层次:
FrameworkBundle
^
HttpKernel  处理http动态部分
^
HttpFoundation  最底层, 抽象出了一组http处理的对象

内核依赖ControllerResolverInterface的一个实现来选择合适的控制器, 接口声明了两个方法:
    public function getController(Request $request); //默认将通过RouterListener去定义了Request::_controller属性(类似于Bundle\BlogBundle\PostController:indexAction), 最后返回callable形式的controller
    public function getArguments(Request $request, $controller); //默认在Requestion属性中寻找(同名匹配action需要的参数)
    
AppKernel::handle(Request, RequestType, EnableException)的内部实现依赖Resolver和一组有序时间通知链 从而 将 请求 转为 响应


应用生命周期, HttpKernel抛出KernelEvents事件,监听器收到相应事件类:  

    1.kernel.request,事件类GetResponseEvent. 在request dispatching的最初时抛出
    此处可在框架流程开始前就返回响应(任意相关监听器通过setResponse方法在Event上写入Response。如果有监听器返回了Response, 则后续监听器直接略过, 直接跳8)
    一般的FrameworkBundle此处通过RouteListener计算Request::_controller。
    一般挂载在此处的监听器需要判断下$event->isMasterRequest(), 避免响应内部子请求。
    |
    V
    2.调用Resolver来找到Controller(callable形式)
    |
    V
    3.kernel.controller,事件类FilterControllerEvent. 当请求匹配到controller时抛出
    可在此处切换控制器
    |
    V
    4.kernel检查Controller是有效callable
    |
    V
    5.调用Resolver来找到参数传给Controller
    |
    V
    6.Kernel正式调用Controller
    |
    V
    7.kernel.view,事件类GetResponseForControllerResultEvent,当Controller返回非Response实例时抛出
    此处可为controller返回值创建response(监听器获取原始值$event->getControllerResult()并将其转化为Response)
    |
    V
    8.kernel.response,事件类FilterResponseEvent, 当针对请求创建了response时抛出
    此处可调整或替换response(获取响应$event->getResponse())
    |
    V    
    9.返回Response
    |
    V
    10.kernel.finish_request, 事件类FinishRequestEvent,当针对请求生成好http响应时抛出
    如果请求导致调整了应用环境状态,可在此处理, 无论成功或异常都会执行到这
    |
    V
    11.kernel.terminate,事件类PostResponseEvent,当response送出后抛出
    可做些收尾工作
    
    kernel.exception,事件类GetResponseForExceptionEvent,当应用内部未能捕获掉异常时抛出
    此处可处理异常抛出后如何响应或进一步调整异常。异常处理成功, 则进入8。失败, 则将异常重新抛出。
    FramworkBundle注册了ExceptionListener来将请求引导到特定控制器
    在内部请求处理时, 不希望捕获异常, 可在handle()方法第三参传false来关闭kernel.exception事件.
    
    
    监听器处理 kernel.request, kernel.view or kernel.exception 时, 设定了response后, 事件不再传递, 因而这些事件的低优先级监听器不会被调用到
    
#############################################################################################################################################################

FramworkBundle注册了如下监听器:
ProfilerListener 从当前Request中收集数据
WebDebugToolbarListener 注入web调试工具条
ResponserListener 填写响应的content-type信息
EsiListener 添加一个代理控制http头,如果响应存在Esi标签

事件调试:
app/console debug:event-dispatcher 【事件名】
    
内部请求:
每次主请求期间可以执行子请求, 在handle()第二参传入请求类型RequestType
HttpKernelInterface::MASTER_REQUEST;
HttpKernelInterface::SUB_REQUEST;


事件:
Kernel可用Event都继承自KernelEvent.
KernelEvent ->getRequestType();
            ->isMasterRequest();
            ->getKernel();
            ->getRequest();
            
获取调试信息:
$profile = $container->get('profiler')->loadProfileFromResponse($response);
$profile = $container->get('profiler')->loadProfile($token);

导出导入调试信息:
$data = $profiler->export($profile);
$profiler->import($data);

获取调试token(也保存在http响应头X-Debug-Token):
$tokens = $container->get($host_ip, $url_pattern, $latest_count, $time_begin, $time_end);


事件监听

symfony自带许多事件、钩子
由 HttpKernel 组件抛出(定义在KernelEvents类中)

监听事件流程:
1. 创建事件监听器
class AcmeExceptionListener
{
    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        $exception = $event->getException();
        if ($exception instanceof HttpExceptionInterface) {}
        //....
        $event->setResponse($response); //对象上设定response(对象是传引用)
    }
}
2. 监听器注册为服务, 并绑定到事件
# app/config/services.yml
services:
    kernel.listener.your_listener_name:
        class: AppBundle\EventListener\AcmeExceptionListener
        tags:
            - { name: kernel.event_listener, event: kernel.exception, method: onKernelException, priority: xxx }  #priority参数可选, 默认为0, 范围-255 ~ 255, 监听器从大到小值调用


转载于:https://my.oschina.net/u/2400083/blog/500654

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值