Building a Web App with Symfony 2: Bootstrapping

Taylor Ren
Tweet
This entry is part 1 of 3 in the series Building a Personal Web App Head To Toe With Symfony 2

Building a Personal Web App Head To Toe With Symfony 2

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.

Building a Personal Web App Head To Toe With Symfony 2

Building a Web App With Symfony 2: Development >>

Get your free chapter of Level Up Your Web Apps with Go

Get a free chapter of Level Up Your Web Apps with Go, plus updates and exclusive offers from SitePoint.

  • Mike

    This looks very promising, hope to see the next part soon.

  • Geoff

    I’ve heard so much about Symfony and will most likely give it a crack now. Thanks for this.

  • Joselee

    part 1 of 1, or part 1 of 2 0r 3, I am really waiting how you did bootstrapping3 with sf2

  • Steve

    Seems a bit bloated for a simple site.

    • mTorres

      Symfony is not targetted for simple sites. If you want simplicity, go for Silex (Symfony little brother) or Laravel. Symfony is well engineered and is extremely flexible, but if you’re not going to use its flexibility, maybe it’s not the right tool for your job.

      • Taylor Ren

        Silex or Laravel is cool and good to use.

        I did not use too much on these two though.

        Web development (excluding the HTML5/JS development) is still very static and should not tap too much on the dynamics in anonymous functions, closures, etc.

  • Alan Zhang

    Symfony is great. But these days, laravel is more promising. I work for a company using symfony, but all my personal projects,I only use laravel.

    • Anonymous

      That’s all personal preference. After trying Phalcon, I’d never use another non-compiled framework again just because of the well-roundedness and performance. To each his own. Use whatever makes your life easier.

    • Taylor Ren

      Agree with Bruno on this. “Promising” is really subjective and personal preference prevails in the selection of the framework.

  • Taylor Ren

    This is the Part 1 of 3. And yes, I do rely on Bootstrap 3 to design the layout (and used it in Symfony’s Twig engine). That could be a very long story and not really very much related to Symfony itself (except the Twig grammar) but more on the Bootstrap 3 (to choose the right template to start with).

  • Anonymous

    I have always liked the Symphony Project, however this brain can’t handle Symphony and Zend 2 at the same time, nice post though.

  • J23

    I’m getting an error when importing the database structure:

    php console doctrine:mapping:import trrsywxBundle

    [DoctrineORMMappingMappingException] Property “bookid” in “BookHeadline” was already declared, but it must be declared only once

    • Taylor Ren

      Can you dump your db structure in a sql format and send to me: taylor.ren@gmail.com?

      Most likely it is due to that BookHeadline has a compound primary key, and one of the fields constituting the PK is also a FK (in this case, the bookid). You can try to delete the FK first and after importing, create the FK again.

      • Eugene Fidelin

        Removing ‘bookid’ FK before runing doctrine:mapping:import helps!

  • Rodney Blevins

    I’m getting the same error. Were you able to figure it out?

    • Taylor Ren

      Hi Rodney,

      Sorry to hear this. Can you do the same to dump the db structure and send over to me? I will do a test at my end.

  • johnnyjenkins

    Hi – thanks for the tutorial. Was all quite clear except the last part.
    I can confirm the problem of the last poster and your fix does the trick – remove the FK, import, then re-add.
    But the last command “php appconsole doctrines:generate:entity tr” (apart from the ‘doctrines’ typo) just states ‘Too many arguments’.
    Sorry – I’m such a newb (thus this tutorial) but what did I miss?

    • Taylor Ren

      Try doctrine:generate:entities tr instead. It SHOULD be in plural forms.

    • Taylor Ren

      Use “php appconsole doctrine:generate:entities tr”. Sorry for the typo.

    • johnnyjenkins

      Just to answer my own question (for any that need to know) the actual command is –
      php app/console doctrine:generate:entities whateverBundle

  • Anonymous

    Hi johnnyjenkins, I’m having the same error “Too many arguments”. Did you solved it in some way?

  • Rob

    Ditto

    [DoctrineORMMappingMappingException] Property “bookid” in “BookHeadline” was already declared, but it must be declared only once

    • Taylor Ren

      Hi Rob3,

      The solution is also explained above. Please try and let me know. In case you need my further support, please write to me: taylor.ren@gmail.com

  • Ricardo Seromenho

    Thank you for this post.
    I think after creating the database should be

    php app/console doctrine:mapping:import –force trrsywxBundle
    php app/console doctrine:generate:entities tr