Development

Changeset 6886

You must first sign up to be able to contribute.

Changeset 6886

Show
Ignore:
Timestamp:
01/02/08 13:44:26 (1 year ago)
Author:
fabien
Message:

doc: started to update the first project tutorial for 1.1 (wip)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • doc/branches/1.1/tutorial/my-first-project.txt

    r6760 r6886  
    22======================== 
    33 
    4 So, you want to try it on? Let's build together a fully-functional web app in one hour. You name it. A bookseller application? Ok, another idea. A weblog! That's a good one. Let's go. 
    5  
    6 We'll assume that you are working with apache/PHP5 installed and launched on your localhost. You will also need the SQLite extension, which is bundled and compiled by default in PHP5. However, since PHP 5.1.0 you need to manually activate the extension in `php.ini` (see how [here](http://fr3.php.net/manual/en/ref.sqlite.php)). 
     4So, you want to try it on? Let's build together a fully-functional web app in 
     5one hour. You name it. A bookseller application? Ok, another idea. A blog! 
     6That's a good one. Let's go. 
     7 
     8We'll assume that you are working with Apache installed and launched on your 
     9localhost. You will also need PHP 5.1.3 or newer with the SQLite extension 
     10installed and enabled (you can check this in `php.ini` - see how 
     11[in the PHP documentation](http://fr3.php.net/manual/en/ref.sqlite.php). 
    712 
    813Install symfony and initialize the project 
    914------------------------------------------ 
    1015 
    11 To go fast, we will use the symfony sandbox (you can also download the [final source code](http://www.symfony-project.com/downloads/my_first_project.tgz)). It is an empty symfony project where all the required libraries are already included, and where the basic configuration is already done. The great advantage of the sandbox over other types of installation is that you can start experimenting with symfony immediately. 
    12  
    13 Get it here: [sf_sandbox.tgz](http://www.symfony-project.com/get/sf_sandbox.tgz), and unpack it in your root web directory. Refer to the included readme file for more information. The resulting file structure should look like: 
     16To go fast, we will use the symfony sandbox (you can also download the 
     17[final source code](http://www.symfony-project.com/downloads/my_first_project.tgz)). 
     18It is an empty symfony project where all the required libraries are already included, 
     19and where the basic configuration is already done. The great advantage of the sandbox 
     20over other types of installation is that you can start experimenting with symfony 
     21immediately. 
     22 
     23Get it here: [sf_sandbox.tgz](http://www.symfony-project.com/get/sf_sandbox.tgz), 
     24and unpack it in your root web directory. Refer to the included readme file for more 
     25information. The resulting file structure should look like: 
    1426 
    1527    www/ 
     
    3345          js/ 
    3446 
    35 This shows a `sf_sandbox` **project** containing a `frontend` **application**. Test the sandbox by requesting the following URL: 
     47This shows a `sf_sandbox` **project** containing a `frontend` **application**. 
     48Test the sandbox by requesting the following URL: 
    3649 
    3750    http://localhost/sf_sandbox/web/index.php/ 
     
    4154![Congratulations](/images/tutorials/first_congrats.gif) 
    4255 
    43 You can also install symfony in a custom folder and setup your web server with a Virtual Host or an Alias. The symfony book contains detailed chapters about [symfony installation](http://www.symfony-project.com/book/trunk/03-Running-Symfony) and the [symfony directory structure](http://www.symfony-project.com/book/trunk/02-Exploring-Symfony-s-Code). 
     56You can also install symfony in a custom folder and setup your web server with 
     57a Virtual Host or an Alias. The symfony book contains detailed chapters about 
     58[symfony installation](http://www.symfony-project.com/book/1.1/03-Running-Symfony) 
     59and the [symfony directory structure](http://www.symfony-project.com/book/1.1/02-Exploring-Symfony-s-Code). 
    4460 
    4561Initialize the data model 
    4662------------------------- 
    4763 
    48 So, the weblog will handle posts, and you will enable comments on them. Create a `schema.yml` file in `sf_sandbox/config/` and paste the following data model: 
     64So, the blog will handle posts, and you will enable comments on them. Create a 
     65`schema.yml` file in `sf_sandbox/config/` and paste the following data model: 
    4966 
    5067    propel: 
    51       weblog_post: 
    52         _attributes: { phpName: Post } 
    53         id: 
     68      post: 
     69        id:          ~ 
    5470        title:       varchar(255) 
    5571        excerpt:     longvarchar 
    5672        body:        longvarchar 
    57         created_at: 
    58       weblog_comment: 
    59         _attributes: { phpName: Comment } 
    60         id: 
    61         post_id: 
     73        created_at:  ~ 
     74      comment: 
     75        id:          ~ 
     76        post_id:     ~ 
    6277        author:      varchar(255) 
    6378        email:       varchar(255) 
    6479        body:        longvarchar 
    65         created_at: 
    66  
    67 This configuration file uses the YAML syntax. It's a very simple language that allows XML-like tree structures described by indentation. Furthermore, it is faster to read and write than XML. The only thing is, the indentation has a meaning and tabulations are forbidden, so remember to use spaces for indentation. You will find more about YAML and the symfony configuration in the [configuration chapter](http://www.symfony-project.com/book/trunk/05-Configuring-Symfony). 
    68      
    69 This schema describes the structure of two the tables needed for the weblog. `Post` and `Comment` are the names of the related classes to be generated. Save the file, open a command line, browse to the `sf_sandbox/` directory and type: 
     80        created_at:  ~ 
     81 
     82This configuration file uses the YAML syntax. It's a very simple language that 
     83allows XML-like tree structures described by indentation. Furthermore, it is 
     84faster to read and write than XML. The only thing is, the indentation has a 
     85meaning and tabulations are forbidden, so remember to use spaces for indentation. 
     86You will find more about YAML and the symfony configuration in the 
     87[configuration chapter](http://www.symfony-project.com/book/1.1/05-Configuring-Symfony). 
     88 
     89This schema describes the structure of two the tables needed for the blog. 
     90`Post` and `Comment` are the names of the related classes to be generated. 
     91Save the file, open a command line, browse to the `sf_sandbox/` directory and type: 
    7092 
    7193    $ php symfony propel:build-model 
    7294 
    73 >**Note**: Make sure to be at the root of your project (`sf_sandbox/`) when you call the `symfony` command. 
    74  
    75 A few classes are created in the `sf_sandbox/lib/model/` directory. These are the classes of the object-relational mapping, who allow us to have access to a relational database from within an object-oriented code without writing a single SQL query. Symfony uses the Propel library for this purpose. We will call theses objects the **model** (find more in the [model chapter](http://www.symfony-project.com/book/trunk/08-Inside-the-Model-Layer)). 
     95>**Note**: Make sure to be at the root of your project (`sf_sandbox/`) when you 
     96call the `symfony` command. 
     97 
     98A few classes are created in the `sf_sandbox/lib/model/` directory. These are the 
     99classes of the object-relational mapping, who allow us to have access to a relational 
     100database from within an object-oriented code without writing a single SQL query. 
     101By default, symfony uses the Propel library for this purpose. Theses classes are 
     102part of the **model** of our application (find more in the [model chapter](http://www.symfony-project.com/book/1.1/08-Inside-the-Model-Layer)). 
    76103 
    77104Now type in the command line: 
     
    79106    $ php symfony propel:build-sql 
    80107 
    81 A `lib.model.schema.sql` file is created in `sf_sandbox/data/sql/`. This SQL query can be used to initialize a database with the same table structure. You could create a database in MySQL with the command line or a web interface (as described in the [model chapter](http://www.symfony-project.com/book/trunk/08-Inside-the-Model-Layer)). Luckily, the symfony sandbox is configured to work out of the box with a simple SQLite file, so no database initialization is required. By default, the `sf_sandbox` project will use a database called `sandbox.db` located in `sf_sandbox/data/`. To build the table structure based on the the SQL file, type: 
     108A `lib.model.schema.sql` file is created in `sf_sandbox/data/sql/`. 
     109The SQL statements found is this file can be used to initialize a database with 
     110the same table structure. You could create a database in MySQL with the command 
     111line or a web interface (as described in the 
     112[model chapter](http://www.symfony-project.com/book/1.1/08-Inside-the-Model-Layer)). 
     113Luckily, the symfony sandbox is configured to work out of the box with a simple 
     114SQLite file, so no database initialization is required. By default, the `sf_sandbox` 
     115project will use a database called `sandbox.db` located in `sf_sandbox/data/`. 
     116To build the table structure based on the the SQL file, type: 
    82117 
    83118    $ php symfony propel:insert-sql 
    84119 
    85 >**Note**: Don't worry if there is a warning at that point, it is normal. The `propel:insert-sql` command removes existing tables before adding the ones of your `lib.model.schema.sql`, and there is no table to remove at that time. 
    86  
    87 Create the application scaffolding 
    88 ---------------------------------- 
    89  
    90 The basic features of a weblog are to be able to Create, Retrieve, Update and Delete (CRUD) posts and comments. As you are new to symfony, you will not create symfony code from scratch, but rather let it create a scaffolding that you may use and modify as needed. Symfony can interpret the data model to generate the CRUD interface automatically: 
     120>**Note**: Don't worry if there is a warning at that point, it is normal. 
     121The `propel:insert-sql` command removes existing tables before adding the ones 
     122of your `lib.model.schema.sql`, and there is no table to remove at that time. 
     123 
     124Create the application 
     125---------------------- 
     126 
     127The basic features of a blog are to be able to Create, Retrieve, Update and 
     128Delete (CRUD) posts and comments. As you are new to symfony, you will not create 
     129symfony code from scratch, but rather let it generate the code that you may use 
     130and modify as needed. Symfony can interpret the data model to generate the CRUD 
     131interface automatically: 
    91132 
    92133    $ php symfony propel:generate-crud frontend post Post 
     
    98139    $ chmod 777 data/sandbox.db 
    99140 
    100 You now have two modules (`post` and `comment`) that will let you manipulate objects of the `Post` and `Comment` classes. A **module** usually represents a page or a group of pages with a similar purpose. Your new modules are located in the `sf_sandbox/apps/frontend/modules/` directory, and they are accessible by the URLs: 
     141You now have two modules (`post` and `comment`) that will let you manipulate 
     142objects of the `Post` and `Comment` classes. A **module** usually represents a 
     143page or a group of pages with a similar purpose. Your new modules are located 
     144in the `sf_sandbox/apps/frontend/modules/` directory, and they are accessible 
     145by the URLs: 
    101146 
    102147    http://localhost/sf_sandbox/web/frontend_dev.php/post 
    103148    http://localhost/sf_sandbox/web/frontend_dev.php/comment 
    104149 
    105 Feel free to create a new post to make the weblog look less empty. 
     150Feel free to create a new post to make the blog look less empty. 
    106151 
    107152![post CRUD](/images/tutorials/first_crud.gif) 
    108153 
    109 Find more about [scaffolding](http://www.symfony-project.com/book/trunk/14-Generators) and the explanation of symfony projects [structure](http://www.symfony-project.com/book/trunk/04-The-Basics-of-Page-Creation) (project, application, module). 
    110  
    111 >**Note**: In the URLs above, the name of the main script - called *front controller* in symfony - was changed from `index.php` to `frontend_dev.php`. The two scripts access the same application (`frontend`), but in different environments. With `frontend_dev.php`, you access the application in the **development environment**, which provides handy development tools like the debug toolbar on the top right of the screen and the live configuration engine. That's why the processing of each page is slower than when using `index.php`, which is the front controller of the **production environment**, optimized for speed. If you want to keep on using the production environment, replace `frontend_dev.php/` by `index.php/` in the following URLs, but don't forget to clear the cache before watching the changes: 
     154Find more about [generators](http://www.symfony-project.com/book/1.1/14-Generators) 
     155and the explanation of symfony projects 
     156[structure](http://www.symfony-project.com/book/1.1/04-The-Basics-of-Page-Creation) 
     157(project, application, module). 
     158 
     159>**Note**: In the URLs above, the name of the main script - called 
     160*front controller* in symfony - was changed from `index.php` to `frontend_dev.php`. 
     161The two scripts access the same application (`frontend`), but in different environments. 
     162With `frontend_dev.php`, you access the application in the **development environment**, 
     163which provides handy development tools like the debug toolbar on the top right 
     164of the screen and the live configuration engine. That's why the processing of 
     165each page is slower than when using `index.php`, which is the front controller 
     166of the **production environment**, optimized for speed. If you want to keep on 
     167using the production environment, replace `frontend_dev.php/` by `index.php/` 
     168in the following URLs, but don't forget to clear the cache before watching the 
     169changes: 
    112170> 
    113171>     $ php symfony cache:clear 
     
    115173>     http://localhost/sf_sandbox/web/index.php/ 
    116174 
    117 Find more about [environments](http://www.symfony-project.com/book/trunk/05-Configuring-Symfony#Environments). 
     175Find more about [environments](http://www.symfony-project.com/book/1.1/05-Configuring-Symfony#Environments). 
    118176 
    119177Modify the layout 
    120178----------------- 
    121179 
    122 In order to navigate between the two new modules, the weblog needs some global navigation. 
    123  
    124 Edit the global template `sf_sandbox/apps/frontend/templates/layout.php` and change the content of the `<body>` tag to: 
     180In order to navigate between the two new modules, the blog needs some global navigation. 
     181 
     182Edit the global template `sf_sandbox/apps/frontend/templates/layout.php` and 
     183change the content of the `<body>` tag to: 
    125184 
    126185    [php] 
     
    141200    </div> 
    142201 
    143 Please be forgiving for the poor design and the use of inner-tag css, but one hour is a short time. 
     202Please be forgiving for the poor design and the use of inner-tag css, but 
     203one hour is a short time. 
    144204 
    145205![post CRUD in layout](/images/tutorials/first_crud_layout.gif) 
    146206 
    147 While you are at it, you can change the title of your pages. Edit the view configuration file of the application (`sf_sandbox/apps/frontend/config/view.yml`), locate the line showing the `title` key and change it to: 
     207While you are at it, you can change the title of your pages. 
     208Edit the view configuration file of the application (`sf_sandbox/apps/frontend/config/view.yml`), 
     209locate the line showing the `title` key and change it to: 
    148210 
    149211    default: 
     
    152214 
    153215    metas: 
    154       title:        The best weblog ever 
     216      title:        The best blog ever 
    155217      robots:       index, follow 
    156218      description:  symfony project 
     
    158220      language:     en 
    159221 
    160 The home page itself needs to be changed. It uses the default template of the `default` module, which is kept in the framework but not in your application directory. To override it, you have to create a custom `main` module: 
     222The home page itself needs to be changed. It uses the default template of the 
     223`default` module, which is kept in the framework but not in your application 
     224directory. To override it, you have to create a custom `main` module: 
    161225 
    162226    $ php symfony generate:module frontend main 
    163227 
    164 By default, the `index` action shows a default congratulations screen. To remove it, edit the `sf_sandbox/apps/frontend/modules/main/actions/actions.class.php` and remove the content of the `executeIndex()` method as follows: 
     228By default, the `index` action shows a default congratulations screen. 
     229To remove it, edit the `sf_sandbox/apps/frontend/modules/main/actions/actions.class.php` 
     230and remove the content of the `executeIndex()` method as follows: 
    165231 
    166232    [php] 
     
    169235    } 
    170236 
    171 Edit the `sf_sandbox/apps/frontend/modules/main/templates/indexSuccess.php` file to show a nice welcome message: 
    172  
    173     [php] 
    174     <h1>Welcome to my swell weblog</h1> 
     237Edit the `sf_sandbox/apps/frontend/modules/main/templates/indexSuccess.php` file 
     238to show a nice welcome message: 
     239 
     240    [php] 
     241    <h1>Welcome to my swell blog</h1> 
    175242    <p>You are the <?php echo rand(1000,5000) ?>th visitor today.</p> 
    176243 
    177 Now, you must tell symfony which action to execute when the homepage is requested. To that extend, edit the `sf_sandbox/apps/frontend/config/routing.yml` and change the `homepage` rule as follows: 
     244Now, you must tell symfony which action to execute when the homepage is requested. 
     245To that extend, edit the `sf_sandbox/apps/frontend/config/routing.yml` and change 
     246the `homepage` rule as follows: 
    178247 
    179248    [yml] 
     
    188257![New home page](/images/tutorials/first_welcome.gif) 
    189258 
    190 Go ahead, start using your new web app: Create a new test post, and a test comment for your this post. 
    191  
    192 Find more about [views and templates](http://www.symfony-project.com/book/trunk/07-Inside-the-View-Layer). 
     259Go ahead, start using your new web app: Create a new test post, and a test 
     260comment for your this post. 
     261 
     262Find more about [views and templates](http://www.symfony-project.com/book/1.1/07-Inside-the-View-Layer). 
    193263 
    194264Pass data from the action to the template 
    195265----------------------------------------- 
    196266 
    197 That was fast, wasn't it? Now it is time to mix the `comment` module into the `post` one to get comments displayed below posts. 
    198  
    199 First, you need to make the post comments available for the post display template. In symfony, this kind of logic is kept in **actions**. Edit the actions file `sf_sandbox/apps/frontend/modules/post/actions/actions.class.php` and change the `executeShow()` method by adding the 4 last lines: 
     267That was fast, wasn't it? Now it is time to mix the `comment` module into the 
     268`post` one to get comments displayed below posts. 
     269 
     270First, you need to make the post comments available for the post display template. 
     271In symfony, this kind of logic is kept in **actions**. Edit the actions file 
     272`sf_sandbox/apps/frontend/modules/post/actions/actions.class.php` and change 
     273the `executeShow()` method by adding the 4 last lines: 
    200274 
    201275    [php] 
     
    211285    } 
    212286 
    213 The `Criteria` and `-Peer` objects are part of Propel's object-relational mapping. Basically, these four lines will handle a SQL query to the `Comment` table to get the comments related to the current `Post` (the one designated by the URL parameter `id`). The `$this->comments` line in the action will give access to a `$comments` variable in the corresponding template. Now, modify the post display template `sf_sandbox/apps/frontend/modules/post/templates/showSuccess.php` by adding at the end: 
     287The `Criteria` and `-Peer` objects are part of Propel's object-relational mapping. 
     288Basically, these four lines will handle a SQL query to the `Comment` table to get 
     289the comments related to the current `Post` (the one designated by the URL parameter `id`). 
     290The `$this->comments` line in the action will give access to a `$comments` variable 
     291in the corresponding template. Now, modify the post display template 
     292`sf_sandbox/apps/frontend/modules/post/templates/showSuccess.php` by adding at the end: 
    214293 
    215294    [php] 
     
    228307    <?php endif; ?> 
    229308 
    230 This page uses new PHP functions (`format_date()` and `simple_format_text()`) provided by symfony, and called 'helpers' because they do some tasks for you that would normally require more time and code. Create a new comment for your first post, then check again the first post, either by clicking on its number in the list, or by typing directly: 
     309This page uses new PHP functions (`format_date()` and `simple_format_text()`) 
     310provided by symfony, and called 'helpers' because they do some tasks for you 
     311that would normally require more time and code. Create a new comment for your 
     312first post, then check again the first post, either by clicking on its number 
     313in the list, or by typing directly: 
    231314 
    232315    http://localhost/sf_sandbox/web/frontend_dev.php/post/show?id=1 
     
    236319This is getting good. 
    237320 
    238 Find more about the [naming conventions](http://www.symfony-project.com/book/trunk/07-Inside-the-View-Layer) linking an action to a template. 
     321Find more about the [naming conventions](http://www.symfony-project.com/book/1.1/07-Inside-the-View-Layer) 
     322linking an action to a template. 
    239323 
    240324Add a record relative to another table 
    241325-------------------------------------- 
    242326 
    243 When adding a comment, you can choose the `id` of the related post. That's not very user-friendly. Let's change this, and make sure that the user comes back to the post he was looking at after adding a comment. 
    244  
    245 First, in the still fresh `modules/post/templates/showSuccess.php` template, add a line at the bottom: 
     327When adding a comment, you can choose the `id` of the related post. 
     328That's not very user-friendly. Let's change this, and make sure that the user 
     329comes back to the post he was looking at after adding a comment. 
     330 
     331First, in the still fresh `modules/post/templates/showSuccess.php` template, 
     332add a line at the bottom: 
    246333 
    247334    [php] 
    248335    <?php echo link_to('Add a comment', 'comment/create?post_id='.$post->getId()) ?> 
    249336     
    250 The `link_to()` helper creates a hyperlink pointing to the `create` action of the `comment` module, so you can add a comment directly from the post details page. Next, open the `modules/comment/templates/editSuccess.php` and replace the following lines: 
     337The `link_to()` helper creates a hyperlink pointing to the `create` action of 
     338the `comment` module, so you can add a comment directly from the post details page. 
     339Next, open the `modules/comment/templates/editSuccess.php` and replace the 
     340following lines: 
    251341 
    252342    [php] 
     
    270360    <?php endif; ?> 
    271361     
    272 The form in the `comment/create` page points to a `comment/update` action, which redirects to `comment/show` when submitted (this is the default behaviour in generated CRUDs). For the weblog, that means that after adding a comment to a post, the detail of the comment is displayed. It is better to display the post with the comments at that point. So open the `modules/comment/actions/actions.class.php` and look for the `executeUpdate()` method. Note that the `created_at` field is not defined by the action: symfony knows that a field named `created_at` has to be set to the system time when a record is created. The final redirect of the action has to be modified to point to the correct action. Change it to: 
     362The form in the `comment/create` page points to a `comment/update` action, which 
     363redirects to `comment/show` when submitted (this is the default behaviour in generated CRUDs). 
     364For the blog, that means that after adding a comment to a post, the detail of the 
     365comment is displayed. It is better to display the post with the comments at that point. 
     366So open the `modules/comment/actions/actions.class.php` and look for the `executeUpdate()` 
     367method. Note that the `created_at` field is not defined by the action: symfony knows 
     368that a field named `created_at` has to be set to the system time when a record is created. 
     369The final redirect of the action has to be modified to point to the correct action. 
     370Change it to: 
    273371 
    274372    [php] 
     
    296394    } 
    297395 
    298 Users can now add comments to a post and come back to the post afterwards. You wanted a weblog? You have a weblog. 
    299  
    300 Find more about [actions](http://www.symfony-project.com/book/trunk/06-Inside-the-Controller-Layer). 
     396Users can now add comments to a post and come back to the post afterwards. 
     397You wanted a blog? You have a blog. 
     398 
     399Find more about [actions](http://www.symfony-project.com/book/1.1/06-Inside-the-Controller-Layer). 
    301400 
    302401Form Validation 
    303402--------------- 
    304403 
    305 Visitors can enter comments, but what if they submit the form without any data in it? You will have a dirty database. To avoid that, create a file called `update.yml` in the `sf_sandbox/apps/frontend/modules/comment/validate/` directory (you also have to create the directory) and write in: 
     404Visitors can enter comments, but what if they submit the form without any data 
     405in it? You will have a dirty database. To avoid that, create a file called 
     406`update.yml` in the `sf_sandbox/apps/frontend/modules/comment/validate/` 
     407directory (you also have to create the directory) and write in: 
    306408 
    307409    methods: 
     
    330432        email_error:  The email address is not valid. 
    331433 
    332 >**Note**: Beware that you don't copy 4 extra spaces at the beginning of each line, since the YAML parser would fail in that case. The first letter of this file must be the 'm' of 'methods'. 
    333  
    334 The `fillin` activation enables the repopulation of the form with the value previously entered by the user in case of failed validation. The `names` declarations set the validation rules for each input of the form. 
    335  
    336 By itself, the controller will redirect the user to a `updateError.php` template if an error is detected. It would be better to display the form again with an error message. To do that, add a `handleErrorUpdate` method to the action class of the `modules/comment/actions/actions.class.php` file: 
     434>**Note**: Beware that you don't copy 4 extra spaces at the beginning of each 
     435line, since the YAML parser would fail in that case. The first letter of this 
     436file must be the 'm' of 'methods'. 
     437 
     438The `fillin` activation enables the repopulation of the form with the value 
     439previously entered by the user in case of failed validation. The `names` declarations 
     440set the validation rules for each input of the form. 
     441 
     442By itself, the controller will redirect the user to a `updateError.php` template 
     443if an error is detected. It would be better to display the form again with an 
     444error message. To do that, add a `handleErrorUpdate` method to the action class 
     445of the `modules/comment/actions/actions.class.php` file: 
    337446 
    338447    [php] 
     
    342451    } 
    343452 
    344 Now to finish, open again the `modules/comment/templates/editSuccess.php` template and insert at the top: 
     453Now to finish, open again the `modules/comment/templates/editSuccess.php` template 
     454and insert at the top: 
    345455 
    346456    [php] 
     
    360470![Form validation](/images/tutorials/first_form_validation.gif) 
    361471 
    362 Find more about [form validation](http://www.symfony-project.com/book/trunk/10-Forms). 
     472Find more about [form validation](http://www.symfony-project.com/book/1.1/10-Forms). 
    363473 
    364474Change the URL aspect 
    365475--------------------- 
    366476 
    367 Did you notice the way the URLs are rendered? You can make them more user and search engine-friendly. Let's use the post title as an URL for posts.  
    368  
    369 The problem is that post titles can contain special characters like spaces. If you just escape them, the URL will show some ugly `%20` kind of things, so you'd better extend the model to add a new method to the `Post` object to get a clean, stripped title. To do that, edit the file `Post.php` located in the `sf_sandbox/lib/model/` directory, and add the following method: 
     477Did you notice the way the URLs are rendered? You can make them more user and 
     478search engine-friendly. Let's use the post title as an URL for posts. 
     479 
     480The problem is that post titles can contain special characters like spaces. 
     481If you just escape them, the URL will show some ugly `%20` kind of things, 
     482so you'd better extend the model to add a new method to the `Post` object 
     483to get a clean, stripped title. To do that, edit the file `Post.php` located 
     484in the `sf_sandbox/lib/model/` directory, and add the following method: 
    370485 
    371486    [php] 
     
    387502    } 
    388503 
    389 Now you can create a `permalink` action for the `post` module. Add the following method to the `modules/post/actions/actions.class.php`: 
     504Now you can create a `permalink` action for the `post` module. Add the following 
     505method to the `modules/post/actions/actions.class.php`: 
    390506 
    391507    [php] 
     
    407523    } 
    408524 
    409 The post list can call this `permalink` action instead of the `show` one for each post. In `modules/post/templates/listSuccess.php`, delete the `id` table header and cell, and change the `Title` cell from: 
     525The post list can call this `permalink` action instead of the `show` one for 
     526each post. In `modules/post/templates/listSuccess.php`, delete the `id` table 
     527header and cell, and change the `Title` cell from: 
    410528 
    411529    [php] 
     
    417535    <td><?php echo link_to($post->getTitle(), 'post/permalink?title='.$post->getStrippedTitle()) ?></td> 
    418536 
    419 Just one more step: Edit the `routing.yml` located in the `sf_sandbox/apps/frontend/config/` directory and add these rules at the top: 
     537Just one more step: Edit the `routing.yml` located in the 
     538`sf_sandbox/apps/frontend/config/` directory and add these rules at the top: 
    420539 
    421540    list_of_posts: 
     
    424543 
    425544    post: 
    426       url:   /weblog/:title 
     545      url:   /blog/:title 
    427546      param: { module: post, action: permalink } 
    428547 
     
    431550![Routed URLs](/images/tutorials/first_routing.gif) 
    432551 
    433 Find more about [smart URLs](http://www.symfony-project.com/book/trunk/09-Links-and-the-Routing-System). 
     552Find more about [smart URLs](http://www.symfony-project.com/book/1.1/09-Links-and-the-Routing-System). 
    434553 
    435554Cleanup in the frontend 
    436555----------------------- 
    437556 
    438 Well, if this is a weblog, then everybody has the right to post. This isn't exactly what you thought about, right? Ok, let's clean up our templates a bit. 
    439  
    440 In the template `modules/post/templates/showSuccess.php`, get rid of the 'edit' link by removing the line: 
     557Well, if this is a blog, then everybody has the right to post. 
     558This isn't exactly what you thought about, right? Ok, let's clean up our 
     559templates a bit. 
     560 
     561In the template `modules/post/templates/showSuccess.php`, get rid of the 
     562'edit' link by removing the line: 
    441563 
    442564    [php] 
     
    460582------------------------- 
    461583 
    462 For you to write posts, let's create a backend application by typing in the command line (still from the `sf_sandbox` project directory): 
     584For you to write posts, let's create a backend application by typing in the 
     585command line (still from the `sf_sandbox` project directory): 
    463586 
    464587    $ php symfony generate:app backend 
     
    466589    $ php symfony propel:init-admin backend comment Comment 
    467590 
    468 This time, we use the [admin generator](http://www.symfony-project.com/book/trunk/14-Generators). It offers much more features and customization than the very basic CRUD generator. 
    469  
    470 Just like you did for the `frontend` application, edit the layout (`apps/backend/templates/layout.php`) to add global navigation: 
     591This time, we use the [admin generator](http://www.symfony-project.com/book/1.1/14-Generators). 
     592It offers much more features and customization than the basic CRUD generator. 
     593 
     594Just like you did for the `frontend` application, edit the layout (`apps/backend/templates/layout.php`) 
     595to add global navigation: 
    471596 
    472597    <div id="navigation"> 
     
    486611![basic generated admin](/images/tutorials/first_basic_admin.gif) 
    487612 
    488 The great advantage of the generated admin is that you can easily customize it by editing a configuration file. 
     613The great advantage of the generated admin is that you can easily customize it by 
     614editing a configuration file. 
    489615 
    490616Change the `backend/modules/post/config/generator.yml` to: 
     
    518644            created_at:   { type: input_date_tag, params: rich=on } 
    519645 
    520 Note that among the existing columns of the `Post` table, the admin will look for a `nb_comments`. There is no associated getter yet, but it is simple to add to the `sf_sandbox/lib/model/Post.php`: 
     646Note that among the existing columns of the `Post` table, the admin will look 
     647for a `nb_comments`. There is no associated getter yet, but it is simple to 
     648add to the `sf_sandbox/lib/model/Post.php`: 
    521649 
    522650    [php] 
     
    540668      is_secure: on 
    541669 
    542 Repeat the operation for the `comment` module. Now you can't access these modules anymore unless you are logged. 
    543  
    544 But the logging action doesn't exist! Ok, so you can easily add it. First, create the `security` module skeleton: 
     670Repeat the operation for the `comment` module. Now you can't access these modules 
     671anymore unless you are logged. 
     672 
     673But the logging action doesn't exist! Ok, so you can easily add it. 
     674First, create the `security` module skeleton: 
    545675 
    546676    $ php symfony generate:module backend security 
    547677 
    548 This new module will be used to handle the login form and the request. Edit the `apps/backend/modules/security/templates/indexSuccess.php` to create the login form: 
     678This new module will be used to handle the login form and the request. 
     679Edit the `apps/backend/modules/security/templates/indexSuccess.php` to 
     680create the login form: 
    549681 
    550682    [php] 
     
    565697    </form> 
    566698 
    567 Add the `login` action that is called by the form to the `security` module (in the `apps/backend/modules/security/actions/actions.class.php` file): 
     699Add the `login` action that is called by the form to the `security` module 
     700(in the `apps/backend/modules/security/actions/actions.class.php` file): 
    568701 
    569702    [php] 
     
    591724    } 
    592725 
    593 The last thing to do is to set the `security` module as the default module to handle login actions. To do that, open the `apps/backend/config/settings.yml` configuration file and add: 
     726The last thing to do is to set the `security` module as the default module to 
     727handle login actions. To do that, open the `apps/backend/config/settings.yml` 
     728configuration file and add: 
    594729 
    595730    all: 
    596731      .actions: 
    597732        login_module:           security 
    598         login_action:           index     
    599  
    600 At that point, if you try to access the Posts management, you will have to enter a login and a password: 
     733        login_action:           index 
     734 
     735At that point, if you try to access the Posts management, you will have to enter 
     736a login and a password: 
    601737 
    602738![login form](/images/tutorials/first_login.gif) 
    603739 
    604 Find more about [security](http://www.symfony-project.com/book/trunk/06-Inside-the-Controller-Layer#Action%20Security). 
     740Find more about [security](http://www.symfony-project.com/book/1.1/06-Inside-the-Controller-Layer#Action%20Security). 
    605741 
    606742Conclusion 
    607743---------- 
    608744 
    609 Ok, the hour is out. You made it. Now you can use both applications in the production environment and play with them: 
     745Ok, the hour is out. You made it. Now you can use both applications in the production 
     746environment and play with them: 
    610747 
    611748    frontend:   http://localhost/sf_sandbox/web/index.php/ 
    612749    backend:    http://localhost/sf_sandbox/web/backend.php/ 
    613750 
    614 At this point, if you meet an error, it might be because you changed the model after some actions were put in cache (cache isn't activated in the development environment). To clear the cache, simply type: 
     751At this point, if you meet an error, it might be because you changed the model after 
     752some actions were put in cache (cache isn't activated in the development environment). 
     753To clear the cache, simply type: 
    615754 
    616755    $ php symfony cc 
    617756 
    618 See, the application is fast and runs smoothly. Pretty darn cool, isn't it? Feel free to explore the code, add new modules, and change the design of pages.  
    619  
    620 And don't forget to mention your working symfony applications in the symfony Wiki! 
     757See, the application is fast and runs smoothly. Pretty darn cool, isn't it? 
     758Feel free to explore the code, add new modules, and change the design of pages.  
     759 
     760And don't forget to mention your working symfony applications in the 
     761[symfony Wiki](http://trac.symfony-project.com/wiki/ApplicationsDevelopedWithSymfony)!