亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

Symfony2中文手冊 / 控制器

控制器

控制器是一個你創(chuàng)建的php函數(shù),它能夠獲取http請求信息并構建和返回一個http響應(作為Symfony的Response對象),Response可能是一個html頁面、xml文檔、一個序列化的json數(shù)組、圖像、重定向、404錯誤或者一些其他你能夠想像的??刂破靼四銘贸绦蛐枰秩卷撁娴娜魏芜壿?。

看一下symfony簡單的控制器。下面控制器將輸出 hello word

use Symfony\Component\HttpFoundation\Response; public function helloAction(){
    return new Response('Hello world!');}

控制器的目標都是相同的:創(chuàng)建并返回一個Response對象。在這個過程中,它可能會從請求中讀取信息,加載數(shù)據(jù)庫資源,發(fā)送郵件,在用戶session中設置信息。但是所有情況下,控制器將最終返回 Response 對象給客戶端。

沒有什么神奇的不用擔心還有別的要求!下面是一些常見的例子:

  • 控制器A準備了一個首頁上的Response對象。-

  • 控制器B從請求中讀取{slug}參數(shù),從數(shù)據(jù)庫中載入一條博文,并創(chuàng)建一個顯示該博文的Response對象。如果{slug}不能被數(shù)據(jù)庫中檢索到,那么控制器將創(chuàng)建并返回一個帶404狀態(tài)碼的Response對象。

  • 控制器C處理關于聯(lián)系人的表單提交。它從請求中讀取表單信息,將聯(lián)系人信息存入數(shù)據(jù)庫并發(fā)送包含聯(lián)系人信息的電子郵件給網(wǎng)站管理員。最后,它創(chuàng)建一個Response對象將用戶的瀏覽器重定向到聯(lián)系人表單的“感謝”頁面。

請求、控制器、響應的生命周期 ?

symfony處理的每一個請求都會有相同的生命周期??蚣軙撠煱押芏嘀貜偷娜蝿沼靡粋€控制器最終執(zhí)行,控制器執(zhí)行你自定義的應用代碼:

  1. 每個請求都被單個前端控制器(如app.php生產(chǎn)環(huán)境 或app_dev.php開發(fā)環(huán)境)文件處理,前端控制器負責引導框架;

  2. 前端控制器的唯一工作是去初始化Symfony引擎(調(diào)用Kernel)并傳入一個Request對象來讓它處理。

  3. Symfony核心要求路由器去檢查這個請求;

  4. 路由查看并匹配請求信息,并將其指向一個特定的路由,該路由決定調(diào)用哪個控制器;

  5. 執(zhí)行控制器,控制器中的代碼將創(chuàng)建并返回一個Response對象;

  6. HTTP頭和Response對象的內(nèi)容將發(fā)回客戶端。

創(chuàng)建控制器與創(chuàng)建頁面一樣方便,同時映射一個URI到該控制器。

1466410869_65826_51226_http-xkcd-request.png

雖然名稱相似,但前端控制器與我們在本章節(jié)所說的控制器是不同的,前端控制器是你web/目錄中的一個PHP小文件,所有的請求都直接經(jīng)過它。一個典型的應用程序?qū)⒂幸粋€用于生產(chǎn)的前端控制器(如app.php)和一個用于開發(fā)的前端控制器(如app_dev.php)。你可以永遠不需要去對前端控制器編輯、查看或者有所擔心。本章的“控制器類”用一種方便的方法組織各自的“controllers”,也被稱為actions,它們都在一個類里(如,updateAction(), deleteAction(), 等)。所以,在控制器類里一個控制器就是一個方法。它們會持有你創(chuàng)建的代碼,并返回Response響應對象。

一個簡單的控制器 ?

雖然一個控制器可以是任何的可被調(diào)用的PHP(函數(shù)、對象的方法或Closure),在Symfony,控制器通常是在控制器類中的一個方法,控制器也常被稱為action:

// src/AppBundle/Controller/HelloController.phpnamespace AppBundle\Controller; use Symfony\Component\HttpFoundation\Response; class HelloController{
    public function indexAction($name)
    {
        return new Response('<html><body>Hello '.$name.'!</body></html>');
    }}

這里面的控制器是indexAction方法,它隸屬于一個控制器類HelloController。

