創(chuàng)建你的第一個Symfony頁面
創(chuàng)建一個新頁面 - 無論是HTML還是JSON輸出 - 都是一個簡單的“兩步”操作:
創(chuàng)建一個路由:路由(route)是一個指向你的頁面URL(比如
/about
),同時映射到一個控制器。創(chuàng)建一個控制器:控制器(controller)是你為了構(gòu)造頁面而寫的功能。你要拿到發(fā)送來的請求請求信息,用它創(chuàng)建一個Symfony的
Response
對象,令其包含HTML內(nèi)容,JSON字符串或是其他
如同在網(wǎng)上每一次互動都是從HTTP請求開始,你的任務單純而簡單:理解請求,返回回復。
創(chuàng)建一個頁面:路由和控制器 ?
在開始之前,確保你已經(jīng)閱讀了安裝和配置Symfony章節(jié),同時已經(jīng)可以訪問瀏覽器中的Symfony程序。
假設(shè)你要新建一個/lucky/number
頁面,用于生成一個隨機的幸運數(shù)字并且輸出它。那么,要先創(chuàng)建一個類并添加方法,用于在某人訪問/lucky/number
時被執(zhí)行:
// src/AppBundle/Controller/LuckyController.phpnamespace AppBundle\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Symfony\Component\HttpFoundation\Response; class LuckyController{ /** * @Route("/lucky/number") */ public function numberAction() { $number = rand(0, 100); return new Response( '<html><body>Lucky number: '.$number.'</body></html>' ); }}
在開始之前測試一下
http:// localhost:8000 / lucky / number
如果你在Apache或Nginx上正確設(shè)置了虛擬主機,就可以把http://localhost:8000
部分替換為你自己的主機名,比如http://symfony.dev/app_dev.php/lucky/number
。
如果你看到一個幸運數(shù)字被輸出,那么恭喜!不過在玩轉(zhuǎn)樂透之前,先要了解它是如何工作的。
numberAction
上面的@Route
被稱為注釋,它定義了URL匹配。你也可以在YAML(或其他格式)里寫路由:請參考路由章節(jié)。實際上,文檔中的多數(shù)路由例程都有“標簽”,以顯示每種格式的配置
注釋下面的方法 - numberAction
- 被稱為控制器,這是你控制頁面的地方。這個唯一的原則是:一個控制器必須返回一個Symfony的響應對象(你最終將學習到活用這個原則)。
創(chuàng)建一個JSON響應 ?
在控制器中返回的Response
對象可以包含HTML,JSON甚至二進制文件比如圖片或PDF。你可以輕松設(shè)置HTTP頭信息或HTTP狀態(tài)碼。
假設(shè)你要創(chuàng)建一個JSON返回值,則只需要LuckyController
再添加一個方法:
// src/AppBundle/Controller/LuckyController.php // ...class LuckyController{ // ... /** * @Route("/api/lucky/number") */ public function apiNumberAction() { $data = array( 'lucky_number' => rand(0, 100), ); return new Response( json_encode($data), 200, array('Content-Type' => 'application/json') ); }}
在瀏覽器中測一下
http:// localhost:8000 / api / lucky / number
你更可將代碼精簡為超好用的JsonResponse
:
// src/AppBundle/Controller/LuckyController.php // ...// --> don't forget this new use statement 別忘了這行新的use聲明use Symfony\Component\HttpFoundation\JsonResponse; class LuckyController{ // ... /** * @Route("/api/lucky/number") */ public function apiNumberAction() { $data = array( 'lucky_number' => rand(0, 100), ); // calls json_encode and sets the Content-Type header // 自動調(diào)用json_encode并設(shè)置Content-Type頭 return new JsonResponse($data); }}
動態(tài)URL匹配:/ lucky / number / {count} ?
窩,你做得不錯但Symfony的路由還可以做得更多假設(shè)你希望用戶可以到!/lucky/number/5
來立即生成幸運數(shù)字5,更新路由,在使其擁有尾部一個{wildcard}
通配符:
注釋:// src/AppBundle/Controller/LuckyController.php // ...class LuckyController{ /** * @Route("/lucky/number/{count}") */ public function numberAction() { // ... } // ...}
YAML:# app/config/routing.ymllucky_number: path: /lucky/number/{count} defaults: { _controller: AppBundle:Lucky:number }
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="lucky_number" path="/lucky/number/{count}"> <default key="_controller">AppBundle:Lucky:number</default> </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\RouteCollection;use Symfony\Component\Routing\Route; $collection = new RouteCollection();$collection->add('lucky_number', new Route('/lucky/number/{count}', array( '_controller' => 'AppBundle:Lucky:number',))); return $collection;
因為{count}
占位符,頁面URL變得不一樣了。現(xiàn)在它要求URL匹配/lucky/number/*
,比如/lucky/number/5
。這樣一來你可以在控制器中收到并使用這個值:
// src/AppBundle/Controller/LuckyController.php// ... class LuckyController{ /** * @Route("/lucky/number/{count}") */ public function numberAction($count) { $numbers = array(); for ($i = 0; $i < $count; $i++) { $numbers[] = rand(0, 100); } $numbersList = implode(', ', $numbers); return new Response( '<html><body>Lucky numbers: '.$numbersList.'</body></html>' ); } // ...}
去/lucky/number/xx
測試一下,把xx換為任意數(shù)字:
http:// localhost:8000 / api / lucky / number / 7
你應該看到幸運數(shù)字7被輸出!在控制器中增加一個$placeholder
參數(shù),你就可以得到路由中任何一個{placeholder}
占位符的值只要確保它們的名字相同即可。
系統(tǒng)-路由還可以做更多,像是支持多個占位符(比如/blog/{category}/{page}
),令占位符可選以及強制占位符匹配一個正則表達式(比如{count}
必須為數(shù)字)。
在路線章節(jié)尋找更多,即可成為路由專家。
渲染模板(利用容器) ?
如果你在控制器中返回HTML,你可能需要渲染模板。幸運的是,Symfony擁有Twig:一種易學的模板語言,強大卻相當有趣。
目前,LuckyController
沒有繼承任何基類。此時引用Twig(或其他Symfony工具)最簡單的方式,就是繼承Symfony的Controller
基類:
// src/AppBundle/Controller/LuckyController.php // ... // --> add this new use statement use Symfony\Bundle\FrameworkBundle\Controller\Controller; class LuckyController extends Controller { // ...}
使用模板服務 ?
這些并不改變?nèi)魏螙|西,但是把你帶入Symfony的容器/容器:這是一個數(shù)組模樣的對象,允許你從中取出系統(tǒng)級的每一個有用對象這些有用的對象被稱為服務(服務) ,其中Symfony送出了一個專門用于渲染模板的服務對象,還有一個用來記錄日志的,以及許多許多。
渲染Twig模板,要求到的服務名為templating
:
// src/AppBundle/Controller/LuckyController.php // ...class LuckyController extends Controller{ /** * @Route("/lucky/number/{count}") */ public function numberAction($count) { // ... $numbersList = implode(', ', $numbers); $html = $this->container->get('templating')->render( 'lucky/number.html.twig', array('luckyNumberList' => $numbersList) ); return new Response($html); } // ...}
“服務容器”十分重要,學習過程中你會掌握大量相關(guān)知識。現(xiàn)在,你只需了解它擁有很多對象,然后你可以通過“昵稱”(比如templating
或logger
)利用get()
來得到其中的任何一個。templating
服務,是TwigEngine
的實例,里面有個render()
方法。
但是還可以再簡單些!通過繼承Controller
基類,你可以使用很多快捷方法,比如render()
:
// src/AppBundle/Controller/LuckyController.php // .../** * @Route("/lucky/number/{count}") */public function numberAction($count){ // ... /* $html = $this->container->get('templating')->render( 'lucky/number.html.twig', array('luckyNumberList' => $numbersList) ); return new Response($html); */ // render: a shortcut that does the same as above 快捷方法 return $this->render( 'lucky/number.html.twig', array('luckyNumberList' => $numbersList) ); }
關(guān)于控制器中的快捷方法是如何運作的請參閱控制器章節(jié)。
高級用戶請參考如何將控制器定義為服務。
創(chuàng)建模板 ?
如果你現(xiàn)在刷新頁面,會得到一個報錯:
無法找到模板“l(fā)ucky / number.html.twig”
修復它要靠創(chuàng)建一個新的app/Resources/views/lucky
目錄,再將number.html.twig
置于其中:
枝條:{# app/Resources/views/lucky/number.html.twig #} {% extends 'base.html.twig' %} {% block body %} <h1>Lucky Numbers: {{ luckyNumberList }}</h1> {% endblock %}
PHP:<!-- app/Resources/views/lucky/number.html.php --> <?php $view->extend('base.html.php') ?> <?php $view['slots']->start('body') ?> <h1>Lucky Numbers: <?php echo $view->escape($luckyNumberList) ?> <?php $view['slots']->stop() ?>
Twig歡迎你!這個簡單的文件已經(jīng)展示了基本功能:像是{{ variableName }}
語法被用于打印一些東西。而luckyNumberList
這個變量是你在控制器中的render()
方法中將其傳遞進來。
% extends 'base.html.twig' %
對應的是一個布局文件,它們位于app / Resources / views / base.html.twig,這個文件隨Symfony項目的建立而存在。它相當?shù)?/span>單純(只是一個未經(jīng)樣式處理的HTML結(jié)構(gòu)),供你定制。{% block body %}
部分則是使用了嫩枝模板的繼承系統(tǒng)/繼承系統(tǒng),將來的其間置于內(nèi)容父模板base.html.twig
布局中的相應位置。
立即刷新頁面
http:// localhost:8000 / lucky / number / 9
如果你查看頁面源代碼,你會看到完整的HTML骨架,多虧了base.html.twig
。
這只是Twig威力的極小部分。若你希望精通Twig的語法,數(shù)組循環(huán),輸出其他模板乃至更多超酷功能,應該參閱創(chuàng)建并使用模板。
瀏覽整個項目 ?
你已經(jīng)創(chuàng)建了一個彈性的URL,渲染了一個“使用了繼承功能”的模板,并且輸出了JSON響應。
是時候瀏覽你的項目中的文件并且去掉它們的神秘光環(huán)了。之前你已經(jīng)在兩個極為重要的文件夾中進行作業(yè):
app/
內(nèi)容配置文件和模板。大體上,只要不是 PHP代碼的材料都放在這里。
src/
你的PHP程序之所在99%的時間你都會工作在src/
(PHP文件)或app/
(其他東東)之下。隨著你的技術(shù)實力高大上起來,你會學習到每個文件夾下都發(fā)生了什么。
app/
目錄也存在其他內(nèi)容,app/AppKernel.php
像是,你要用它來開啟新捆綁(它是app/
下面很少的PHP文件之一)。
src/
目錄下暫時只有一個目錄 - src/AppBundle
- 所有的東西都在這里面。一個包,像一個“插件”,你可以找到開源捆綁,然后把它們安裝到你的項目中,但就算是你自己的代碼,也是處理束之中 - 典型的就是AppBundle(盡管這捆毫無特殊之處)。為了深入了解捆綁,以及為何你應該創(chuàng)建多個捆綁(提示:在項目之間共享代碼),請參閱Bundle系統(tǒng)章節(jié)。
那么項目中的其他文件夾又是什么情況呢?
web/
它是整個項目的文檔根目錄,存在可公開訪問的文件,比如CSS,圖片以及用于執(zhí)行應用程序(app_dev.php
和app.php
)的Symfony的前端控制器(前端控制器)。
tests/
你程序的自動測試(如單元測試/單元測試)被存放在這里。
bin/
用于存放二進制(binary)文件。最重要的是console
文件,它被用于控制中執(zhí)行Symfony命令。
var/
這是那些自動生成的文件被存放的地方,比如緩存文件(var/cache/
)和日志文件(var/logs/
)。
vendor/
通過依賴管理器Composer,第三方類庫,包,bundles被下載到這里。你應該不去編輯這個目錄下的東西。
Symfony是彈性化的。如果需要,你可以覆寫默認的目錄結(jié)構(gòu)。參考如何覆蓋Symfony的默認目錄結(jié)構(gòu)。
程序級別的配置 ?
Symfony內(nèi)置了幾個原生束(打開你的app/AppKernel.php
文件查看),你可以安裝更多.bundles的主要配置文件是app/config/config.yml
:
YAML:# app/config/config.yml # ...framework: secret: '%secret%' router: resource: '%kernel.root_dir%/config/routing.yml' # ...twig: debug: '%kernel.debug%' strict_variables: '%kernel.debug%' # ...
XML:<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:framework="http://symfony.com/schema/dic/symfony" xmlns:twig="http://symfony.com/schema/dic/twig" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd http://symfony.com/schema/dic/twig http://symfony.com/schema/dic/twig/twig-1.0.xsd"> <!-- ... --> <framework:config secret="%secret%"> <framework:router resource="%kernel.root_dir%/config/routing.xml" /> <!-- ... --> </framework:config> <!-- Twig Configuration --> <twig:config debug="%kernel.debug%" strict-variables="%kernel.debug%" /> <!-- ... --></container>
PHP:// app/config/config.php// ... $container->loadFromExtension('framework', array( 'secret' => '%secret%', 'router' => array( 'resource' => '%kernel.root_dir%/config/routing.php', ), // ...)); // Twig Configuration$container->loadFromExtension('twig', array( 'debug' => '%kernel.debug%', 'strict_variables' => '%kernel.debug%',)); // ...
framework
根鍵配置的是FrameworkBundle,twig
根鍵配置的是TwigBundle,諸如此類.Symfony中的許多行為都可以被控制,只需改變配置文件的一些選項即可。要搞清原因,請閱讀配置參考。
或者,通過超好用的bin/console
命令,取得一個根鍵下被剝離出的完整配置樣板:
$ php bin/console config:dump-reference framework
Symfony配置系統(tǒng)的威力絕大,包括環(huán)境,導入和參數(shù)等。為了掌握所有這些,參考配置章節(jié)。
下一步? ?
恭喜你!你已經(jīng)開始掌握Symfony,并將學到以全新方式來打造美麗的,功能性的,快速的,可維護的程序。
好了,你還需要熟悉下面這些章節(jié),才能完成對基礎(chǔ)架構(gòu)的掌握:
控制器
路由
創(chuàng)建和使用模板
然后,在中文書,還要學習服務容器,表單系統(tǒng),使用Doctrine(如果你需要查詢數(shù)據(jù)庫的話)以及更多!
還有一本中文菜譜,打包了更加高深的“如何”文章以解決更多問題。
祝各位學得高興!