Development

Changeset 11244

You must first sign up to be able to contribute.

Changeset 11244

Show
Ignore:
Timestamp:
08/29/08 22:52:16 (3 months ago)
Author:
halfer
Message:

Fixed validation, some admin generator things, plus misc code and text

Files:

Legend:

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

    r11231 r11244  
    1212 
    1313We'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. 
     14local machine. You will also need PHP 5.1.3 or newer. 
    1515 
    1616Install symfony and initialize the project 
     
    300300 
    301301    [php] 
    302     <h1>Welcome to my swell blog</h1> 
     302    <h1>Welcome to my new blog</h1> 
    303303    <p>You are the <?php echo rand(1000,5000) ?>th visitor today.</p> 
    304304 
     
    551551--------------- 
    552552 
    553 >**Caution** 
    554 >The following part of the tutorial refers to code that would have appeared in the 1.0 
    555 > version of the sandbox, and has not been updated to take account of symfony 1.1. It will 
    556 >take a while longer to convert this section. Please bear with us! 
    557  
    558553Visitors 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')) 
     554in it, or data that is obviously wrong? You would end up with a database containing 
     555invalid rows. To avoid that, we need to set up some validation rules to specify what 
     556data is allowed. You will recall that some default rules were set up for us already 
     557during the CRUD build process, in the BaseBlogCommentForm class. We will override some 
     558of these rules now. 
     559 
     560Again, our changes go in BlogCommentForm.class.php, and not in the base class. So, 
     561open 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 
     577Each of these rows overwrites the base validator for the specified form element name 
     578&mdash; the default definitions for 'blog_post_id', 'author', 'email' and 'body' are 
     579effectively deleted. It is worth bearing in mind that we could equally have used the 
     580syntax that was used in the base class &mdash; the setValidators() method &mdash; but 
     581that method requires all validators to be specified. By doing it this alternative way, 
     582we have avoided duplicating a little code. 
     583 
     584The syntax of the validators themselves is fairly simple. As you can see, the first 
     585array parameter contains a number of options, such as whether the parameter is required, 
     586and the second array parameter contains message(s) to use if the validation fails. If 
     587an error message is not specified, then symfony will even output a simple default 
     588message instead. 
     589 
     590Once these rules are in place, try saving a comment without an author name, a bad email 
     591address, or no body text - you now have a robust form! You will notice a number of 
     592things: first of all, where the form contains data, that data will automatically be 
     593preserved 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 
     596tests. 
     597 
     598Now would be a good time to explain a little about how the form save process works. It 
     599uses 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()) 
    606609      { 
    607         $this->forward('comment', 'create'); 
     610        $blog_comment = $this->form->save(); 
     611 
     612        $this->redirect('post/show?id='.$blog_comment->getBlogPostId()); 
    608613      } 
    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 
     616After 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 
     620that this name is an array of values in the form, not a single value, and returns them 
     621as an associative array (e.g. form element 'blog_comment[author]' is returned in an 
     622array having a key of 'author') 
     623*   This associative array is then fed into the form using a process called *binding*, 
     624in which the values are used to fill form elements in the form object. After this, the 
     625values 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 
     627immediately to the show action. 
    631628 
    632629![Form validation](/images/tutorials/first_form_validation.gif) 
    633630 
    634 Find more about [form validation](http://www.symfony-project.org/book/1_1/10-Forms). 
    635  
    636 Change the URL aspect 
     631Find more about 
     632[form validation](http://www.symfony-project.org/book/1_1/en/02-Form-Validation). 
     633 
     634Change the URL format 
    637635--------------------- 
    638636 
     
    641639 
    642640The 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` object 
    645 to get a clean, stripped title. To do that, edit the file `Post.php` located 
     641If you just escape them, the URL will contain some ugly `%20` strings, 
     642so we will extend the model to add a new method to the `BlogPost` object 
     643to get a clean, stripped title. To do that, edit the file `BlogPost.php` located 
    646644in the `sf_sandbox/lib/model/` directory, and add the following method: 
    647645 
     
    670668    public function executePermalink($request) 
    671669    { 
    672       $posts = PostPeer::doSelect(new Criteria()); 
     670      $posts = BlogPostPeer::doSelect(new Criteria()); 
    673671      $title = $request->getParameter('title'); 
    674672      foreach ($posts as $post) 
     
    686684 
    687685The 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` table 
    689 header and cell, and change the `Title` cell from
     686each post. In `modules/post/templates/indexSuccess.php`, delete the `id` table 
     687header and cell, and change the `Title` cell from this
    690688 
    691689    [php] 
    692690    <td><?php echo $post->getTitle() ?></td> 
    693691 
    694 To a link using a named rule we will create in a second: 
    695  
    696     [php] 
    697     <td><?php echo link_to($post->getTitle(), '@post?title='.$post->getStrippedTitle()) ?></td> 
     692to 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> 
    698696 
    699697Just one more step: Edit the `routing.yml` located in the 
     
    708706      param: { module: post, action: permalink } 
    709707 
    710 Now navigate again in your application and watch the URLs. 
     708Now navigate again in your application to see your new URLs in action. If you get an 
     709error, it may be because the routing cache needs to be cleared. To do that, type the 
     710following at the command line while in your sf_sandbox folder: 
     711 
     712    $ php symfony cc 
    711713 
    712714![Routed URLs](/images/tutorials/first_routing.gif) 
     
    714716Find more about [smart URLs](http://www.symfony-project.org/book/1_1/09-Links-and-the-Routing-System). 
    715717 
    716 Cleanup in the frontend 
    717 ----------------------- 
    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 our 
     718Cleaning up the frontend 
     719------------------------ 
     720 
     721Well, if this is meant to be a blog, then it is perhaps a little strange that everybody 
     722is allowed to post! This isn't generally how blogs are meant to work, so let's clean up our 
    721723templates a bit. 
    722724 
     
    724726'edit' link by removing the line: 
    725727 
    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    &nbsp; 
    728730 
    729731Do the same for the `modules/post/templates/listSuccess.php` template and remove: 
    730732 
    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 
     735You also have to remove the following methods from `modules/post/actions/actions.class.php`: 
     736 
    737737    * executeEdit 
    738     * executeUpdate 
    739738    * executeDelete 
    740739 
    741 All right, readers cannot post anymore
     740This means that readers cannot post anymore, which is what we want
    742741 
    743742Generation of the backend 
     
    748747 
    749748    $ php symfony generate:app backend 
    750     $ php symfony propel:init-admin backend post Post 
    751     $ php symfony propel:init-admin backend comment Comment 
     749    $ php symfony propel:init-admin backend post BlogPost 
     750    $ php symfony propel:init-admin backend comment BlogComment 
    752751 
    753752This time, we use the [admin generator](http://www.symfony-project.org/book/1_1/14-Generators). 
     
    781780      class:              sfPropelAdminGenerator 
    782781      param: 
    783         model_class:      Post 
     782        model_class:      BlogPost 
    784783        theme:            default 
    785784        fields: 
    786785          title:          { name: Title } 
    787           excerpt:        { name: Exerpt } 
     786          excerpt:        { name: Excerpt } 
    788787          body:           { name: Body } 
    789788          nb_comments:    { name: Comments } 
     
    806805            created_at:   { type: input_date_tag, params: rich=on } 
    807806 
    808 Note that among the existing columns of the `Post` table, the admin will look 
    809 for a `nb_comments`. There is no associated getter yet, but it is simple to 
    810 add to the `sf_sandbox/lib/model/Post.php`
     807Note that among the existing columns of the `blog_post` table, the admin will look 
     808for a column (or getter method) for `nb_comments`. Since this is a generated value and 
     809not a column, we can add a getter to our model (`sf_sandbox/lib/model/BlogPost.php`)
    811810 
    812811    [php] 
    813812    public function getNbComments() 
    814813    { 
    815       return count($this->getComments()); 
    816     } 
    817  
    818 Now refresh the Post administration an see the changes: 
     814      return count($this->getBlogComments()); 
     815    } 
     816 
     817Now refresh the Post administration screen to see the changes: 
    819818 
    820819![customized generated admin](/images/tutorials/first_custom_admin.gif) 
     
    823822------------------------------ 
    824823 
    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: 
     824Currently the backend application can be accessed by everybody. We therefore need to 
     825add some access restrictions. In `apps/backend/modules/post/config/`, add a 
     826file called `security.yml` with the following content: 
    828827 
    829828    all: 
    830829      is_secure: on 
    831830 
    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: 
     831Repeat this operation for the `comment` module. Now you can no longer access these 
     832modules, unless you are logged in. However, currently the login action doesn't 
     833exist! Of course, we can easily add it. To do so, create the `security` module 
     834skeleton: 
    837835 
    838836    $ 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! 
    839842 
    840843This new module will be used to handle the login form and the request.