Changeset 7362
- Timestamp:
- 02/06/08 09:28:31 (10 months ago)
- Files:
-
- doc/branches/1.0/tutorial/my-first-project.txt (modified) (33 diffs)
- doc/branches/1.0/tutorial/symfony-ajax.txt (modified) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
doc/branches/1.0/tutorial/my-first-project.txt
r6759 r7362 2 2 ======================== 3 3 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)). 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 5 application? Ok, another idea. A weblog! That's a good one. Let's go. 6 7 We'll assume that you are working with apache/PHP5 installed and launched on your localhost. You will also need the SQLite 8 extension, which is bundled and compiled by default in PHP5. However, since PHP 5.1.0 you need to manually activate the 9 extension in `php.ini` (see how [here](http://fr3.php.net/manual/en/ref.sqlite.php)). 7 10 8 11 Install symfony and initialize the project 9 12 ------------------------------------------ 10 13 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: 14 To go fast, we will use the symfony sandbox (you can also download the [final source 15 code](http://www.symfony-project.org/downloads/my_first_project.tgz)). It is an empty symfony project where all the 16 required libraries are already included, and where the basic configuration is already done. The great advantage of the 17 sandbox over other types of installation is that you can start experimenting with symfony immediately. 18 19 Get it here: [sf_sandbox.tgz](http://www.symfony-project.org/get/sf_sandbox.tgz), and unpack it in your root web 20 directory. Refer to the included readme file for more information. The resulting file structure should look like: 14 21 15 22 www/ … … 33 40 js/ 34 41 35 This shows a `sf_sandbox` **project** containing a `frontend` **application**. Test the sandbox by requesting the following URL: 42 This shows a `sf_sandbox` **project** containing a `frontend` **application**. Test the sandbox by requesting the 43 following URL: 36 44 37 45 http://localhost/sf_sandbox/web/index.php/ … … 41 49  42 50 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). 51 You can also install symfony in a custom folder and setup your web server with a Virtual Host or an Alias. The symfony 52 book contains detailed chapters about [symfony installation](http://www.symfony-project.org/book/1_0/03-Running-Symfony) 53 and the [symfony directory structure](http://www.symfony-project.org/book/1_0/02-Exploring-Symfony-s-Code). 44 54 45 55 Initialize the data model 46 56 ------------------------- 47 57 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: 58 So, the weblog will handle posts, and you will enable comments on them. Create a `schema.yml` file in `sf_sandbox/config/` 59 and paste the following data model: 49 60 50 61 propel: … … 65 76 created_at: 66 77 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: 78 This configuration file uses the YAML syntax. It's a very simple language that allows XML-like tree structures described 79 by indentation. Furthermore, it is faster to read and write than XML. The only thing is, the indentation has a meaning and 80 tabulations are forbidden, so remember to use spaces for indentation. You will find more about YAML and the symfony 81 configuration in the [configuration chapter](http://www.symfony-project.org/book/1_0/05-Configuring-Symfony). 82 83 This schema describes the structure of two the tables needed for the weblog. `Post` and `Comment` are the names of the 84 related classes to be generated. Save the file, open a command line, browse to the `sf_sandbox/` directory and type: 70 85 71 86 $ php symfony propel-build-model … … 73 88 >**Note**: Make sure to be at the root of your project (`sf_sandbox/`) when you call the `symfony` command. 74 89 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)). 90 A few classes are created in the `sf_sandbox/lib/model/` directory. These are the classes of the object-relational 91 mapping, who allow us to have access to a relational database from within an object-oriented code without writing a single 92 SQL query. Symfony uses the Propel library for this purpose. We will call theses objects the **model** (find more in the 93 [model chapter](http://www.symfony-project.org/book/1_0/08-Inside-the-Model-Layer)). 76 94 77 95 Now type in the command line: … … 79 97 $ php symfony propel-build-sql 80 98 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: 99 A `lib.model.schema.sql` file is created in `sf_sandbox/data/sql/`. This SQL query can be used to initialize a database 100 with the same table structure. You could create a database in MySQL with the command line or a web interface (as described 101 in the [model chapter](http://www.symfony-project.org/book/1_0/08-Inside-the-Model-Layer)). Luckily, the symfony sandbox 102 is configured to work out of the box with a simple SQLite file, so no database initialization is required. By default, the 103 `sf_sandbox` project will use a database called `sandbox.db` located in `sf_sandbox/data/`. To build the table structure 104 based on the the SQL file, type: 82 105 83 106 $ php symfony propel-insert-sql 84 107 85 >**Note**: Don't worry if there is a warning at that point, it is normal. The `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. 108 >**Note**: Don't worry if there is a warning at that point, it is normal. The `insert-sql` command removes existing tables 109 >before adding the ones of your `lib.model.schema.sql`, and there is no table to remove at that time. 86 110 87 111 Create the application scaffolding 88 112 ---------------------------------- 89 113 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: 114 The basic features of a weblog are to be able to Create, Retrieve, Update and Delete (CRUD) posts and comments. As you are 115 new to symfony, you will not create symfony code from scratch, but rather let it create a scaffolding that you may use and 116 modify as needed. Symfony can interpret the data model to generate the CRUD interface automatically: 91 117 92 118 $ php symfony propel-generate-crud frontend post Post … … 98 124 $ chmod 777 data/sandbox.db 99 125 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: 126 You now have two modules (`post` and `comment`) that will let you manipulate objects of the `Post` and `Comment` classes. 127 A **module** usually represents a page or a group of pages with a similar purpose. Your new modules are located in the 128 `sf_sandbox/apps/frontend/modules/` directory, and they are accessible by the URLs: 101 129 102 130 http://localhost/sf_sandbox/web/frontend_dev.php/post … … 107 135  108 136 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: 137 Find more about [scaffolding](http://www.symfony-project.org/book/1_0/14-Generators) and the explanation of symfony 138 projects [structure](http://www.symfony-project.org/book/1_0/04-The-Basics-of-Page-Creation) (project, application, 139 module). 140 141 >**Note**: In the URLs above, the name of the main script - called *front controller* in symfony - was changed from 142 >`index.php` to `frontend_dev.php`. The two scripts access the same application (`frontend`), but in different 143 >environments. With `frontend_dev.php`, you access the application in the **development environment**, which provides handy 144 >development tools like the debug toolbar on the top right of the screen and the live configuration engine. That's why the 145 >processing of each page is slower than when using `index.php`, which is the front controller of the **production 146 >environment**, optimized for speed. If you want to keep on using the production environment, replace `frontend_dev.php/` 147 >by `index.php/` in the following URLs, but don't forget to clear the cache before watching the changes: 112 148 > 113 149 > $ php symfony clear-cache … … 115 151 > http://localhost/sf_sandbox/web/index.php/ 116 152 117 Find more about [environments](http://www.symfony-project. com/book/trunk/05-Configuring-Symfony#Environments).153 Find more about [environments](http://www.symfony-project.org/book/1_0/05-Configuring-Symfony#Environments). 118 154 119 155 Modify the layout … … 145 181  146 182 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: 183 While you are at it, you can change the title of your pages. Edit the view configuration file of the application 184 (`sf_sandbox/apps/frontend/config/view.yml`), locate the line showing the `title` key and change it to: 148 185 149 186 default: … … 158 195 language: en 159 196 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: 197 The home page itself needs to be changed. It uses the default template of the `default` module, which is kept in the 198 framework but not in your application directory. To override it, you have to create a custom `main` module: 161 199 162 200 $ php symfony init-module frontend main 163 201 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: 202 By default, the `index` action shows a default congratulations screen. To remove it, edit the 203 `sf_sandbox/apps/frontend/modules/main/actions/actions.class.php` and remove the content of the `executeIndex()` method as 204 follows: 165 205 166 206 [php] … … 175 215 <p>You are the <?php echo rand(1000,5000) ?>th visitor today.</p> 176 216 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: 217 Now, you must tell symfony which action to execute when the homepage is requested. To that extend, edit the 218 `sf_sandbox/apps/frontend/config/routing.yml` and change the `homepage` rule as follows: 178 219 179 220 [yml] … … 190 231 Go ahead, start using your new web app: Create a new test post, and a test comment for your this post. 191 232 192 Find more about [views and templates](http://www.symfony-project. com/book/trunk/07-Inside-the-View-Layer).233 Find more about [views and templates](http://www.symfony-project.org/book/1_0/07-Inside-the-View-Layer). 193 234 194 235 Pass data from the action to the template 195 236 ----------------------------------------- 196 237 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: 238 That was fast, wasn't it? Now it is time to mix the `comment` module into the `post` one to get comments displayed below 239 posts. 240 241 First, you need to make the post comments available for the post display template. In symfony, this kind of logic is kept 242 in **actions**. Edit the actions file `sf_sandbox/apps/frontend/modules/post/actions/actions.class.php` and change the 243 `executeShow()` method by adding the 4 last lines: 200 244 201 245 [php] … … 211 255 } 212 256 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: 257 The `Criteria` and `-Peer` objects are part of Propel's object-relational mapping. Basically, these four lines will handle 258 a SQL query to the `Comment` table to get the comments related to the current `Post` (the one designated by the URL 259 parameter `id`). The `$this->comments` line in the action will give access to a `$comments` variable in the corresponding 260 template. Now, modify the post display template `sf_sandbox/apps/frontend/modules/post/templates/showSuccess.php` by 261 adding at the end: 214 262 215 263 [php] … … 228 276 <?php endif; ?> 229 277 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: 278 This page uses new PHP functions (`format_date()` and `simple_format_text()`) provided by symfony, and called 'helpers' 279 because they do some tasks for you that would normally require more time and code. Create a new comment for your first 280 post, then check again the first post, either by clicking on its number in the list, or by typing directly: 231 281 232 282 http://localhost/sf_sandbox/web/frontend_dev.php/post/show?id=1 … … 236 286 This is getting good. 237 287 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. 288 Find more about the [naming conventions](http://www.symfony-project.org/book/1_0/07-Inside-the-View-Layer) linking an 289 action to a template. 239 290 240 291 Add a record relative to another table 241 292 -------------------------------------- 242 293 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. 294 When adding a comment, you can choose the `id` of the related post. That's not very user-friendly. Let's change this, and 295 make sure that the user comes back to the post he was looking at after adding a comment. 244 296 245 297 First, in the still fresh `modules/post/templates/showSuccess.php` template, add a line at the bottom: … … 248 300 <?php echo link_to('Add a comment', 'comment/create?post_id='.$post->getId()) ?> 249 301 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: 302 The `link_to()` helper creates a hyperlink pointing to the `create` action of the `comment` module, so you can add a 303 comment directly from the post details page. Next, open the `modules/comment/templates/editSuccess.php` and replace the 304 following lines: 251 305 252 306 [php] … … 270 324 <?php endif; ?> 271 325 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: 326 The form in the `comment/create` page points to a `comment/update` action, which redirects to `comment/show` when 327 submitted (this is the default behaviour in generated CRUDs). For the weblog, that means that after adding a comment to a 328 post, the detail of the comment is displayed. It is better to display the post with the comments at that point. So open 329 the `modules/comment/actions/actions.class.php` and look for the `executeUpdate()` method. Note that the `created_at` 330 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 331 record is created. The final redirect of the action has to be modified to point to the correct action. Change it to: 273 332 274 333 [php] … … 298 357 Users can now add comments to a post and come back to the post afterwards. You wanted a weblog? You have a weblog. 299 358 300 Find more about [actions](http://www.symfony-project. com/book/trunk/06-Inside-the-Controller-Layer).359 Find more about [actions](http://www.symfony-project.org/book/1_0/06-Inside-the-Controller-Layer). 301 360 302 361 Form Validation 303 362 --------------- 304 363 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: 364 Visitors can enter comments, but what if they submit the form without any data in it? You will have a dirty database. To 365 avoid that, create a file called `update.yml` in the `sf_sandbox/apps/frontend/modules/comment/validate/` directory (you 366 also have to create the directory) and write in: 306 367 307 368 methods: … … 330 391 email_error: The email address is not valid. 331 392 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: 393 >**Note**: Beware that you don't copy 4 extra spaces at the beginning of each line, since the YAML parser would fail in 394 >that case. The first letter of this file must be the 'm' of 'methods'. 395 396 The `fillin` activation enables the repopulation of the form with the value previously entered by the user in case of 397 failed validation. The `names` declarations set the validation rules for each input of the form. 398 399 By itself, the controller will redirect the user to a `updateError.php` template if an error is detected. It would be 400 better to display the form again with an error message. To do that, add a `handleErrorUpdate` method to the action class 401 of the `modules/comment/actions/actions.class.php` file: 337 402 338 403 [php] … … 360 425  361 426 362 Find more about [form validation](http://www.symfony-project. com/book/trunk/10-Forms).427 Find more about [form validation](http://www.symfony-project.org/book/1_0/10-Forms). 363 428 364 429 Change the URL aspect 365 430 --------------------- 366 431 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: 432 Did you notice the way the URLs are rendered? You can make them more user and search engine-friendly. Let's use the post 433 title as an URL for posts. 434 435 The problem is that post titles can contain special characters like spaces. If you just escape them, the URL will show 436 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, 437 stripped title. To do that, edit the file `Post.php` located in the `sf_sandbox/lib/model/` directory, and add the 438 following method: 370 439 371 440 [php] … … 387 456 } 388 457 389 Now you can create a `permalink` action for the `post` module. Add the following method to the `modules/post/actions/actions.class.php`: 458 Now you can create a `permalink` action for the `post` module. Add the following method to the 459 `modules/post/actions/actions.class.php`: 390 460 391 461 [php] … … 407 477 } 408 478 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: 479 The post list can call this `permalink` action instead of the `show` one for each post. In 480 `modules/post/templates/listSuccess.php`, delete the `id` table header and cell, and change the `Title` cell from: 410 481 411 482 [php] … … 417 488 <td><?php echo link_to($post->getTitle(), 'post/permalink?title='.$post->getStrippedTitle()) ?></td> 418 489 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: 490 Just one more step: Edit the `routing.yml` located in the `sf_sandbox/apps/frontend/config/` directory and add these rules 491 at the top: 420 492 421 493 list_of_posts: … … 431 503  432 504 433 Find more about [smart URLs](http://www.symfony-project. com/book/trunk/09-Links-and-the-Routing-System).505 Find more about [smart URLs](http://www.symfony-project.org/book/1_0/09-Links-and-the-Routing-System). 434 506 435 507 Cleanup in the frontend 436 508 ----------------------- 437 509 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. 510 Well, if this is a weblog, then everybody has the right to post. This isn't exactly what you thought about, right? Ok, 511 let's clean up our templates a bit. 439 512 440 513 In the template `modules/post/templates/showSuccess.php`, get rid of the 'edit' link by removing the line: … … 460 533 ------------------------- 461 534 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): 535 For you to write posts, let's create a backend application by typing in the command line (still from the `sf_sandbox` 536 project directory): 463 537 464 538 $ php symfony init-app backend … … 466 540 $ php symfony propel-init-admin backend comment Comment 467 541 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: 542 This time, we use the [admin generator](http://www.symfony-project.org/book/1_0/14-Generators). It offers much more 543 features and customization than the very basic CRUD generator. 544 545 Just like you did for the `frontend` application, edit the layout (`apps/backend/templates/layout.php`) to add global 546 navigation: 471 547 472 548 <div id="navigation"> … … 518 594 created_at: { type: input_date_tag, params: rich=on } 519 595 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`: 596 Note that among the existing columns of the `Post` table, the admin will look for a `nb_comments`. There is no associated 597 getter yet, but it is simple to add to the `sf_sandbox/lib/model/Post.php`: 521 598 522 599 [php] … … 546 623 $ php symfony init-module backend security 547 624 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: 625 This new module will be used to handle the login form and the request. Edit the 626 `apps/backend/modules/security/templates/indexSuccess.php` to create the login form: 549 627 550 628 [php] … … 565 643 </form> 566 644 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): 645 Add the `login` action that is called by the form to the `security` module (in the 646 `apps/backend/modules/security/actions/actions.class.php` file): 568 647 569 648 [php] … … 591 670 } 592 671 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: 672 The last thing to do is to set the `security` module as the default module to handle login actions. To do that, open the 673 `apps/backend/config/settings.yml` configuration file and add: 594 674 595 675 all: … … 602 682  603 683 604 Find more about [security](http://www.symfony-project. com/book/trunk/06-Inside-the-Controller-Layer#Action%20Security).684 Find more about [security](http://www.symfony-project.org/book/1_0/06-Inside-the-Controller-Layer#Action%20Security). 605 685 606 686 Conclusion … … 612 692 backend: http://localhost/sf_sandbox/web/backend.php/ 613 693 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: 694 At this point, if you meet an error, it might be because you changed the model after some actions were put in cache (cache 695 isn't activated in the development environment). To clear the cache, simply type: 615 696 616 697 $ php symfony cc 617 698 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. 699 See, the application is fast and runs smoothly. Pretty darn cool, isn't it? Feel free to explore the code, add new 700 modules, and change the design of pages. 619 701 620 702 And don't forget to mention your working symfony applications in the symfony Wiki! doc/branches/1.0/tutorial/symfony-ajax.txt
r5695 r7362 5 5 -------- 6 6 7 Symfony has Ajax helpers that make programming an elaborate interface a piece of cake. This tutorial will show you step-by-step how to create an Ajax-powered symfony application in minutes. 7 Symfony has Ajax helpers that make programming an elaborate interface a piece of cake. This tutorial will show you 8 step-by-step how to create an Ajax-powered symfony application in minutes. 8 9 9 10 Introduction 10 11 ------------ 11 12 12 Real lazy folks that can't stand reading long documentation are advised to watch the [online screencast](http://downloads.symfony-project.com/demo/cart/cart.mov) that demonstrates exactly what is written below. 13 14 Adding items to a shopping cart in common e-commerce applications isn't very close to the actual "add to cart" metaphor, since it requires clicking an "add to cart" button, watch a new page (the shopping cart), and then go back to the shop or checkout with buttons. 15 16 Ajax allows to get closer to the cart metaphor, by enabling drag-and-drop interactions and giving immediate visual feedback, without leaving the shop. 17 18 The target application of this tutorial will be a symfony ported version of the shopping cart demo published by [script.aculo.us](http://script.aculo.us/demos/shop) in [Rails](http://www.rubyonrails.com). It uses the [prototype](http://prototype.conio.net/) JavaScript framework (bundled with symfony) and some [script.aculo.us](http://script.aculo.us/) JavaScript that is the core of the JavaScript helpers. 13 Real lazy folks that can't stand reading long documentation are advised to watch the [online 14 screencast](http://www.symfony-project.org/screencast/cart) that demonstrates exactly what is written below. 15 16 Adding items to a shopping cart in common e-commerce applications isn't very close to the actual "add to cart" metaphor, 17 since it requires clicking an "add to cart" button, watch a new page (the shopping cart), and then go back to the shop or 18 checkout with buttons. 19 20 Ajax allows to get closer to the cart metaphor, by enabling drag-and-drop interactions and giving immediate visual 21 feedback, without leaving the shop. 22 23 The target application of this tutorial will be a symfony ported version of the shopping cart demo published by 24 [script.aculo.us](http://script.aculo.us/demos/shop) in [Rails](http://www.rubyonrails.com). It uses the 25 [prototype](http://prototype.conio.net/) JavaScript framework (bundled with symfony) and some 26 [script.aculo.us](http://script.aculo.us/) JavaScript that is the core of the JavaScript helpers. 19 27 20 28 Application Setup … … 30 38 $ symfony init-module app cart 31 39 32 Setup your web server to be able to access this new application (whether using a virtual host or an alias, as described in the [web server setup](http://www.symfony-project.com/cookbook/1_0/web_server) chapter of the documentation). For this example, let's assume that this module is accessible via a localhost: 40 Setup your web server to be able to access this new application (whether using a virtual host or an alias, as described in 41 the [web server setup](http://www.symfony-project.org/cookbook/1_0/web_server) chapter of the documentation). For this 42 example, let's assume that this module is accessible via a localhost: 33 43 34 44 http://localhost/cart/ … … 36 46 Congratulations, it says. 37 47 38 Your app must have access to the symfony JavaScript libraries. If your app doesn't work, check you can access these libraries within your browser (test `http://localhost/sf/prototype/js/prototype.js` for example). If not, you have 3 different ways to fix this problem: 48 Your app must have access to the symfony JavaScript libraries. If your app doesn't work, check you can access these 49 libraries within your browser (test `http://localhost/sf/prototype/js/prototype.js` for example). If not, you have 3 50 different ways to fix this problem: 39 51 40 52 * configure Apache with the following `Alias`: … … 56 68 ------------- 57 69 58 First, you need to create a list of items to be purchased. To keep the project simple, the element list is accessed via a simple `getProducts()` method of the `cart` actions class. The shopping cart is a simple parameter of the `sfUser` object, set with the Attribute [parameter holder](http://www.symfony-project.com/content/book/page/parameter_holder.html). Modify the `sfdemo/apps/app/modules/cart/actions/actions.class.php` to: 70 First, you need to create a list of items to be purchased. To keep the project simple, the element list is accessed via a 71 simple `getProducts()` method of the `cart` actions class. The shopping cart is a simple parameter of the `sfUser` object, 72 set with the Attribute [parameter holder](http://www.symfony-project.org/book/1_0/02-Exploring-Symfony-s-Code#Parameter%20Holders). Modify 73 the `sfdemo/apps/app/modules/cart/actions/actions.class.php` to: 59 74 60 75 [php] … … 73 88 } 74 89 75 The main page of the `cart` module will contain a list of items, and a zone to drag items to. This zone is the shopping cart. So open the template `sfdemo/apps/app/modules/cart/templates/indexSuccess.php` and write in: 90 The main page of the `cart` module will contain a list of items, and a zone to drag items to. This zone is the shopping 91 cart. So open the template `sfdemo/apps/app/modules/cart/templates/indexSuccess.php` and write in: 76 92 77 93 [php] … … 98 114 </div> 99 115 100 You can see that products are shown as images. Use the images available in [this archive](http://www.symfony-project.com/downloads/demo/cart/products.tgz), and put them in the `sfdemo/web/images/` directory. In addition, part of the styling was done for you, so it is recommended that you upload [this stylesheet](http://www.symfony-project.com/downloads/demo/cart/cart.css) to the `sfdemo/web/css/` directory and add a `view.yml` in the `sfdemo/apps/app/modules/cart/config/` directory with the following content: 116 You can see that products are shown as images. Use the images available in [this 117 archive](http://www.symfony-project.org/downloads/demo/cart/products.tgz), and put them in the `sfdemo/web/images/` 118 directory. In addition, part of the styling was done for you, so it is recommended that you upload [this 119 stylesheet](http://www.symfony-project.org/downloads/demo/cart/cart.css) to the `sfdemo/web/css/` directory and add a 120 `view.yml` in the `sfdemo/apps/app/modules/cart/config/` directory with the following content: 101 121 102 122 all: … … 110 130 ----------------- 111 131 112 The cart content will change as you drag items to it. This means that the content of the cart in the template must be in an independent file. Use the `include_partial()` helper for that. The items in the shopping cart will be stored in divs with `float:left` style, so a clearing div is necessary after the container. So change the end of the `indexSuccess.php` template to: 132 The cart content will change as you drag items to it. This means that the content of the cart in the template must be in 133 an independent file. Use the `include_partial()` helper for that. The items in the shopping cart will be stored in divs 134 with `float:left` style, so a clearing div is necessary after the container. So change the end of the `indexSuccess.php` 135 template to: 113 136 114 137 [php] … … 124 147 </div> 125 148 126 The `include_partial()` helper will include a `_cart.php` file, and look for this file in the `sfdemo/apps/app/modules/cart/templates/` directory. Create it with the following content: 149 The `include_partial()` helper will include a `_cart.php` file, and look for this file in the 150 `sfdemo/apps/app/modules/cart/templates/` directory. Create it with the following content: 127 151 128 152 [php] … … 144 168 <?php endif; ?> 145 169 146 If the cart contains items, they appear as images, as many times as they are added; the quantity is be displayed after each series. 170 If the cart contains items, they appear as images, as many times as they are added; the quantity is be displayed after 171 each series. 147 172 148 173 Now watch again the shopping cart at: … … 171 196 <?php endforeach; ?> 172 197 173 This adds a 'draggable' behavior to each of the images of the list of products. The `revert` option will make images go back to their origin position when released (unless received by a receiving element). 174 175 Now, define the cart as a receiving element. You just need to define which part of the template will have to be updated when the event occurs, which action will be called for its content, and which type of draggable elements can be dragged into it. Use the `drop_receiving_elements` JavaScript helper for that: 198 This adds a 'draggable' behavior to each of the images of the list of products. The `revert` option will make images go 199 back to their origin position when released (unless received by a receiving element). 200 201 Now, define the cart as a receiving element. You just need to define which part of the template will have to be updated 202 when the event occurs, which action will be called for its content, and which type of draggable elements can be dragged 203 into it. Use the `drop_receiving_elements` JavaScript helper for that: 176 204 177 205 [php] … … 182 210 )) ?> 183 211 184 Now try again, and move the products to the cart: it works. When a draggable item is dragged to the receiving element, an XMLHTTPRequest is sent to the `add` action, and the result is displayed in the `items` div. The thing is, the `add` action of the `cart` module is not defined yet... 212 Now try again, and move the products to the cart: it works. When a draggable item is dragged to the receiving element, an 213 XMLHTTPRequest is sent to the `add` action, and the result is displayed in the `items` div. The thing is, the `add` action 214 of the `cart` module is not defined yet... 185 215 186 216 Define the Updating Action … … 210 240 This action looks for the parameter sent by the JavaScript (the id of the dragged item) and adds it to the cart. 211 241 212 The result of the `add` action will be the `addSuccess.php` template. It is a simple inclusion of the `_cart.php` partial, but this time it is necessary to pass the products as a parameter : 242 The result of the `add` action will be the `addSuccess.php` template. It is a simple inclusion of the `_cart.php` partial, 243 but this time it is necessary to pass the products as a parameter : 213 244 214 245 [php] 215 246 <?php include_partial('cart', array('products' => $products)) ?> 216 247 217 This template must not use the global layout, so edit the `view.yml` in the `sfdemo/apps/app/modules/cart/config/` directory, and write in: 248 This template must not use the global layout, so edit the `view.yml` in the `sfdemo/apps/app/modules/cart/config/` 249 directory, and write in: 218 250 219 251 addSuccess: … … 229 261 ------------------ 230 262 231 You could stop now, but this shopping cart has a big default: while the cart is updated, the interface doesn't change and the user might be disoriented. This is a general issue of asynchronous requests: an indicator zone has to be added to show that the request is being processed. In addition, nothing tells the user when the dragged item is considered accepted by the cart, so the `hover` style of the `cart` div also has to be defined. 263 You could stop now, but this shopping cart has a big default: while the cart is updated, the interface doesn't change and 264 the user might be disoriented. This is a general issue of asynchronous requests: an indicator zone has to be added to show 265 that the request is being processed. In addition, nothing tells the user when the dragged item is considered accepted by 266 the cart, so the `hover` style of the `cart` div also has to be defined. 232 267 233 268 To do that, edit the `indexSuccess.php` template and write in: … … 240 275 </div> 241 276 242 Save the 'indicator.gif' [image file](http://www.symfony-project.com/downloads/demo/cart/indicator.gif) to your `sfdemo/web/images/` directory. 243 244 Now, modify the `drop_receiving_element()` JavaScript helper call in the same template to show this new indicator while requests are processed and declare the hover style: 277 Save the 'indicator.gif' [image file](http://www.symfony-project.org/downloads/demo/cart/indicator.gif) to your 278 `sfdemo/web/images/` directory. 279 280 Now, modify the `drop_receiving_element()` JavaScript helper call in the same template to show this new indicator while 281 requests are processed and declare the hover style: 245 282 246 283 [php] … … 258 295 ---------- 259 296 260 The complete source of the demo can be [downloaded](http://www.symfony-project.com/downloads/demo/cart/project.tgz) and is available [online](http://www.symfony-project.com/demo/cart.html). You will notice a few minor differences with the code described in this tutorial (including a trash box), but the core behaviors are the same. 261 262 Until the full documentation of the JavaScript helpers is released, you can find more information about them in the [script.aculo.us documentation](http://wiki.script.aculo.us/scriptaculous/list?category=Controls). 297 The complete source of the demo can be [downloaded](http://www.symfony-project.org/downloads/demo/cart/project.tgz) and is 298 available [online](http://www.symfony-project.org/demo/cart.html). You will notice a few minor differences with the code 299 described in this tutorial (including a trash box), but the core behaviors are the same. 300 301 Until the full documentation of the JavaScript helpers is released, you can find more information about them in the 302 [script.aculo.us documentation](http://wiki.script.aculo.us/scriptaculous/list?category=Controls).