Symfony model layer tips and tricks – A PHP Framework – Part 3

I had a tough time searching for examples over the net for all kind of symfony queries. Though symfony is well documented here, I didn’t find enough examples there.

If you have landed up on this post straight and are new to symfony, you may want to first read previous posts:
Getting started with Symfony – A PHP Framework – Part 1
How to build a login-registration system using Symfony – A PHP Framework – Part 2

If you are well equipped with the basics, read on

Select Query:
Lets start with the few basic example queries.

  1. Extract list of all users from the users table

    $c = new Criteria();
    $this->resultSet = UsersPeer::doSelect($c);

    Now lets see how can we use this $resultset within the model layer and in the template files.
    To use the resultset within model layer, we can do something like this:

    foreach($this->resultset as $rs) {
        $uid = $ps->getId();
        $fname = $ps->getFirstName();
        $lname = $ps->getLastName();
    }

    To use the resultset in template files (viewer layer), we can do something like this:

    foreach($resultset as $rs) {
        $uid = $ps->getId();
        $fname = $ps->getFirstName();
        $lname = $ps->getLastName();
    }

  2. Extract list of first 10 users only

    $c = new Criteria();
    $c->setLimit(10);
    $this->resultSet = UsersPeer::doSelect($c);

  3. Extract list of 10 users starting from 100th user

    $c = new Criteria();
    $c->setOffset(100);
    $c->setLimit(10);
    $this->resultSet = UsersPeer::doSelect($c);

  4. Extract user data where username = ‘imoracle’

    $c = new Criteria();
    $c->add(UsersPeer::USERNAME,”imoracle”);           // Note USERNAME is all in caps, even if your column name is in small case
    $this->resultSet = UsersPeer::doSelect($c);

  5. Another approach to do a select query

    $c = new Criteria();
    $c->add(UsersPeer::USERNAME,”imoracle”);
    $resultSet = UsersPeer::doSelectRS($c);

    To access this resultset in the model layer itself, we can do something like this:

    while($resultSet->next()) {
        $uid = $resultSet->get(1);
        $fname = $resultSet->get(2);
        $lname = $resultSet->get(3);
    }

    Where get(1) fetches the 1st column for you of the resultset. Hence $resultSet->get(n) will fetch you the nth column of the resultSet.

Insert Query:
Lets see a few quick examples for inserting a new row in a table.

  1. Insert a user entry in user table

    $new_user = new Users();
    $new_user->setUserName($uname);
    $new_user->setFirstName($fname);
    $new_user->setLastName($lname);
    $new_user->setPassword(md5($pass));

    $new_user->save();
    $new_user_id = $new_user->getId();

    Finally we get the last inserted user row id.

Update Query:
Symfony provides nothing special for the update queries. The same above format works for updating a row as well. Symfony is smart enough to analyze whether its a select or update query.

  1. First Method for Update Query (Recommended)

    $c = new Criteria();
    $c->add(UsersPeer::USERNAME,”imoracle”);
    $c->add(UsersPeer::PASSWORD,$newpass);
    $res = UsersPeer::doUpdate($c);

    In the above example we chose to update the password for user with username “imoracle”.

  2. Another Method for Update Query

    $user = new User();
    $user->setNew(false);
    $user->setId($uid);
    $user->setPassword($newpass);
    $user->save();

    Important code in above 5 lines is the 2nd line. Without this line it will add a new row and not update. Also another drawback which I found in this approach is that in third line you need to give the PK (primary key) of the table. Like our 1st method you cannot give username in the third line.

    Finally I haven’t tried and tested this method enough. So I will not recommend this.

Delete Query:
Its basically the same above methods, with change of final call.

  1. Delete a user’s account where username = ‘imoracle’

    $c = new Criteria();
    $c->add(UsersPeer::USERNAME,’imoracle’);
    $res = UsersPeer::doDelete($c);

How to alter a table in symfony?

  1. Method 1 (Non-standard)
    A drawback which I have seen in symfony till now is that, when you try to alter a table by adding new columns in your schema.yml, It flushes the data from the table and gives you an altered table with no data. This is really bad, if you don’t know this behavior and move ahead altering the table. Though Symfony provider propel-dump-data to handle alter tables, but it is still quite buggy and slow for big databases. The clean and smooth way to achieve this is:

    1. Take a mysql dump with following options:
      mysqldump -h hostname -u username -p password -c -t dbname > dbname.sql
      Do not forget to use option -c and -t, without which it can land you in a problem
    2. Update your schema.yml file, with new columns which you want to add and run
      sudo symfony propel-build-all
    3. Restore the database content using following command:
      mysql -h hostname -u username -p password dbname < dbname.sql

    And you have your new altered table without any loss of data.

  2. Method 2 (Standard)
    If you are afraid of your data being flushed by the stupid symfony, then you may choose not to touch your database using propel at all. Here is what you can do in such a case.

    1. Update your schema.yml file and run
      sudo symfony propel-build-model
    2. Then manually go and alter the table in the database.

    Here propel-build-model will only rebuild the ORM layer to incorporate your schema.yml changes. However propel-build-all not only builds the ORM layer, but also actually creates the table in the database (flushing the data)

