Building a Web App with Symfony 2: Bootstrapping

Taylor Ren
Share

Introduction

The Symfony PHP Framework is powerful, scalable and flexible. Yet it is considered by many, especially those new to frameworks, to have a very steep learning curve.

This is true to a certain extent. At first glance, Models, Views, Controllers, Entities, Repositories, Routing, Templating, etc, altogether can appear very terrifying and confusing.

However, if you have grasped the fundamentals of PHP and HTML, have a basic understanding of modern web site development (in particular, Pretty URIs, MVC), and know how to CRUD a database/table, you are not far from developing a fairly good website, be it for your personal usage or business application.

In this series, I will capture a few key steps and some advanced techniques (image manipulation, pagination, dynamic contents, NativeQuery, etc) to help anyone who is considering using Symfony (note, to avoid future confusion, Symfony here refers to the Symfony 2, not the obsolete Symfony 1) as their PHP framework to develop a website.

I will use my personal book collection site as the starting point. It is up and running, so the project I use here is not a demo but a real running site (hosted at http://www.rsywx.net, in pure Chinese).

The final source code of the site for this part of the tutorial can be found at the Github repository. Any comments and queries, please feel free to contact me.

Quick setup

Setting up Symfony is fairly easy. My favorite way is to download the Symfony Standard without vendors package. Visit the official download site and make sure you choose the right package. Unzip/Untar the archives to your planned web root directory and you are almost there (my project for this series will be located at f:\www\rsywx_test). After unzipping the Symfony package, you will see a directory structure not unlike this one:

Be sure the above directory is correct (you may not see the .hg directory as this is for version control only).

The next step is to download the PHP packaging system called Composer. Most modern PHP frameworks use Composer for package management.

If you have the cURL utility installed, you can issue the following command:

curl -S https://getcomposer.org/installer | php

or if not (but you really should install cURL), punch in the following:

php -r "eval('?>'.file_get_contents('https://getcomposer.org/installer'));"

There will be one new file downloaded, called composer.phar. This file is the entry point for our PHP package management.

As the name of the archive suggests, the files we have now contain no libraries (or bundles) to make Symfony really work. To do that, you need to run:

php composer.phar update

The above will install the latest and necessary bundles normally required. If you run into any errors (missing utilities, critical dependencies that cannot be met..) composer will kindly let you know. The installation procedure should be done within a couple minutes at most, depending on your connection speed.

If you have setup your web server (I am using Apache) correctly, you can visit the site already:

With Symfony, it is common practice to use app_dev.php as the entry page during development. In a production environment, app_dev.php would be omitted.

Feel free to navigate around to get a feeling of the framework and familiarize yourself with the toolbars and debug messages it offers.

Detailed setup instructions can be found here, in case you need more help.

It is always a good idea to run php composer.phar selfupdate periodically to get the latest composer.phar distribution.

Note: The Symfony package always has a built-in bundle called AcmeDemoBundle. That bundle is a demo app that proves Symfony is up and running, and serves as an example which you can use to build your own app. To remove that bundle out of your web site setup, please follow the instructions in this article.

After removing, if you visit the site again, you will see a 404 page (No route found for "GET /") as we have not started to create our own application yet.

Bundle, Controllers, Views, Models (Entities)

In short, Symfony relies on bundles (often called modules in other frameworks). A bundle can be treated as a collection of files – it serves as the container for data retrieving, logic control and presentation of a particular function set or sets in your website. My site has only one bundle and serves to list all of my books, the detail of one book, the articles I wrote after reading a book, my favorite NBA team (Lakers) scores, etc. These functions (or modules as they're counterintuitively called in Symfony) are all encapsulated in one bundle (trrsywxBundle).

A bundle will contain controllers, views and entity files (models). These constitute the foundation of an MVC-structured website.

To generate a bundle and start our application development, issue the below command:

php app/console generate:bundle

Before creating the bundle, the console will ask you several questions:

  • Bundle namespace: in this example, I am using tr\rsywxBundle. Be sure to have "Bundle" at the end.
  • Bundle name: use the suggested name derived from the namespace. In this case, "trrsywxBundle".
  • Target Directory: use the suggested lcoation ("F:/www/rsywx_test/src" in this case).
  • Configuration format: there are 4 options available: PHP, YAML, XML and annotation. Choose the one your prefer and feel comfortable with. If you'd like to follow along, I will use YAML, so type "yml" as your choice.
  • Do you want to generate the whole directory structure: Not necessary.
  • Confirm the generation, kernel update and Routing generation.

More detailed instructions about this process can be found here.

Routing

Consider routing as a mapping mechanism from the HTTP request to the module/function that really handles it (processing the request, grabbing data, and rendering the proper response back to the web browser).

Like most other frameworks, Symfony has a routing feature to support pretty URIs. This is done by creating routes in routing.yml (and by having the right .htaccess configuration, which is located in the web/ directory of your Symfony setup).

To make the encapsulation stronger, I do recommend you add your own routes in the bundle's routing.yml file (located under path-to-your-site-root/src/tr/rsywxBundle/Resources/config). This comes in handy when you eventually want to port the whole bundle into another site. Please note how the namespace of the bundle is reflected in the directory structure.

A common pitfall when defining routes is that routes have their precedence. The earlier a route appears, the earlier it will be matched. In other words, if the routes are not arranged properly, weird, difficult to debug problems will occur.

For example, in an earlier version of my site, I had two routes looking like this:

tag_list:
  pattern: /books/{tag}/{page}
  defaults: {_controller: trrsywxBundle:Book:taglist, page:1}   
...  
reading_list:
  pattern: /books/readings/{page}
  defaults: {_controller: trrsywxBundle:Reading:list, page:1}  

See the problem? /books/readings will actually be mapped to tag_list route, in which the parameter tag will take readings as its value and directs us to a totally different controller. I can't simply switch the order of these two routes (which would solve most of the issues, but crash when someone is really looking for books containing 'readings' as a tag). The only way to get around this is to change the route pattern for the first one:

tag_list:
  pattern: /books/tag/{page}/{tag}
  defaults: {_controller: trrsywxBundle:Book:taglist, page:1} 

Derived from the fact that the earlier a route appears, the earlier it is matched, you need to put the most frequently used routes at the beginning of the routing.yml file. This has the added benefit of being faster, since the framework has fewer routes to check before hitting a match.

I am not covering the whole aspect of routing in Symfony here. The official documentation says it all.

Database

In this project, the database used is relatively simple. A few tables are created to reflect the book information (title, author, publisher, purchase date, location, etc), my reading thoughts, the Lakers score, Quote Of The Day, etc. Most of the tables (books, readings, publisher, purchase place, etc) are related to each other with a One-To-Many relationship. The tags table and books table are linked with Many-To-Many relationships.

The rsywx.sql file in the project's misc folder will let you import the database (MariaDB or MySQL) – simply import it via the mysql command line tool, or through a web GUI like PhpMyAdmin. Though Symfony official documentation suggests databases/tables be created from within the Symfony framework, I strongly suggest using another 3rd party tool. The advantages of using a 3rd party tool include:

  • More intuitive and straightforward definition of the database;
  • Less typings when defining the data type, relationships, indexes, primary keys, etc.

We can now link up the database by configuring app/config/parameters.yml:

parameters:
  database_driver: pdo_mysql
  database_host: 127.0.0.1
  database_port: null
  database_name: symfony
  database_user: root
  database_password: null

Normally, you will only change the dabase name, user and password to reflect your own choices.

After creating the database/tables, it is easy to import these database structures into Symfony:

php app\console doctrine:mapping:import

And then create the corresponding entities by:

php app\console doctrines:generate:entity tr

(where tr is the namespace of the bundle).

Note: Symfony supports two ORMs for now: Doctrine and Propel. I am using Doctrine in this application.

In general, the import will succeed with next to no problems. However, there are at least two things to notice:

  • The tool is not good at mapping a table with a compound primary key (i.e., a primary key with 2 or more fields) in which at the same time, one of the fields is also a foreign key to another table
  • You can edit the generated entity files (located under path-to-your-site-root/src/tr/rsywxBundle/Entity/). But if you modified the field names, types and other information, be sure to "reflect" those changes back to the database via the php app/console doctrine:database:create command. Don't worry, Syfmony is stronger and smarter now. The command will not destroy the data you loaded before.

Conclusion

In this part of the tutorial, we set the project and the Symfony framework up, put the database in place and did a clean-up job (removing the built-in AcmeDemoBundle).

Having the framework ready for proper further development is often the most difficult part of starting a project, especially when dealing with a framework you've never dealt with before. So far, I hope the setup is still easy and straightforward enough. Symfony is the most well-documented framework that I have ever come across, so if you still have problems be sure to visit the Official Documentation and The Cookbook for help, or just get in touch. Again, the final code of this part of the tutorial is available on Github.

Next time, we'll create routes, controllers (to guide the application flow and logic), entities/repositories (to retrieve data), and templates (for presentation) to make the site functional.