這個控制器非常的簡單:

  • 第2行:Symfony利用php命名空間函數(shù)去命名整個控制器類

  • 第4行:Symfony充分利用了PHP5.3的名稱空間的功能:use關鍵字導入Response類,是我們控制器必須返回的;

  • 第6行:類名是一個串聯(lián)的控制器類名稱(例如hello)加上Controller關鍵字。這是一個約定,為控制器提供一致性,并允許它們引用控制器名稱(例如hello)作為路由配置。

  • 第8行:在控制器類中的每個action都有著后綴Action,并且這個action名(index)被引用到路由配置文件中。在下一節(jié)中,我們將使用路由映射一個URI到該action,并展示如何將路由占位符({name})變成action的參數(shù)($name);

  • 第10行:控制器創(chuàng)建并返回一個Response對象。

將URI映射到控制器 ?

我們的新控制器返回一個簡單的HTML頁。為了能夠在指定的URI中渲染該控制器,我們需要為它創(chuàng)建一個路由。 我們將在路由章節(jié)中討論路由組件的細節(jié),但現(xiàn)在我們?yōu)槲覀兊目刂破鲃?chuàng)建一個簡單路由:

Annotations:// src/AppBundle/Controller/HelloController.phpnamespace AppBundle\Controller; use Symfony\Component\HttpFoundation\Response;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class HelloController{
    /**
     * @Route("/hello/{name}", name="hello")
     */
    public function indexAction($name)
    {
        return new Response('<html><body>Hello '.$name.'!</body></html>');
    }}
YAML:# app/config/routing.ymlhello:
    path:      /hello/{name}
    # uses a special syntax to point to the controller - see note below
    defaults:  { _controller: AppBundle:Hello:index }.
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/routing        http://symfony.com/schema/routing/routing-1.0.xsd">     <route id="hello" path="/hello/{name}">
        <!-- uses a special syntax to point to the controller - see note below -->
        <default key="_controller">AppBundle:Hello:index</default>
    </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\Route;use Symfony\Component\Routing\RouteCollection; $collection = new RouteCollection();$collection->add('hello', new Route('/hello/{name}', array(
    // uses a special syntax to point to the controller - see note below
    '_controller' => 'AppBundle:Hello:index',))); return $collection;