In future I shall keep adding more SQL queries on this post, as and when I write them using symfony. So keep glued to this one 😉

How to build a login-registration system using Symfony – A PHP Framework – Part 2

Hello again,

In the last tutorial we saw a very basic implementation which will simply print “Hello World” on your browser screen. For those who have landed up here straight here, you may want to go through this blog post. Getting started with Symfony – A PHP Framework – Part 1 By now if you have decided to go ahead with symfony and use it for your site development, this is what you will be looking for next.

You can download the code for this tutorial from google code base.

svn checkout http://abhinavsingh.googlecode.com/svn/trunk/PHP/
Frameworks/Symfony/Authentication abhinavsingh-read-only

A Registration-Login-Logout System for your site
This is mostly the first thing you end up building for your site. To be frank, I myself haven’t made this application. I will make it as I write this blog, and note down all my steps here, so that I don’t miss any detail.

  1. We will name our project as Authentication
  2. Create a folder called Authentication under the Symfony directory we made in the last tutorial. For me its here C:WorkspaceSymfonyAuthentication
  3. Open your command line and point it to the above created folder
  4. Type “symfony init-project Authentication” and it will create same directory structure that we discussed in last tutotial.
  5. Lets create an application inside this, we will name it as Auth
  6. Type “symfony init-app Auth” and it will create an application named Auth under the apps folder. (C:WorkspaceSymfonyAuthenticationappsAuth)
  7. First we need a module called Registration, to allow our users to register.
  8. Type “symfony init-module Auth Registration” and it will tell symfony to create a module named Registration inside our application Auth
  9. As told in last tutorial copy the C:php5peardatasymfonywebsf folder to C:WorkspaceSymfonyAuthenticationwebsf. At the end of this part, we will learn how can we skip this copying again and again
  10. Open C:WorkspaceSymfonyAuthenticationappsAuthmodulesRegistrationactionsactions.class.php and comment out the forwarding as discussed in last tutorial.
  11. Go to your command line and type “symfony clear-cache“. Read why we do this in the last tutorial.
  12. Open http://localhost/Symfony/Authentication/web/ in your browser and you must get something like this.


Figure 1

OOPS! Did we missed something? Yes we did and intentionally. We could have gone to C:WorkspaceSymfonyAuthenticationappsAuthconfigrouting.yml and redirected our Authentication application to our Registration Module by default. In that case we would have seen an empty page since indexSuccess.php file inside C:WorkspaceSymfonyAuthenticationappsAuthmodulesRegistrationtemplates is empty. But since we didn’t modified the routing.yml file, it took us to the default module of symfony.

So how do we access our Registration module without modifying routing.yml file??
http://localhost/Symfony/Authentication/web/Registration/index is the answer 🙂

As a convention
http://localhost/Symfony/Authentication/web/<Module>/<ModuleFile>
this is the standard for symfony.

Hence it went to Registration module and then indexSuccess.php page inside that. Cool so we actually just followed up from our last tutorial till here. Lets now do the actual development.

