Changeset 11244
- Timestamp:
- 08/29/08 22:52:16 (3 months ago)
- Files:
-
- doc/branches/1.1/tutorial/my-first-project.txt (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
doc/branches/1.1/tutorial/my-first-project.txt
r11231 r11244 12 12 13 13 We'll assume that you are working with Apache installed and running on your 14 local host. You will also need PHP 5.1.3 or newer.14 local machine. You will also need PHP 5.1.3 or newer. 15 15 16 16 Install symfony and initialize the project … … 300 300 301 301 [php] 302 <h1>Welcome to my swellblog</h1>302 <h1>Welcome to my new blog</h1> 303 303 <p>You are the <?php echo rand(1000,5000) ?>th visitor today.</p> 304 304 … … 551 551 --------------- 552 552 553 >**Caution**554 >The following part of the tutorial refers to code that would have appeared in the 1.0555 > version of the sandbox, and has not been updated to take account of symfony 1.1. It will556 >take a while longer to convert this section. Please bear with us!557 558 553 Visitors can enter comments, but what if they submit the form without any data 559 in it? You will have a dirty database. To avoid that, create a file called 560 `update.yml` in the `sf_sandbox/apps/frontend/modules/comment/validate/` 561 directory (you also have to create the directory) and write in: 562 563 methods: 564 post: [author, email, body] 565 get: [author, email, body] 566 567 fillin: 568 enabled: on 569 570 names: 571 author: 572 required: Yes 573 required_msg: The name field cannot be left blank 574 575 email: 576 required: No 577 validators: emailValidator 578 579 body: 580 required: Yes 581 required_msg: The text field cannot be left blank 582 583 emailValidator: 584 class: sfEmailValidator 585 param: 586 email_error: The email address is not valid. 587 588 >**Note**: Beware that you don't copy 4 extra spaces at the beginning of each 589 >line, since the YAML parser would fail in that case. The first letter of this 590 >file must be the 'm' of 'methods'. 591 592 The `fillin` activation enables the repopulation of the form with the value 593 previously entered by the user in case of failed validation. The `names` declarations 594 set the validation rules for each input of the form. 595 596 By itself, the controller will redirect the user to a `updateError.php` template 597 if an error is detected. It would be better to display the form again with an 598 error message. To do that, add a `handleErrorUpdate` method to the action class 599 of the `modules/comment/actions/actions.class.php` file: 600 601 [php] 602 public function handleErrorUpdate() 603 { 604 // forward it to edit if the id exists 605 if (!$this->getRequestParameter('id')) 554 in it, or data that is obviously wrong? You would end up with a database containing 555 invalid rows. To avoid that, we need to set up some validation rules to specify what 556 data is allowed. You will recall that some default rules were set up for us already 557 during the CRUD build process, in the BaseBlogCommentForm class. We will override some 558 of these rules now. 559 560 Again, our changes go in BlogCommentForm.class.php, and not in the base class. So, 561 open that file, and add in the following PHP code at the end of the configure() method: 562 563 [php] 564 $this->validatorSchema['blog_post_id'] = new sfValidatorPropelChoice( 565 array('model' => 'BlogPost', 'column' => 'id', 'required' => true), 566 array('required' => 'This comment must have an associated post')); 567 $this->validatorSchema['author'] = new sfValidatorString( 568 array('required' => true), 569 array('required' => 'The author field cannot be left blank')); 570 $this->validatorSchema['email'] = new sfValidatorEmail( 571 array('required' => false), 572 array('invalid' => 'The email address is not valid')); 573 $this->validatorSchema['body'] = new sfValidatorString( 574 array('required' => true), 575 array('required' => 'The body field cannot be left blank')); 576 577 Each of these rows overwrites the base validator for the specified form element name 578 — the default definitions for 'blog_post_id', 'author', 'email' and 'body' are 579 effectively deleted. It is worth bearing in mind that we could equally have used the 580 syntax that was used in the base class — the setValidators() method — but 581 that method requires all validators to be specified. By doing it this alternative way, 582 we have avoided duplicating a little code. 583 584 The syntax of the validators themselves is fairly simple. As you can see, the first 585 array parameter contains a number of options, such as whether the parameter is required, 586 and the second array parameter contains message(s) to use if the validation fails. If 587 an error message is not specified, then symfony will even output a simple default 588 message instead. 589 590 Once these rules are in place, try saving a comment without an author name, a bad email 591 address, or no body text - you now have a robust form! You will notice a number of 592 things: first of all, where the form contains data, that data will automatically be 593 preserved during the form submission. This saves the user having to type it back in 594 (and normally is something in that the programmer has to arrange manually). Also, errors 595 (in this case) are placed next to the fields that failed their associated validation 596 tests. 597 598 Now would be a good time to explain a little about how the form save process works. It 599 uses the following action code, which you edited earlier in 600 `/sf_sandbox/apps/frontend/modules/comment/actions/actions.class.php`: 601 602 [php] 603 $this->form = new BlogCommentForm(BlogCommentPeer::retrieveByPk($request->getParameter('id')), $request->getParameter('post_id')); 604 605 if ($request->isMethod('post')) 606 { 607 $this->form->bind($request->getParameter('blog_comment')); 608 if ($this->form->isValid()) 606 609 { 607 $this->forward('comment', 'create'); 610 $blog_comment = $this->form->save(); 611 612 $this->redirect('post/show?id='.$blog_comment->getBlogPostId()); 608 613 } 609 else 610 { 611 $this->forward('comment', 'edit'); 612 } 613 } 614 615 Now to finish, open again the `modules/comment/templates/editSuccess.php` template 616 and insert at the top: 617 618 [php] 619 <?php if ($sf_request->hasErrors()): ?> 620 <div id="errors" style="padding:10px;"> 621 Please correct the following errors and resubmit: 622 <ul> 623 <?php foreach ($sf_request->getErrors() as $error): ?> 624 <li><?php echo $error ?></li> 625 <?php endforeach; ?> 626 </ul> 627 </div> 628 <?php endif; ?> 629 630 You now have a robust form. 614 } 615 616 After the form object is instantiated, the following happens: 617 618 * The code checks that the HTTP method is a POST operation 619 * The parameter array 'blog_comment' is retrieved. The getParameter() method detects 620 that this name is an array of values in the form, not a single value, and returns them 621 as an associative array (e.g. form element 'blog_comment[author]' is returned in an 622 array having a key of 'author') 623 * This associative array is then fed into the form using a process called *binding*, 624 in which the values are used to fill form elements in the form object. After this, the 625 values are determined to have either passed or failed the validation checks 626 * Only if the form is valid does the save go ahead, after which the page redirects 627 immediately to the show action. 631 628 632 629  633 630 634 Find more about [form validation](http://www.symfony-project.org/book/1_1/10-Forms). 635 636 Change the URL aspect 631 Find more about 632 [form validation](http://www.symfony-project.org/book/1_1/en/02-Form-Validation). 633 634 Change the URL format 637 635 --------------------- 638 636 … … 641 639 642 640 The problem is that post titles can contain special characters like spaces. 643 If you just escape them, the URL will show some ugly `%20` kind of things,644 so you'd better extend the model to add a new method to the `Post` object645 to get a clean, stripped title. To do that, edit the file ` Post.php` located641 If you just escape them, the URL will contain some ugly `%20` strings, 642 so we will extend the model to add a new method to the `BlogPost` object 643 to get a clean, stripped title. To do that, edit the file `BlogPost.php` located 646 644 in the `sf_sandbox/lib/model/` directory, and add the following method: 647 645 … … 670 668 public function executePermalink($request) 671 669 { 672 $posts = PostPeer::doSelect(new Criteria());670 $posts = BlogPostPeer::doSelect(new Criteria()); 673 671 $title = $request->getParameter('title'); 674 672 foreach ($posts as $post) … … 686 684 687 685 The post list can call this `permalink` action instead of the `show` one for 688 each post. In `modules/post/templates/ listSuccess.php`, delete the `id` table689 header and cell, and change the `Title` cell from :686 each post. In `modules/post/templates/indexSuccess.php`, delete the `id` table 687 header and cell, and change the `Title` cell from this: 690 688 691 689 [php] 692 690 <td><?php echo $post->getTitle() ?></td> 693 691 694 To a link usinga named rule we will create in a second:695 696 [php] 697 <td><?php echo link_to($ post->getTitle(), '@post?title='.$post->getStrippedTitle()) ?></td>692 to this, which uses a named rule we will create in a second: 693 694 [php] 695 <td><?php echo link_to($blog_post->getTitle(), '@post?title='.$blog_post->getStrippedTitle()) ?></td> 698 696 699 697 Just one more step: Edit the `routing.yml` located in the … … 708 706 param: { module: post, action: permalink } 709 707 710 Now navigate again in your application and watch the URLs. 708 Now navigate again in your application to see your new URLs in action. If you get an 709 error, it may be because the routing cache needs to be cleared. To do that, type the 710 following at the command line while in your sf_sandbox folder: 711 712 $ php symfony cc 711 713 712 714  … … 714 716 Find more about [smart URLs](http://www.symfony-project.org/book/1_1/09-Links-and-the-Routing-System). 715 717 716 Clean up inthe frontend717 ----------------------- 718 719 Well, if this is a blog, then everybody has the right to post.720 This isn't exactly what you thought about, right? Ok,let's clean up our718 Cleaning up the frontend 719 ------------------------ 720 721 Well, if this is meant to be a blog, then it is perhaps a little strange that everybody 722 is allowed to post! This isn't generally how blogs are meant to work, so let's clean up our 721 723 templates a bit. 722 724 … … 724 726 'edit' link by removing the line: 725 727 726 [php]727 <?php echo link_to('edit', 'post/edit?id='.$post->getId()) ?>728 <a href="<?php echo url_for('post/edit?id='.$blog_post->getId()) ?>">Edit</a> 729 728 730 729 731 Do the same for the `modules/post/templates/listSuccess.php` template and remove: 730 732 731 [php] 732 <?php echo link_to('create', 'post/create') ?> 733 734 You also have to remove the following methods from the `modules/post/actions/actions.class.php`: 735 736 * executeCreate 733 <a href="<?php echo url_for('post/edit') ?>">Create</a> 734 735 You also have to remove the following methods from `modules/post/actions/actions.class.php`: 736 737 737 * executeEdit 738 * executeUpdate739 738 * executeDelete 740 739 741 All right, readers cannot post anymore.740 This means that readers cannot post anymore, which is what we want. 742 741 743 742 Generation of the backend … … 748 747 749 748 $ php symfony generate:app backend 750 $ php symfony propel:init-admin backend post Post751 $ php symfony propel:init-admin backend comment Comment749 $ php symfony propel:init-admin backend post BlogPost 750 $ php symfony propel:init-admin backend comment BlogComment 752 751 753 752 This time, we use the [admin generator](http://www.symfony-project.org/book/1_1/14-Generators). … … 781 780 class: sfPropelAdminGenerator 782 781 param: 783 model_class: Post782 model_class: BlogPost 784 783 theme: default 785 784 fields: 786 785 title: { name: Title } 787 excerpt: { name: Ex erpt }786 excerpt: { name: Excerpt } 788 787 body: { name: Body } 789 788 nb_comments: { name: Comments } … … 806 805 created_at: { type: input_date_tag, params: rich=on } 807 806 808 Note that among the existing columns of the ` Post` table, the admin will look809 for a `nb_comments`. There is no associated getter yet, but it is simple to810 add to the `sf_sandbox/lib/model/Post.php`:807 Note that among the existing columns of the `blog_post` table, the admin will look 808 for a column (or getter method) for `nb_comments`. Since this is a generated value and 809 not a column, we can add a getter to our model (`sf_sandbox/lib/model/BlogPost.php`): 811 810 812 811 [php] 813 812 public function getNbComments() 814 813 { 815 return count($this->get Comments());816 } 817 818 Now refresh the Post administration ansee the changes:814 return count($this->getBlogComments()); 815 } 816 817 Now refresh the Post administration screen to see the changes: 819 818 820 819  … … 823 822 ------------------------------ 824 823 825 The backend can be accessed by everybody. You have to add access restriction. 826 827 In `apps/backend/modules/post/config/`, add a`security.yml` with the following content:824 Currently the backend application can be accessed by everybody. We therefore need to 825 add some access restrictions. In `apps/backend/modules/post/config/`, add a 826 file called `security.yml` with the following content: 828 827 829 828 all: 830 829 is_secure: on 831 830 832 Repeat the operation for the `comment` module. Now you can't access these modules 833 anymore unless you are logged. 834 835 But the login action doesn't exist! Ok, so you can easily add it. 836 First, create the `security` module skeleton: 831 Repeat this operation for the `comment` module. Now you can no longer access these 832 modules, unless you are logged in. However, currently the login action doesn't 833 exist! Of course, we can easily add it. To do so, create the `security` module 834 skeleton: 837 835 838 836 $ php symfony generate:module backend security 837 838 >**Caution** 839 >The following part of the tutorial refers to code that would have appeared in the 1.0 840 > version of the sandbox, and has not been updated to take account of symfony 1.1. It will 841 >take a while longer to convert this section. Please bear with us! 839 842 840 843 This new module will be used to handle the login form and the request.