Symfony2 學習筆記之內部構件



  Symfony2內部是怎樣工作的以及我們如何來擴展它呢?
  從外部整體上看,symfony2代碼是由許多獨立的層構成,每一層都是建立在前一層基礎之上。其中,自動加載時不受框架直接管理的,它完全是在UniversalClassLoader類和src/autoload.php文件的幫助下獨立完成的。

HttpFoundation 組件
  最深層次的是HttpFoundation組件,它提供了處理HTTP所需的主要對象。是一個對一些PHP函數和變量的面向對象抽象。
包括:
  Request 類,抽象了PHP中主要的全局變量$_GET,$_POST,$_COOKIE,$_FILES 和 $_SERVER。
  Response類,抽象類一些PHP函數比如header(), setcookie()和echo();
  Session 類和SessionStorageInterface接口則是抽象了Session管理Session_*()函數。

 

HttpKernel 組件:
  在HttpFoundation組件之上創建的一個組件,它處理HTTP的動態部分。它是為了能夠通過標准的方式來處理request,而對Request和Response對象的一個最小封裝。同時它提供了一些擴展點和工具,讓它成為創建一個web框架的最理想的開始點。

  另外,Dependency Injection組件和強大的插件系統bundles讓它增加了可配置性和擴展性。

 

FrameworkBundle Bundle
  FrameworkBundle bundle 是一個bundle,它是構成輕量級快速MVC框架的主要組件和類庫。

 

Kernel
  HttpKernel類是Symfony2的中心類,它負責處理客戶端請求。它的主要任務就是把Request對象轉換成Response對象。每個Symfony2核心實現HttpKernelInterface接口。

function handle(Request $request,$type=self::MASTER_REQUEST,$catch=true)

 


Controller
  Kernel依靠Controller來吧Request轉換為Response。 Controller可以是任何有效的PHP調用。Kernel委托選擇哪個Controller應該被執行給一個ControllerResolverInterface接口的實現者。

public function getController(Request $request);
public function getArguments(Request $request,$controller);

  其中,getController()方法返回一個和給定的Request相對於的Controller(一個PHP調用)。ControllerResolver的默認實現是查找Request的一個_controller屬性,它的值是一個class::method 格式的字符串。比如Bundle\BlogBundle\PostController::indexAction 。默認的實現使用RouterListener來定義Request的屬性 _controller。getArguments()方法返回一個輸入參數數組來傳遞給Controller調用。默認實現會根據Request屬性自動的獲取這些輸入參數。

  從Request屬性中匹配Controller方法的輸入參數:Symfony2對於每一個方法的輸入參數都會是這從Request中查找其同名屬性,如果沒有定義,就會取該輸入參數的默認值。

// Symfony2 從Request屬性中查找 'id' 屬性(強制)
// 和一個'admin' 屬性 (可選)
public function showAction($id, $admin = true)
{
       // ...
}

處理請求:handle()方法需要一個Request參數並且永遠都必須返回一個Response。要轉換Request,handle()需要依靠一個分析器和一個事件通知順序鏈。
  1. 在處理任何事情之前,kernel.request事件將被通知 --如果一個監聽者返回了一個Response,那么它會直接跳至第8步。
  2. 分析器被調用來判斷哪個Controller將被執行。
  3. kernel.controller事件監聽器現在開始處理Controller調用(改變它,封裝它...)
  4. Kernel檢查Controller是否是一個合法可調用的PHP回調。
  5. 分析器被調用來決定傳遞給controller的參數
  6. Kernel調用Controller
  7. 如果Controller沒有返回Response對象,kernel.view事件監聽器會把Controller的返回值轉換成一個Response。
  8. kernel.response事件監聽器開始處理Response(內容和頭部);
  9. Response對象被返回。

  如果在這個過程中有一個異常被拋出,kernel.exception就會被通知,監聽器就把異常轉換為一個Response,之后kernel.response事件就會被通知,如果沒能轉換,該異常就會被拋出。

  如果你不想異常被捕獲,你可以通過傳遞一個false作為第三個參數到handle()方法,來關閉kernel.exception事件。

 