Defining a layout for our website
Before we do any backend stuff, lets atleast get our site out of that blank page (http://localhost/Symfony/Authentication/web/Registration/index). However, If you view the source of that blank page, you will actually find that there are already some header, css, body tags in the source code. How is this coming? when we have an empty indexSuccess.php file.

From our last tutorial we saw the flow which symfony follows to finally display a page on the browser. But then I actually skipped a step to ease down the tutorial. In symfony we follow the Decorator Design Patterns (I hope i m not wrong here) , to get the front end stuff. Essentially Decorator Design Pattern consists of a Layout and a Content page.

In symfony our layout file is located under at C:WorkspaceSymfonyAuthenticationappsAuthtemplateslayout.php. Open it up and you will know the answer to “How are those meta tags, head tags and body tags coming”.

Cool enough. Lets go back to our indexSuccess.php file of Registration module and design our website. With a little CSS and HTML, I came up with this design page for our site. Mostly inspired and stolen from my new site Gtalkbots.com


Figure 2

We will shift a bit of code from this page to our layout.php page later on so that we need now write the same modules again and again. Download all the code, from the my google code vault location given at the beginning and end of this tutorial.

Designing the backend database:
Now we need  a databases schema which will save our registered user’s data.  Lets create our database structure.

As talked about in last tutorial, symfony follows ORM programming technique. For this, they provide a method through which you actually need not go to your database and create tables. Symfony will do that for you. Not only this, Symfony will also allow you to skip most of the SQL queries. Lets see how.

  1. Open C:WorkspaceSymfonyAuthenticationconfigschema.yml . From extension we know that symfony follows YAML structures which is similar to XML, but a bit easy to write. We will define our table structures in this file.
  2. Type the following in the schema.yml file:
    Propel:
      users:
        id:        { type: integer, primaryKey: true, autoIncrement: true }
        username:  varchar(100)
        emailid:   varchar(100)
        password:  varchar(100)
    
  3. Note the indentation, it is very very important when you are using YAML. Indentation actually decides how the YAML parsers will read and interpret the information you want to write in .yml files. In our case we have a very simple schema.yml file having only one table. We will learn about what that “Propel” is all about later, but lets focus from line 2.
  4. We are trying to make a table called users having fields like id, username, emailid and password
  5. Now before Symfony makes this table for you, we need to tell symfony the database username and password. For this we have a configuration file called propel.ini, located at C:WorkspaceSymfonyyahooconfigpropel.ini
  6. Open it and change the lines as below:
    propel.database.createUrl  = mysql://[email protected]/
    propel.database.url        = mysql://root:[email protected]/authentication
    

    Now go to your mysql database and create a database named authentication, which symfony will use from now on.

  7. Type “symfony propel-build-all” in your command line. This command will happily create a table named “users” in youy MySQL database “authentication”. Some of the possible errors which I got in the past are:
    • Your PHP must be compiled with XSLT, hence enable it by going in your php.ini file
    • In schema.yml file never use TABS. The YAML parsers don’t understand TABS. User SPACES intead of that.
  8. To cross verify check your database, if the table has been created. Now a bit about Propel.

Propel is nothing but a third-party-vendor plugin which Symfony use. It helps in parsing the YAML files, creating and executing the whole ORM module including parsing of schema.yml , creating tables, creating ORM data objects. We will slowly and gradually learn a lot more about ORM.

A look at the model layer
Another thing which the propel command did was, it created the whole ORM module. If you go to C:WorkspaceSymfonyAuthenticationlibmodel you can see 2 folders being created and a few files too.

For every table, propel build 5 files under the model folder. These files are basically the class files, which will provide use with a database object which we can use to select or insert data in the database.

C:WorkspaceSymfonyAuthenticationlibmodelomBaseUsers.php &
C:WorkspaceSymfonyAuthenticationlibmodelomBaseUsersPeer.php are the only 2 files which will be re-created when you run the propel command again.

The file positioned at
C:WorkspaceSymfonyAuthenticationlibmodelUsers.php &
C:WorkspaceSymfonyAuthenticationlibmodelUsersPeer.php will be as it is from this point in time. If you write your own methods in them, they will remain as it is even when you re-create your database schema.

We will use these created ORM files to insert, delete, select data from the databases. In symfony we can actually skip writing a SQL query (though we can always write a direct query too)

Writing the backend Code:
With UI and database in shape, its time to write our backend code which will handle the registration form submission. If you notice the source code of our form, the action field is set as :

<form id=”registration” action=”<?php echo url_for(“Registration/index”); ?>” method=”POST”>

In symfony we have a lot of helper functions which we can use. In this case we users url_for helper function, which helps in generating a url with <module>/<modulefile> being passed as parameter.

So we have our form being submitted to indexSuccess.php itself, i.e. SELF.
Hence lets go to executeIndex() method in action.class.php and write the code which will handle the submitted form.

Copy the modified action.class.php file from the vault location. I have documented every line inside the code, which will walk you through the code. Understand the flow and continue reading.

However before we insert any data in the database, we need to give the database parameters. Go to
C:WorkspaceSymfonyAuthenticationconfigdatabases.yml
and uncomment the lines of code in there. Finally it should be of the following structure:

all:
  propel:
    class:          sfPropelDatabase
    param:
      dsn:          mysql://root:[email protected]/authentication

Lastly open:
C:WorkspaceSymfonyAuthenticationappsAuthconfigsettings.yml
and go to the last line of the file. You will find
# compat_10    off
being commented out
Uncomment it and then turn on compat_10 i.e.
compat_10    on

Clear your cache, before submitting the form (symfony clear-cache) and then try to register.

If you have followed everything, you will be able to successfully able to register and visit mainSuccess.php of the module.

I have documented all the code which you can download from the vault location. Read it, try it, play with it.

PS: The best documentation is available at symfony-project website. This tutorial was intended to
build a real life scenario application using Symfony. Though I must admit that I still haven’t used 100% possible symfony
for this application, just to make it simple but still give you a feel of how things flow in symfony.

Leave a comment if you have any doubt or difficulty in implementing the code.
Do leave a comment even if you like the code 😉