19 May 2014
Symfony2 VS Flat PHP [第2天]
为什么Symfony2比打开一个文件纯粹写PHP更好呢?
如果您从未使用过PHP框架,不熟悉MVC的理念,或者只是想知道所有围绕Symfony2中,这一章是给你的。Symfony2会让你开发得更快。
在本章中,你会用纯PHP一个简单的应用程序,然后重构它更有条理。你会穿越时间,看到后面为什么web开发已经发展了近几年的地方,现在是作出决定。截至去年底,你将看到如何Symfony2中可以从平凡的工作拯救你,让你收回你的代码控制。一个简单的博客作为例子来讲述本章节¶
在本章中,你将只使用PHP写一个博客应用程序。首先,创建一个显示已保存到数据库博客条目的单个页面,当然这个方式有点”quick and dirty”。:
That’s quick to write, fast to execute, and, as your app grows, impossible to maintain. There are several problems that need to be addressed:
No error-checking: What if the connection to the database fails? Poor organization: If the application grows, this single file will become increasingly unmaintainable. Where should you put code to handle a form submission? How can you validate data? Where should code go for sending emails? Difficult to reuse code: Since everything is in one file, there’s no way to reuse any part of the application for other “pages” of the blog.
Tips:
Another problem not mentioned here is the fact that the database is tied to MySQL. Though not covered here, Symfony2 fully integrates Doctrine, a library dedicated to database abstraction and mapping.
Isolating the Presentation¶
The code can immediately gain from separating the application “logic” from the code that prepares the HTML “presentation”:
这是快写,快执行,而且,正如你的应用程序的增长,不可能维持。需要解决几个问题:
没有错误检查:如果有什么连接到数据库失败?组织不力:如果应用程序的增长,这种单一的文件将变得越来越难以维护。你应该在哪里把代码来处理表单提交?你怎么能验证数据?应该在哪里编写代码去发送电子邮件?很难重用代码:既然一切都在一个文件中,有没有办法再用任何部分申请了博客的其他“页”的。
温馨提示:
这里没有提到的另一个问题是,数据库连接到MySQL的。虽然这里没有涉及,Symfony2的完全集成 Doctrine,致力于数据库抽象和映射库。
隔离演示¶
该代码可以立即从该准备的HTML“简报”中的代码分离应用程序的“逻辑”获得:
The HTML code is now stored in a separate file (templates/list.php), which is primarily an HTML file that uses a template-like PHP syntax:
By convention, the file that contains all of the application logic - index.php - is known as a “controller”. The term controller is a word you’ll hear a lot, regardless of the language or framework you use. It refers simply to the area of your code that processes user input and prepares the response.
In this case, the controller prepares data from the database and then includes a template to present that data. With the controller isolated, you could easily change just the template file if you needed to render the blog entries in some other format (e.g. list.json.php for JSON format).
Isolating the Application (Domain) Logic¶
So far the application contains only one page. But what if a second page needed to use the same database connection, or even the same array of blog posts? Refactor the code so that the core behavior and data-access functions of the application are isolated in a new file called model.php:
Tips:
The filename model.php is used because the logic and data access of an application is traditionally known as the “model” layer. In a well-organized application, the majority of the code representing your “business logic” should live in the model (as opposed to living in a controller). And unlike in this example, only a portion (or none) of the model is actually concerned with accessing a database.
The controller (index.php) is now very simple:
Now, the sole task of the controller is to get data from the model layer of the application (the model) and to call a template to render that data. This is a very simple example of the model-view-controller pattern.
Isolating the Layout¶
At this point, the application has been refactored into three distinct pieces offering various advantages and the opportunity to reuse almost everything on different pages. The only part of the code that can’t be reused is the page layout. Fix that by creating a new layout.php file:
The template (templates/list.php) can now be simplified to “extend” the layout:
You’ve now introduced a methodology that allows for the reuse of the layout. Unfortunately, to accomplish this, you’re forced to use a few ugly PHP functions (ob_start(), ob_get_clean()) in the template. Symfony2 uses a Templating component that allows this to be accomplished cleanly and easily. You’ll see it in action shortly.
Adding a Blog “show” Page¶
The blog “list” page has now been refactored so that the code is better-organized and reusable. To prove it, add a blog “show” page, which displays an individual blog post identified by an id query parameter. To begin, create a new function in the model.php file that retrieves an individual blog result based on a given id:
Next, create a new file called show.php - the controller for this new page:
Finally, create the new template file - templates/show.php - to render the individual blog post:
Creating the second page is now very easy and no code is duplicated. Still, this page introduces even more lingering problems that a framework can solve for you. For example, a missing or invalid id query parameter will cause the page to crash. It would be better if this caused a 404 page to be rendered, but this can’t really be done easily yet. Worse, had you forgotten to clean the id parameter via the intval() function, your entire database would be at risk for an SQL injection attack.
Another major problem is that each individual controller file must include the model.php file. What if each controller file suddenly needed to include an additional file or perform some other global task (e.g. enforce security)? As it stands now, that code would need to be added to every controller file. If you forget to include something in one file, hopefully it doesn’t relate to security…
A “Front Controller” to the Rescue¶
The solution is to use a front controller: a single PHP file through which all requests are processed. With a front controller, the URIs for the application change slightly, but start to become more flexible:
Tips:
The index.php portion of the URI can be removed if using Apache rewrite rules (or equivalent). In that case, the resulting URI of the blog show page would be simply /show.
When using a front controller, a single PHP file (index.php in this case) renders every request. For the blog post show page, /index.php/show will actually execute the index.php file, which is now responsible for routing requests internally based on the full URI. As you’ll see, a front controller is a very powerful tool.
Creating the Front Controller¶
You’re about to take a big step with the application. With one file handling all requests, you can centralize things such as security handling, configuration loading, and routing. In this application, index.php must now be smart enough to render the blog post list page or the blog post show page based on the requested URI:
For organization, both controllers (formerly index.php and show.php) are now PHP functions and each has been moved into a separate file, controllers.php:
As a front controller, index.php has taken on an entirely new role, one that includes loading the core libraries and routing the application so that one of the two controllers (the list_action() and show_action() functions) is called. In reality, the front controller is beginning to look and act a lot like Symfony2’s mechanism for handling and routing requests.
Tips:
Another advantage of a front controller is flexible URLs. Notice that the URL to the blog post show page could be changed from /show to /read by changing code in only one location. Before, an entire file needed to be renamed. In Symfony2, URLs are even more flexible.
By now, the application has evolved from a single PHP file into a structure that is organized and allows for code reuse. You should be happier, but far from satisfied. For example, the “routing” system is fickle, and wouldn’t recognize that the list page (/index.php) should be accessible also via / (if Apache rewrite rules were added). Also, instead of developing the blog, a lot of time is being spent working on the “architecture” of the code (e.g. routing, calling controllers, templates, etc.). More time will need to be spent to handle form submissions, input validation, logging and security. Why should you have to reinvent solutions to all these routine problems?
Add a Touch of Symfony2¶
Symfony2 to the rescue. Before actually using Symfony2, you need to download it. This can be done by using Composer, which takes care of downloading the correct version and all its dependencies and provides an autoloader. An autoloader is a tool that makes it possible to start using PHP classes without explicitly including the file containing the class.
In your root directory, create a composer.json file with the following content:
Next, download Composer and then run the following command, which will download Symfony into a vendor/ directory:
Beside downloading your dependencies, Composer generates a vendor/autoload.php file, which takes care of autoloading for all the files in the Symfony Framework as well as the files mentioned in the autoload section of your composer.json.
Core to Symfony’s philosophy is the idea that an application’s main job is to interpret each request and return a response. To this end, Symfony2 provides both a Request and a Response class. These classes are object-oriented representations of the raw HTTP request being processed and the HTTP response being returned. Use them to improve the blog:
{New in version 2.4: Support for HTTP status code constants was introduced in Symfony 2.4.}
The controllers are now responsible for returning a Response object. To make this easier, you can add a new render_template() function, which, incidentally, acts quite a bit like the Symfony2 templating engine:
By bringing in a small part of Symfony2, the application is more flexible and reliable. The Request provides a dependable way to access information about the HTTP request. Specifically, the getPathInfo() method returns a cleaned URI (always returning /show and never /index.php/show). So, even if the user goes to /index.php/show, the application is intelligent enough to route the request through show_action().
The Response object gives flexibility when constructing the HTTP response, allowing HTTP headers and content to be added via an object-oriented interface. And while the responses in this application are simple, this flexibility will pay dividends as your application grows.
The Sample Application in Symfony2¶
The blog has come a long way, but it still contains a lot of code for such a simple application. Along the way, you’ve made a simple routing system and a method using ob_start() and ob_get_clean() to render templates. If, for some reason, you needed to continue building this “framework” from scratch, you could at least use Symfony’s standalone Routing and Templating components, which already solve these problems.
Instead of re-solving common problems, you can let Symfony2 take care of them for you. Here’s the same sample application, now built in Symfony2:
The two controllers are still lightweight. Each uses the Doctrine ORM library to retrieve objects from the database and the Templating component to render a template and return a Response object. The list template is now quite a bit simpler:
The layout is nearly identical:
Tips:The show template is left as an exercise, as it should be trivial to create based on the list template.
When Symfony2’s engine (called the Kernel) boots up, it needs a map so that it knows which controllers to execute based on the request information. A routing configuration map provides this information in a readable format:
Now that Symfony2 is handling all the mundane tasks, the front controller is dead simple. And since it does so little, you’ll never have to touch it once it’s created (and if you use a Symfony2 distribution, you won’t even need to create it!):
The front controller’s only job is to initialize Symfony2’s engine (Kernel) and pass it a Request object to handle. Symfony2’s core then uses the routing map to determine which controller to call. Just like before, the controller method is responsible for returning the final Response object. There’s really not much else to it. For a visual representation of how Symfony2 handles each request, see the request flow diagram.
Where Symfony2 Delivers¶
In the upcoming chapters, you’ll learn more about how each piece of Symfony works and the recommended organization of a project. For now, have a look at how migrating the blog from flat PHP to Symfony2 has improved life:
Your application now has clear and consistently organized code (though Symfony doesn’t force you into this). This promotes reusability and allows for new developers to be productive in your project more quickly;
100% of the code you write is for your application. You don’t need to develop or maintain low-level utilities such as autoloading, routing, or rendering controllers;
Symfony2 gives you access to open source tools such as Doctrine and the Templating, Security, Form, Validation and Translation components (to name a few);
The application now enjoys fully-flexible URLs thanks to the Routing component;
Symfony2’s HTTP-centric architecture gives you access to powerful tools such as HTTP caching powered by Symfony2’s internal HTTP cache or more powerful tools such as Varnish. This is covered in a later chapter all about caching.
And perhaps best of all, by using Symfony2, you now have access to a whole set of high-quality open source tools developed by the Symfony2 community! A good selection of Symfony2 community tools can be found on KnpBundles.com.
Better Templates¶
If you choose to use it, Symfony2 comes standard with a templating engine called Twig that makes templates faster to write and easier to read. It means that the sample application could contain even less code! Take, for example, the list template written in Twig
From:http://symfony.com/doc/current/book/from_flat_php_to_symfony2.html
Til next time,
Xujiajun
at 07:39