この記事では、Symfony2 でページを作成する方法について説明します。参考のために皆さんと共有してください。詳細は次のとおりです:
Symfony2 でページを作成するには 2 つのステップのみが必要です:
1. ルートを作成します: ルートはページの URI (/about など) を定義し、実行するコントローラー (PHP 関数) を指定します。受信リクエスト URL がこのルートと一致すると、Symfony2 は指定されたコントローラーを実行します
2. コントローラーを作成します: コントローラーは、受信リクエストを受け取り、それを Symfony2 Response オブジェクトに変換する PHP 関数です。
私たちは、このようなシンプルな実装がウェブの仕組みに適しているので気に入っています。すべての Web 対話は HTTP リクエストで始まり、リクエストを単純に解釈して、対応する HTTP レスポンスを返すのがアプリケーションの仕事です。 Symfony2 はこの原則に従い、ユーザーと複雑さが増大してもアプリケーションが適切に整理された状態を維持できるようにするツールを提供します。
「Hello Symfony2」ページ
古典的な「hello, world」プログラムから始めましょう。完了したら、ユーザーは次の URL にアクセスして挨拶を受け取ることができます。 リーリー
実際、このページを作成するには、2 つの簡単な手順に従うだけで、Symfony を挨拶用の別の名前に変更できます。このチュートリアルは、Symfony2 をダウンロードし、Web サーバーを設定していることを前提としています。上記の URL は、localhost が新しい Symfony2 プロジェクトを指していることを前提としています。インストールの詳細については、「Symfony2 のインストール」を参照してください。
バンドルを作成始める前に、バンドルを作成する必要があります。 Symfony2 では、Bundle はプラグインに相当し、アプリケーション内のすべてのコードは Bundle に配置する必要があります。バンドルは、その内容が特定の機能に関連する単なるディレクトリ (PHP 名前空間を持つ) です (バンドル システムを参照)。次のコマンドを実行して、AcmeStudyBundle (この章で構築されるゲーム) を作成します。
リーリー次に、Acme 名前空間が確実にブートストラップされるように、次のステートメントが app/autoloader.php ファイルに追加されました (「自動読み込み」の章を参照)。 リーリー
最後に、app/AppKernel.php ファイルの registerBundles() メソッドでバンドルを初期化します。リーリー
これでバンドルのセットアップが完了し、バンドル内にアプリケーションを構築できるようになりました。
ルートを作成する
デフォルトでは、Symfony2 のルーティング設定ファイルは app/config/routing.yml ディレクトリに配置されます。 Symfony2 のすべての設定ファイルは、PHP または XML 形式で記述することもできます。 リーリー
ルーティング構成ファイルの最初の数行は、ユーザーが「/」(ホームページ)リソースをリクエストしたときに呼び出されるコードを定義します。さらに興味深いのは、AcmeStudyBundle にある他のルーティング構成ファイルをインポートする最後の部分です。リーリー
ルートは 2 つの基本部分で構成されます。パターンはこのルートに一致する URI を決定し、デフォルトの配列は実行するコントローラーを指定します。 pattern のプレースホルダー {name} はワイルドカードで、/hello/Ryan、/hello/Fabien などの URI がこのルートに一致することを示します。 {name} プレースホルダー パラメーターもコントローラーに送信されるため、その値を使用してユーザーに挨拶できるようになります。ルーティング システムには、アプリケーションの強力かつ柔軟な URL 構造を作成するための多くの素晴らしい機能があります。詳細については、「Symfony2 学習ノート: システム ルーティングの詳細な説明」を参照してください。 コントローラーを作成する
/hello/Ryan のような URI がアプリケーションによって処理されると、hello ルートが照合され、AcmeStudyBundle:Hello:index コントローラーが Symfony2 フレームワークを通じて実行されます。ページ作成プロセスの 2 番目のステップは、このコントローラーを作成することです 実際、コントローラーはユーザーが作成し、Symfony2 を通じて実行される PHP 関数にすぎません。このカスタム アプリケーション コードは、リクエスト情報を使用して必要なリソースを構築および準備します。一部の高度なケースを除いて、コントローラーの最終出力は同じ Response オブジェクトです。
リーリーコントローラーは非常に単純で、最初のパラメーターが返す応答コンテンツ (この場合は小さな HTML ページ) である新しい Response オブジェクトを作成します。
おめでとうございます。ルートとコントローラーを作成した直後に、完全に機能するページが完成しました。設定に問題がなければ、アプリが次のように挨拶します:
リーリーオプションですがよく使用される手順は、テンプレートを作成することです。
コントローラーはページ作成時の主要なエントリおよび重要な部分であり、詳細についてはコントローラーの章を参照してください。
テンプレートを作成するテンプレートを使用すると、すべてのプレゼンテーション (HTML コードなど) を 1 つのファイルに入れて、ページ レイアウトのさまざまなセクションを再利用できます。次のコードは、テンプレートを使用してコントローラー内の HTML コードを置き換えます。 リーリー render() メソッドを使用するには、いくつかの一般的なタスクのショートカット メソッドを追加する Controller クラスを継承する必要があります。
render() メソッドは、特定のコンテンツが入力され、テンプレートを通じてレンダリングされる Response オブジェクトを作成します。他のコントローラーと同様に、最終的に得られるのは Response オブジェクトです。
注意,这里有两种不同渲染模板的例子,缺省情况下,Symfony2支持两种渲染模板的方式:传统的PHP模板和简洁强大的Twig模板。你可以随意选择使用其中的一种,也可以在同一项目中混用它们,这都不成问题。
控制器渲染AcmeStudyBundle:Hello:index.html.twig模板,该模板使用以下命名约定:
Bundle名:Controller名:Template名
在本例中,AcmeStudyBundle是Bundle名,Hello是控制器,index.html.twig是模板名。
{# src/Acme/StudyBundle/Resources/views/Hello/index.html.twig #} {% extends '::layout.html.twig' %} {% block body %} Hello {{ name }}! {% endblock %}
让我们一行行地来:
第2行:extends定义了一个父模板,模板明确定义了一个将被替换的布局文件;
第4行:block表示其中的内容将会替换掉名为body的block,如我们所知,它在最终渲染时将负责layout.html.twig中名为body的block的渲染。
父模板::layout.html.twig省略了它的bundle名和控制器名(所以用两个冒号::代替),这意味着该模板在bundle外面,在app目录中。
{# app/Resources/views/layout.html.twig #} <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>{% block title %}Hello Application{% endblock %}</title> </head> <body> {% block body %}{% endblock %} </body> </html>
基本模板文件定义了HTML布局,并用我们在index.html.twig模板中定义的名为body的区块渲染。这里还定义了一个名为title的区块,我们也可以选择在index.html.twig模板中定义。由于我们没有在子模板中定义title区块,所以它还是使用缺省值”Hello Application”。
模板在渲染和组织页面内容方面的功能非常强大,它可以是HTML标识语言、CSS代码或者控制器可能需要返回的东东。模板引擎只是达到目标的手段。每个控制器的目标是返回一个Response对象,模板虽然强大,但它却是可选的,它只是为Response对象创建内容的工具而已。
目录结构
经过前面几段的学习,你已经理解了在Symfony2中创建和渲染页面的步骤,也开始明白了Symfony2的组织和结构,在本章的最后,你将学会在哪儿找到和放置不同类型的文件以及为什么这样做。
虽然Symfony2的目录结构相当灵活,但在缺省状态下,Symfony2还是有着相同的、被推荐的基本目录结构:
app/ : 该目录包含应用程序配置;
src/ : 所有项目的PHP代码都保存在该目录下;
vendor/ : 根据约定放置所有供应商的库文件;
web/ : 这是web根目录,包括一些公众可以访问的文件。
WEB目录
web根目录是所有静态的、公共文件的家目录,包括图像、样式表和javascript文件,这里也是前端控制器所在的地方。
// web/app.php require_once __DIR__.'/../app/bootstrap.php'; require_once __DIR__.'/../app/AppKernel.php'; use Symfony\Component\HttpFoundation\Request; $kernel = new AppKernel('prod', false); $kernel->handle(Request::createFromGlobals())->send();
前端控制器(在这里是app.php)其实是一个PHP文件,在使用Symfony2应用程序时执行。它的功能就是使用内核类AppKernel,让应用程序自举。
使用前端控制器意味着要比使用传统的纯PHP程序有着更为灵活多变的URL,当使用前端控制器时,URL格式如下所示:
http://localhost/app.php/hello/Ryan
前端控制器app.php被执行,URI(/hello/Ryan)通过路由配置被内部路由。如果使用Apache的重写规则,你可以在不指定app.php的情况下强制执行它:
http://localhost/hello/Ryan
虽然前端控制器在处理请求时必不可少,但你很少会去修改甚至想到它,我们只是在环境一章中简要地提及它。
应用程序(app)目录
正如你在前端控制器所看到的那样,AppKernel类是整个应用程序的主入口,它负责所有的配置,它被保存在app/目录中。
这个类必须实现三个方法,这些方法是Symfony2需要让应用程序了解的。你甚至在一开始就无须担心这些方法,因为Symfony2会智能地为你填充它们:
1、registerBundles(): 返回所有需要在应用程序中运行的bundle数组 (参见Bundle系统 );
2、registerContainerConfiguration(): 引导应用程序的主配置资源文件 (参见应用程序配置章节);
3、registerRootDir(): 返回app根目录 (缺省是 app/)
在日常开发中,你会经常用到app/目录,你会在app/config/目录中修改配置和路由文件(参见应用程序配置),也会使用app/cache/目录做为应用程序的缓存目录、使用app/logs/目录做为日志目录、使用app/Resources/目录做为应用程序级别的资源目录。在下面的章节中你将会学到更多关于这些目录的内容。
自动加载
当应用程序自举时,将包含一个特殊的文件:app/autoload.php。该文件负责自动加载src/和vender/目录中的所有文件。
因为有自动加载器,你永远无须为使用include或require语句担心。Symfony2利用类的名称空间确定它的位置,并自动加载包含你所需的类文件。
$loader->registerNamespaces(array( 'Acme' => __DIR__.'/../src', // ... ));
在这个配置中,Symfony2将查找src/目录下Acme名称空间(假想公司的名称空间)的所有类。为了能够自动加载,Class Name文件和Path必须遵循同一模式:
Class Name:
Acme\StudyBundle\Controller\HelloController
Path:
src/Acme/StudyBundle/Controller/HelloController.php
app/autoload.php配置自动加载器在不同的目录查找不同的PHP名称空间,也可以在必要时自定义。有关自动加载器的更多情况,参见如何自动加载类。
源(src)目录
简而言之,src/目录包括所有在应用程序中运行的PHP代码。实际上在开发时,大部分工作都是在该目录下完成的。缺省情况下,src/目录是空的,当你开始进行开发时,你将开始填充bundle所在的目录,该目录包含你应用程序的代码。
然而bundle究竟是什么呢?
Bundle系统
Bundle与其它软件中的插件类似,但比它们更好。关键的不同点在于在Symfony2中什么都是bundle,包括框架的核心功能和你为应用程序所写的代码。在Symfony2中,Bundle是一类公民,这让使用第三方Bundle的预建功能包或发布你自己的Bundle变得十分灵活。它也可以使你很容易地选择应用程序所需功能,并用你自己的方式去优化它们。
Bundle简单来说就是在一个目录里用来实现单一功能的结构化文件集。你可以创建BlogBundle、ForumBundle或用户管理的Bundle(许多都已经以开源Bundle的形式存在)。每个目录都包含与功能相关的内容,如PHP文件、模板、样式表、Javascripts、测试等。每个Bundle都包含某种功能的方方面面,而每种功能都必须在Bundle中实现。
应用程序由在AppKernel类中的registerBundles()方法中定义的Bundle组成:
// app/AppKernel.php public function registerBundles() { $bundles = array( new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), new Symfony\Bundle\SecurityBundle\SecurityBundle(), new Symfony\Bundle\TwigBundle\TwigBundle(), new Symfony\Bundle\MonologBundle\MonologBundle(), new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), new Symfony\Bundle\DoctrineBundle\DoctrineBundle(), new Symfony\Bundle\AsseticBundle\AsseticBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(), // register your bundles new Acme\StudyBundle\AcmeStudyBundle(), ); if (in_array($this->getEnvironment(), array('dev', 'test'))) { $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); } return $bundles; }
通过registerBundles()方法,你就拥有了应用程序所有Bundles的全部控制权(包含Symfony2的核心Bundle)
无论Bundle在什么地方,它都可以被Symfony2自动加载。举个例子,如果AcmeStudyBundle放在src/Acme目录中,请确保Acme的名称空间被添加到app/autoload.php文件中,并映射到src/目录,这样它就可以被Symfony2自动加载了。
创建Bundle
为了向你展示Bundle系统是如何之简单,让我们创建一个名为AcmeTestBundle的新Bundle,并激活它。
首先,创建一个src/Acme/TestBundle/ 目录,并添加一个名为AcmeTestBundle.php的新文件:
// src/Acme/TestBundle/AcmeTestBundle.php namespace Acme\TestBundle; use Symfony\Component\HttpKernel\Bundle\Bundle; class AcmeTestBundle extends Bundle { }
AcmeTestBundle遵循Bundle命名约定
这个空类仅仅只是我们需要创建新Bundle的一部分。虽然是空的,但这个类已经足够强大,并能够用来自定义Bundle的行为。
现在我们已经创建了我们的Bundle,我们需要通过Appkernel类激活它:
// app/AppKernel.php public function registerBundles() { $bundles = array( // ... // register your bundles new Acme\TestBundle\AcmeTestBundle(), ); // ... return $bundles; }
虽然目前它还不能做任何事情,但AcmeTestBundle现在已经可以使用了。
同样方便的是,Symfony也提供命令行接口去生成Bundle的基本框架
php app/console init:bundle "Acme\TestBundle" src
生成的Bundle框架包括一个基本控制器、模板和可自定义的路由资源。接下来我们将会讨论更多的Symfony2命令行工具。
无论何时,创建一个新的Bundle或使用第三方Bundle,都是需要确保该Bundle在registerBundles()中被激活。
Bundle的目录结构
Bundle的目录结构是简单而灵活的。缺省状态下,Bundle系统遵循Symfony2所有Bundle之间保持代码一致性的约定集。让我们看看AcmeStudyoverBundle,因为它包含了Bundle的大多数元素:
1、Controller/目录:包含该Bundle的控制器(如:HelloController.php);
2、Resources/config/目录:配置目录,包括路由配置(如:routing.yml);
3、Resources/views/目录:通过控制器名组织的模板(如:Hello/index.html.twig);
4、Resources/public/目录:包含web资源(图片、样式表等),并被拷贝或软链接到项目的web/目录;
5、Tests/目录:存放该Bundle的所有测试。
根据Bundle实现的功能,它可小可大,它只包含你所需要的文件。
你在本书中还将学习到如何持久化对象到数据库、创建和验证表单、翻译你的应用程序和编写测试等等,它们在Bundle中都有自己的位置和所扮演的角色。
应用程序配置
应用程序由代表应用程序所有功能和特征的Bundle集构成。每个Bundle都可以通过YAML、XML或PHP编写的配置文件来自定义。缺省情况下,主配置文件放置在app/config/目录中,被命名为config.yml、config.xml或config.php,这取决于你所使用的格式:
# app/config/config.yml framework: charset: UTF-8 secret: xxxxxxxxxx form: true csrf_protection: true router: { resource: "%kernel.root_dir%/config/routing.yml" } validation: { annotations: true } templating: { engines: ['twig'] } #assets_version: SomeVersionScheme session: default_locale: en lifetime: 3600 auto_start: true # Twig Configuration twig: debug: %kernel.debug% strict_variables: %kernel.debug%
我们将在下一节环境中展示如何准确地选择要引导的文件/格式。
每一个顶级条目,如framework或twig都被配置成一个特定的Bundle。例如,framework被配置成Symfony2的核心FrameworkBundle,并包含路由、模板和其它核心系统的配置。
现在别担心配置文件中各段中的特定配置选项,配置文件缺省值都是合理的。当你浏览Symfony2的各部分时,你将学到每个部分的特定配置选项。
配置格式
纵观整个章节,所有的配置示例都用三种格式(YAML、XML和PHP)展示。它们每个都有自己的优缺点,以下是三种格式的说明:
1、YAML:简单、干净和易读
2、XML:有时比YAML更强大且支持IDE的自动完成
3、PHP:非常强大,但与标准配置格式相比易读性差
环境
应用程序可以在不同的环境中运行。不同的环境共享相同的PHP代码(由前端控制 器区分),但却有着完全不同的配置。开发环境记录警告和错误,而生产环境只记录错误。在开发环境中一些文件在每次请求之后被重构,而在生产环境中却被缓存 。所有的环境都在同一机制中生活。
虽然创建新的环境是容易的,但Symfony2项目通常会从三个环境开始(开发、测试和生产)。通过在你浏览器中改变前端控制器,你可以很方便地让应用程序在不同的环境中切换。要将应用程序切换到开发环境,只需要通过开发前端控制器去访问应用程序即可。
http://localhost/app_dev.php/hello/Ryan
如果你想看看你的应用程序在生产环境中的表现 ,可以调用生产前端控制器:
http://localhost/app.php/hello/Ryan
如果你打开 web/app.php文件,你将发现它已经很明确地被配置成使用生产环境:
$kernel = new AppCache(new AppKernel('prod', false));
你可以为一个新的环境创建一个新的前端控制器,只需要拷贝该文件,并将prod修改成其它值。
因为生产环境是为速度优化的,配置、路由和Twig模板都被编译成纯的PHP类,同时被缓存 。在生产环境中改变视图时,你需要清除这些缓存文件,从而让它们重构:
rm -rf app/cache/*
当进行自动测试时使用测试环境,它并不能从浏览器直接访问。参见测试章节以得到更多细节。
环境配置
AppKernel类负责加载你所选的配置文件:
// app/AppKernel.php public function registerContainerConfiguration(LoaderInterface $loader) { $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); }
我们已经知道.yml扩展名可以转换成.xml或.php,只要你喜欢使用XML或PHP来写配置。注意每种环境也可以加载它们自己的配置文件。下面是为生产环境准备的配置文件。
# app/config/config_dev.yml imports: - { resource: config.yml } framework: router: { resource: "%kernel.root_dir%/config/routing_dev.yml" } profiler: { only_exceptions: false } web_profiler: toolbar: true intercept_redirects: true zend: logger: priority: debug path: %kernel.logs_dir%/%kernel.environment%.log
import关键词与PHP格式中include语句一样,都是首先引导主配置文件(config.yml),文件的其它部分是为了增长的日志和其它有利于开发环境的设置而对缺省配置进行的调整。
在生产环境和测试环境都遵循同样一个模型:每个环境导入基本配置文件,然后修改它们的配置值去适应特殊环境的需要。
小结
恭喜你,你现在已经明白了Symfony2的基本原理,并惊喜地发现它是那样的方便灵活。尽管有许多的功能,但我们可以牢记以下几个基本点:
1、创建页面需要三个步骤,包括路由、控制器和模板(可选);
2、每个应用程序都应该包含四个目录:web/(web资源和前端控制器)、app/(配置)、src/(你的Bundle)和vendor/(第三方代码);
3、Symfony2的每个功能(包括Symfony2框架核心)都被组织进一个Bundle,Bundle是该功能的结构化文件集;
4、每个Bundle的配置都存放在app/config目录中,可以使用YAML、XML和PHP编写;
5、通过不同的前端控制器(如:app.php或app_dev.php)和配置文件,每种环境都可以被访问。
希望本文所述对大家基于Symfony框架的PHP程序设计有所帮助。