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