內部請求
  在處理一個主請求的任何時候,子請求都可以被處理。你可以傳遞一個請求類型到handle()方法,作為它的第二個參數。

HttpKernelInterface::MASTER_ReQUEST;
HttpKernelInterface::SUB_REQUEST

這些類型會根據需要傳遞給所有的事件和監聽器。


事件
  Kernel拋出的每一個事件都會是KernelEvent類的子類。這就意味着每個事件都可以訪問相同的基礎信息。
    getRequestType() 返回請求的類型(HttpKernelInterface::MASTER_REQUEST 或者 HttpKernelInterface::SUB_REQUEST;
    getKernel() 返回處理請求的Kernel
    getRequest() 返回一個當前被處理的請求

  getRequestType()方法允許監聽器知道請求的類型。比如,如果一個監聽器必須是主請求才能激活它,你可以把該代碼添加到你監聽器方法的開頭:

use Symfony\Component\HttpKernel\HttpKernelInterface;
if(HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()){
      //立刻返回
      return;
}

 

kernel.request 事件
事件類:GetResponseEvent

  該事件的目標是立刻返回一個Response對象或者創建一個在事件結束后Controller可以調用的變量。任何監聽器都可以通過event的setResponse()方法返回一個Response對象,當有Response對象被返回時,其它的監聽器就不能在被調用了。

  FrameworkBundle使用事件通過RouterListener來發布一個_controller 請求屬性。
  RequestListener 使用一個RouterInterface對象匹配Request,決定哪個Controller的名字會被存儲到_controller的請求屬性里。


kernel.controller 事件:
事件類: FilterControllerEvent

  FrameworkBundle不會使用該事件,但是該事件可以被作為一個修改要執行的controller的一個入口點。

use Symfony\Component\Httpkernel\Event\FilterControllerEvent;

public function onKernelController(FilterControllerEvent $event)
{
        $controller = $event->getController();
         //...

        // 此處controller可以被該換成任何PHP可回調函數
        $event->setController($controller);
}

 

 

kernel.view 事件
事件類:GetResponseForControllerResultEvent

  FrameworkBundle也不會使用該事件,但是它被用來實現一個視圖子系統。該事件只有當Controller不能返回一個Response對象時才被調用。它的目的就是把其他類型的返回值轉換成一個Response。

  Controller的返回值可以通過getControllerResult方法訪問:

use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpFoundation\Response;

public function onKernelView(GetResponseForControllerResultEvent $event)
{
        $val = $event->getControllerResult();
        $response = new Response();
        //通過返回值自定義化Response
        $event->setResponse($response);
}

 


kernel.response 事件
事件類:FilterResponseEvent

  該事件的目的是允許其它系統在Response對象被創建后對它進行修改或者替換。

public function onKernelResponse(FilterResponseEvent $event)
{
       $response = $event->getResponse();
       //修改Response對象
}

FrameworkBundle注冊了許多的監聽器:

        ProfilerListener 從當前請求中搜集數據
        WebDebugToolbarListener 注入Web 調試工具條
        ResponseListener 基於請求的格式來為Response設置Content-type
        EsiListener 當Response需要解析ESI標簽時,向其添加一個Surrogate-Control HTTP頭。

 

kernel.exception 事件:
事件類:GetResponseForExceptionEvent
     FrameworkBundle注冊一個ExceptionListener把請求定向到一個給定Contoller。這個事件的監聽器可以創建和設置一個Response對象,創建設置一個新的Exception對象或者什么都不做。

use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;

public function onKernelException(GetResponseForExceptionEvent $event)
{
        $exception = $event->getException();
        $response = new Response();
        // 基於捕獲的異常創建一個Response對象
        $event->setResponse($response);

        // 你可以創建一個新的異常代替原有的
        // $exception = new \Exception('Some special exception');
        // $event->setException($exception);
}

 

總結思考:我們了解了Symfony2內部的主要部件和一些主要的事件接口,我們可以在各個事件接口定義相應的監聽器處理,來對請求處理過程進行干預操作。

 

參考URL:http://symfony.com/doc/current/book/internals.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM