## 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 第三方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
sensio/framework-extra-bundle #提供在控制器中注解命令的支持,自带 jms/di-extra-bundle #提供注解命令实现属性注入的支持 doctrine/doctrine-fixtures-bundle #提供data fixture支持
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操作
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
标准化并集中管理对象的初始化 ############ 原始类 ############# 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');
## 前端控制器 $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, 监听器从大到小值调用