現(xiàn)在,你來到 /hello/ryan(例如,如果你使用內(nèi)置的web服務http://localhost:8000/hello/ryan),那么它就會執(zhí)行HelloController::indexAction()控制器,并且將ryan賦給$name變量。創(chuàng)建這樣一個頁面就能夠讓路由跟控制器做簡單的關聯(lián)。

簡單吧?

AppBundle:Hello:index控制器語法

如果你是使用YAML或者XML格式,你給你的控制器使用的一個特定快捷語法被稱為邏輯控制器名稱,例如AppBundle:Hello:index。更多關于控制器格式的信息,請閱讀路由器章節(jié)的: 控制器命名模式。

把路由參數(shù)傳入控制器 ?

我們現(xiàn)在已經(jīng)知道路由指向AppBundle中的HelloController::indexAction()方法。還有更有趣的就是控制器方法的參數(shù)傳遞:

// src/AppBundle/Controller/HelloController.php// ...use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; /**
 * @Route("/hello/{name}", name="hello")
 */public function indexAction($name){
    // ...}

控制器有個參數(shù)$name,對應所匹配路由的{name}參數(shù)(如果你訪問/hello/ryan, 在本例中是ryan)。實際上當執(zhí)行你的控制器時,Symfony在所匹配路由中匹配帶參數(shù)控制器中的每個參數(shù)。所以這個{name}值被傳入到$name。只需要確保占位符的名稱和參數(shù)名稱一樣就行。

以下是更有趣的例子,這里的控制器有兩個參數(shù):

Annotations:// src/AppBundle/Controller/HelloController.php// ... use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class HelloController{
    /**
     * @Route("/hello/{firstName}/{lastName}", name="hello")
     */
    public function indexAction($firstName, $lastName)
    {
        // ...
    }}
YAML:# app/config/routing.ymlhello:
    path:      /hello/{firstName}/{lastName}
    defaults:  { _controller: AppBundle:Hello:index }
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="http://symfony.com/schema/routing"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/routing        http://symfony.com/schema/routing/routing-1.0.xsd">     <route id="hello" path="/hello/{firstName}/{lastName}">
        <default key="_controller">AppBundle:Hello:index</default>
    </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\Route;use Symfony\Component\Routing\RouteCollection; $collection = new RouteCollection();$collection->add('hello', new Route('/hello/{firstName}/{lastName}', array(
    '_controller' => 'AppBundle:Hello:index',))); return $collection;

將路由參數(shù)映射到控制器參數(shù)是十分容易和靈活的。在你開發(fā)時請遵循以下思路:

1. 控制器參數(shù)的順序無關緊要

Symfony可以根據(jù)路由參數(shù)名匹配控制器方法參數(shù)。換句話說,它可以實現(xiàn)last_name參數(shù)與$last_name參數(shù)的匹配。控制器可以在隨意排列參數(shù)的情況下正常工作。

public function indexAction($lastName, $firstName){
    // ...}

2.控制器所需參數(shù)必須匹配路由參數(shù)

下面會拋出一個運行時異常(RuntimeException),因為在路由定義中沒有foo參數(shù):

public function indexAction($firstName, $lastName, $foo){
    // ...}

如果參數(shù)是可選的,那該多好。下面的例子不會拋出異常:

public function indexAction($firstName, $lastName, $foo = 'bar'){
    // ...}

3.不是所有的路由參數(shù)都需要在控制器上有響應參數(shù)的

如果,舉個例子,last_name對你控制器不是很重要的話,你可以完全忽略掉它:

public function indexAction($firstName){
    // ...}


你也可以從你的路由器傳入其他的參數(shù)到你的控制器參數(shù)。請看 如何從路由向控制器傳遞額外的信息


Controller基類 ?

出于方便的考慮,Symfony提供了一個可選的Controller基類。如果你繼承它,它不會改變你控制器的任何工作原理,而且你還能夠很容易的繼承一些幫助方法和服務容器(可看,下面的訪問其他容器):允許你在系統(tǒng)中訪問每一個有用的對象,類似一個數(shù)組對象一樣。這些有用的對象被稱為服務,并且symfony附帶這些服務對象,可以渲染模板,還可以記錄日志信息等。

在頂部使用use語句添加Controller類,然后修改HelloController去繼承它。如下所示:

// src/AppBundle/Controller/HelloController.phpnamespace AppBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class HelloController extends Controller{
    // ...}

而無論你是否使用Controller基類,這些幫助方法只是讓你可以方便地使用Symfony的核心功能。其實查看核心功能的最好方式就是看Controller類本身。

如果你想了解沒有繼承controller基類控制器是如何運作的,可以查看 如何把控制器定義為服務。這是可選的,但它可以讓你精確控制的更多的“對象/依賴項",注入到你的控制器。

生成URL ?

generateUrl()能夠生成一個URL給路由器的輔助方法。

重定向 ?

如果你想將用戶重定向到另一個頁面,請使用 redirectToRoute() 方法:

public function indexAction(){
    return $this->redirectToRoute('homepage');     // redirectToRoute is equivalent to using redirect() and generateUrl() together:
    // return $this->redirect($this->generateUrl('homepage'));}

默認情況下,redirectToRoute()方法執(zhí)行302(臨時)重定向。如果要執(zhí)行301(永久)重定向,請修改第2個參數(shù):

public function indexAction(){
    return $this->redirectToRoute('homepage', array(), 301);}

從定向到外部網(wǎng)站,使用redirect()并傳入外部URL:

public function indexAction(){
    return $this->redirect('http://symfony.com/doc');}

更多細節(jié),請參考框架起步之路由

比創(chuàng)建一個專門從事重定向用戶的Response對象來說 redirectToRoute()方法是個簡單的捷徑,它相當于:

use Symfony\Component\HttpFoundation\RedirectResponse; 
public function indexAction()
{
    return new RedirectResponse($this->generateUrl('homepage'));
    }

渲染模板 ?

如果你使用HTML,你應該想要去渲染一個模板。render()方法可以用來渲染模板并可以把輸出的內(nèi)容放到你的Response 對象:

// renders app/Resources/views/hello/index.html.twig
return $this->render('hello/index.html.twig', array('name' => $name));

模板也可以防止在更深層次的子目錄。但應該避免創(chuàng)建不必要的深層結(jié)構:

// renders app/Resources/views/hello/greetings/index.html.twigreturn $this->render('hello/greetings/index.html.twig', array(
    'name' => $name));

模板可以在任何格式的文件中以一種通用的方式去渲染內(nèi)容。雖然在大多數(shù)情況下,你使用模板來渲染HTML內(nèi)容,模板也可以很容易地生成JavaScript,CSS,XML或者你能想到的任何其他格式。要了解如何使不同的模板格式,參考創(chuàng)建并使用模板中的“模板格式”。

模板的命名模式

你也可以把模板放在一個bundle的Resources/views目錄下并引用它們的特殊快捷語法,例如@App/Hello/index.html.twig 或者 @App/layout.html.twig。這些將分別存放在bundle的Resources/views/Hello/index.html.twigResources/views/layout.html.twig

訪問其他服務 ?

Symfony塞了很多有用對象,成為服務。這些服務用于呈現(xiàn)模板,發(fā)送電子郵件,查詢數(shù)據(jù)庫,以及你能夠想到的任何其他的”工作“。當你安裝一個新的bundle,它也可能會帶來更多的服務。

當繼承controller基類后,你可以通過get()方法訪問任何Symfony的服務。下面列舉了一些常見服務:

$templating = $this->get('templating'); 
$router = $this->get('router'); 
$mailer = $this->get('mailer');

到底存在哪些服務?我想要看所有的服務,請使用debug:container命令行查看:

$ php bin/console debug:container

更多信息請看 服務容器

管理錯誤和404頁面 ?

如果有些動作沒找到,將返回一個404響應。為此,你需要拋出一個異常。如果你繼承了基礎的Controller類,你可以執(zhí)行以下操作:

public function indexAction(){
    // retrieve the object from database
    $product = ...;
    if (!$product) {
        throw $this->createNotFoundException('The product does not exist');
    }     return $this->render(...);}

createNotFoundException() 方法創(chuàng)建了一個特殊的NotFoundHttpException對象,來觸發(fā)symfony內(nèi)部的http的404響應。

當然,你也可以自由地拋出你控制器中的任何Exception類,Symfony將自動返回HTTP響應代碼500。

throw new \Exception('Something went wrong!');

在每個示例中,一個帶格式的錯誤頁被顯示給最終用戶,而一個全是錯誤的調(diào)試頁會被顯示給開發(fā)者(當在調(diào)試模式app_dev.php查看該頁時 - 可查看 配置Symfony(和環(huán)境))。

這些錯誤頁都是可以自定義的。要想知道更多請閱讀“如何自定義錯誤頁”。

Request對象作為一個控制器參數(shù) ?

如果你需要獲取查詢參數(shù),抓取請求頭或者獲得一個上傳文件?這些信息都存儲在Symfony的Request對象。在你的控制器里獲取它們,只需要添加Request對象作為一個參數(shù)并強制類型為Request類:

use Symfony\Component\HttpFoundation\Request;
public function indexAction($firstName, $lastName, Request $request){
$page = $request->query->get('page', 1);     // ...}

管理Session ?

Symfony提供了一個好用的Session對象,它能夠存儲有關用戶的信息(它可以是使用瀏覽器的人、bot或Web服務)之間的請求。默認情況下,Symfony通過使用PHP的原生Session來保存cookie中的屬性。

去獲取這個session,需要調(diào)用Request 對象的getSession()方法。這個方法會返回一個SessionInterface,它用最簡單的方法來存儲和抓取session的數(shù)據(jù):

use Symfony\Component\HttpFoundation\Request; public function indexAction(Request $request){
    $session = $request->getSession();     // store an attribute for reuse during a later user request
    $session->set('foo', 'bar');     // get the attribute set by another controller in another request
    $foobar = $session->get('foobar');     // use a default value if the attribute doesn't exist
    $filters = $session->get('filters', array());}

這些屬性將會在該用戶session的有效期內(nèi)保留。

Flash Message ?

你也可以在用戶session中存儲一些指定的消息,這個消息被稱為“flash message”(消息條子)。證據(jù)規(guī)定,flash消息只能夠使用一次:當你取回它們的時候它們會自動的消失。這種特性使得“flash”消息特別適合存儲用戶通知。

讓我們看看我們處理表單提交的示例:

use Symfony\Component\HttpFoundation\Request; public function updateAction(Request $request){
    $form = $this->createForm(...);     $form->handleRequest($request);     if ($form->isValid()) {
        // do some sort of processing         $this->addFlash(
            'notice',
            'Your changes were saved!'
        );         // $this->addFlash is equivalent to $this->get('session')->getFlashBag()->add         return $this->redirectToRoute(...);
    }     return $this->render(...);}

在處理請求之后,控制器設置了一個名為notice的flash消息,然后重定向。名稱(notice)并不重要 – 它就是一個確定消息的識別符。

接下來是模板(或者是更好的,在你的基礎布局模板),從session中讀取每一條信息:

XML:{% for flash_message in app.session.flashBag.get('notice') %}    <div class="flash-notice">
        {{ flash_message }}    </div>{% endfor %}
PHP:<?php foreach ($view['session']->getFlash('notice') as $message): ?>
    <div class="flash-notice">        <?php echo "<div class='flash-error'>$message</div>" ?>
    </div><?php endforeach ?>

通常使用的noticewarningerror作為不同類型提示信息的鍵,但是你可以使用任何你需要的鍵。

你可以使用peek()方法來獲取消息,它可以讓消息保存住.

請求和響應對象 ?

正如前面所提到的,框架的Request 對象會作為控制器的參數(shù)傳入并強制指定數(shù)據(jù)類型為Request 類:

use Symfony\Component\HttpFoundation\Request; public function indexAction(Request $request){
    $request->isXmlHttpRequest(); // is it an Ajax request?     $request->getPreferredLanguage(array('en', 'fr'));     // retrieve GET and POST variables respectively
    $request->query->get('page');
    $request->request->get('page');     // retrieve SERVER variables
    $request->server->get('HTTP_HOST');     // retrieves an instance of UploadedFile identified by foo
    $request->files->get('foo');     // retrieve a COOKIE value
    $request->cookies->get('PHPSESSID');     // retrieve an HTTP request header, with normalized, lowercase keys
    $request->headers->get('host');
    $request->headers->get('content_type');}

這個Request類有一些公共的屬性和方法,它們能夠返回任何你需要的請求信息。

Request一樣,Response對象也有一個公共的headers屬性。它是一個ResponseHeaderBag它有一些不錯的方法來getting和setting響應頭。頭名稱的規(guī)范化使得 Content-Type等于content-type甚至等于content_type,它們都是相同的。

對于控制器,唯一的要求就是返回一個Response對象。Response類是一個PHP對于HTTP響應的一個抽象,一個基于文本的消息填充HTTP頭,其內(nèi)容發(fā)返客戶端:

use Symfony\Component\HttpFoundation\Response; 
// create a simple Response with a 200 status code (the default)$response = new Response('Hello '.$name, Response::HTTP_OK); 
// create a CSS-response with a 200 status code
$response = new Response('<style> ... </style>');
$response->headers->set('Content-Type', 'text/css');

也有一些特殊的類能夠簡化某種響應:

  • 對于JSON:這是一個JosnResponse??刹榭?創(chuàng)建一個JOSN響應。

  • 對于文件操作:這是 BinaryFileResponse??刹榭?Serving Files。

  • 對于流響應,有StreamedResponse。請看:流化一個響應

JSON Helper ?

3.1json() helper從symfony3.1開始被引入。

返回JSON類型在基于API的應用程序中是日益流行的。出于這個原因,控制器基類定義了json()方法,來創(chuàng)建一個JsonResponse 并自動編碼給定的內(nèi)容:

// ...public function indexAction(){
// returns '{"username":"jane.doe"}' and sets the proper Content-Type header
return $this->json(array('username' => 'jane.doe'));    
// the shortcut defines three optional arguments
// return $this->json($data, $status = 200, $headers = array(), $context = array());}

如果Serializer服務在你的應用程序中啟用,那么內(nèi)容傳遞到json()就會自動編碼。否則,你將要使用json_encode函數(shù)。

你現(xiàn)在已經(jīng)了解了Symfony RequestResponse 對象的基礎,你還可以參考HttpFoundation組件以了解更多。

創(chuàng)建靜態(tài)頁面 ?

你可以在沒有控制器的情況下創(chuàng)建一個靜態(tài)頁面(只需要一個路由和模板)。參考 不使用自定義控制器時如何渲染模板。

總結(jié) ?

當你創(chuàng)建了一個頁面,你需要在頁面中寫一些業(yè)務邏輯的代碼。在symfony中,這些就是控制器,它是一個能夠做任何事情的php函數(shù),目的是把最終的Response對象返回給用戶。

而且你能夠繼承Controller基類,使工作變得輕松。例如,你不用把html代碼寫到控制器,您可以使用render()來渲染模板,并返回模板的內(nèi)容。

在其他章節(jié)中,你會看到控制器是如何使用從數(shù)據(jù)庫中讀取對象和進行持久化的,處理表單提交,操作緩存以及更多。

Keep Going ?

接下來,集中學習使用Twig渲染模板。