SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 26

Thread: Form Validation Class

  1. #1
    SitePoint Guru
    Join Date
    Dec 2003
    Location
    oz
    Posts
    819
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Form Validation Class

    Rather than re-invent the wheel, I was wondering if anyone already has a form validation class that they're pretty happy with and wouldn't mind if I could get a hold of.

    I'm hoping for something as generic as possible.

    Thanks for any help,
    Eli

  2. #2
    SitePoint Guru
    Join Date
    Dec 2003
    Location
    oz
    Posts
    819
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ideally, it would be completely generic so I don't have to write any more validation code.

    maybe a function like this:

    Code:
    validate(arg, string argName, int minLen, int maxLen, bool allowEmpty, 
    bool allowAlpha, bool allowDigits, string specialChars, string errCode) 
    { 
    
    }
    arg is the argument
    argName is the name for in the error message
    minLen, maxLen are self-explainitary
    allowEmpty, allowAlpha, allowDigits also self explanitary
    special chars are chars which are allowed, so might be "-_'!"

    thats alot of params tho, and looks quite ugly for an interface.
    But the only other way is to set it in objects and so will take more lines, which I would prefer not to do - cuz validation of 20 fields wil then take 80 lines instead of 20

    Any ideas?

    Eli

  3. #3
    SitePoint Wizard Chris82's Avatar
    Join Date
    Mar 2002
    Location
    Osnabrück
    Posts
    1,003
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I don't think that the function you posted would be the best idea. There have been several other attempts posted here and Selkirk has written excellent examples how it can be done.

    Rather than having one function you have a formcontroller and you assign rules for each of the form. Each formfield can have several rules. You would need to write the form and then the formcontroller. (I think)

    Have a look at the source code / examples of http://wact.sf.net to get an idea.

  4. #4
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    At the moment I looking at having validation as custom tags within a form element, so I can easilly read them using the DOM extension.

    Also another interesting angle would be to use an XSL stylesheet to validate user inputs, though unfortunately at the moment XSL-T 1.0 doesn't support Reg Exp

    Version 2.0 does of course That'd be very neat IMO, and would simplify a lot of things, removing the need for a lot of scripting as well.

    Tough luck for the time being I suppose

  5. #5
    SitePoint Addict
    Join Date
    Aug 2002
    Location
    Ottawa, Ontario, Canada
    Posts
    214
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    In another post I attached the form generation / validation library I use at work. If you search for my posts I am sure you will find it.

    Cheers,
    Keith.

  6. #6
    SitePoint Addict
    Join Date
    Apr 2002
    Posts
    330
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lazy_yogi
    Rather than re-invent the wheel, I was wondering if anyone already has a form validation class that they're pretty happy with and wouldn't mind if I could get a hold of.
    You may want to try this Forms Generation and Validation class. It is very popular and even comes with a plug-in to integrate with Smarty.
    Manuel Lemos

    Metastorage - Data object relational mapping layer generator
    PHP Classes - Free ready to use OOP components in PHP

  7. #7
    SitePoint Guru
    Join Date
    Dec 2003
    Location
    oz
    Posts
    819
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Taoism: I can't find it. If you have a link handy that'd be appreciated

    I've found what I think to be the most generic form validation, and uses more than one line per field, but still keeps the number down. Similar to pears forms class.

    You have

    Validator->addRule(field, "fieldName", "required","errorMsg")
    Validator->addRule(field, "fieldName", "digitsOnly","errorMsg")
    etc...

    Post number 8 here has an exceptional implementation of it:
    http://www.sitepoint.com/forums/show...hreadid=114185

    The interface is perfect, as is the implementation and class design and interaction. It also decouples the form creation objects from the validation. It doesn't have all the rules implemented in that post tho. I might have to do that if I can't get similar code.

  8. #8
    SitePoint Addict been's Avatar
    Join Date
    May 2002
    Location
    Gent, Belgium
    Posts
    284
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    There have been several other attempts posted here
    Guilty
    http://www.sitepoint.com/forums/show...hreadid=114185
    http://www.sitepoint.com/forums/showthread.php?t=140651

    Although the code had saved me quite some time, it wasn't as flexible as I hoped it would be and due to lack of time the development stalled a bit. This weekend I took some time, sat down and started coding unit tests for the various Rule classes.

    I can't help to mention it here, and some may find it wussy, others may find it boring, others will carry the opinion that I'm not qualified to make such a statement (rightfully so btw ), but: if you are not making writing tests a part of your regular development process, you should definitely give it a try, I'll assure you, it'll change your life (well, the development part anyway).

    Cannot recommend a library, basically because I lack the experience with any of them to tell you antything usefull about them, secondly, I'm assuming that you've already tried a few, but didn't quite like them, or they didn't quite fit into 'your way' of doing things.
    So, what I'll try to do instead is kinda sum up the steps I took during this weekend and how I came up with a design I like far better (for the moment at least), but resembles WACT so much that people will probably think I've just copied the design
    I'm hoping you'll find it somewhat more usefull than a standard 'Have you tried this class' recommendation.

    First some tips:
    1. Take a cold beer, a cup of coffe, a coke, water, chocolate, sigaret, amphetamines, grass, whatever your favorite coding drug might be.
    2. Get a haircut, seriously, if you can't see what you are coding, you're gonna be in trouble.
    3. Cats, they are supposed to be chasing mice, not p1ss in the keyboard.
    ok, think I've got the hard part covered, what rests is pure fun:

    When I started my weekend, my code was somewhere around that of what I had in the links I've mentioned in the beginning.
    First I envisioned my needs:
    What I wanted was a means of validating data syntactically in a way that it could be encapsulated, parametrized and made reusable in 'simple clear api' components.
    This data should be able to come from anywhere and be of any type.
    It should be possible to combine different validation processes and then apply them to a data collection (ex. form post).
    It should be possible to combine different validation processes and then apply them to 1 piece of elementary data (ex. validating an email list for valid email and length < 70).
    It should be possible to influence one validation part according to the value of another field in data collection.
    When some validation process failed, it should be easily made known to a human being using an application, hence the components should have a way of handling errors language-independently.
    Further more, if one validation process fails, the others should not stop.

    From the code I had, I liked the concept of the Validators and the Rules. For the main method of the Rule, I opted for "apply()" in favor of "appliesTo()", for obvious reasons. I liked the concept that you'd just call the apply() method and it returns true or false to indicate the rule did or didn't apply.
    I think the main part about my former code I that I really wasn't happy with, was the Validator, I was trying to implement validation of a collection (rules for different elements) and lists (one or more rules for 1 element), pulling the error codes out of the rules, then storing them internally for later retrieval, all in one "swift" validate() method. It just didn't work out that well and left me with awkward constructions in situations like; required fields (duhu, probably the most used validation ) and applying rules on optional input fields.

    So, started over, from scratch sort of speaking, and coded up some rule tests, at first, these tests were nothing more than (just the body of a test method):
    PHP Code:
    $r =& new LengthRule(5,10);
      
    $this->assertFalse($r->apply(''));
      
    $this->assertFalse($r->apply('123'));
      
    $this->assertTrue($r->apply('0123456789'));
     
    $this->assertFalse($r->apply('01234567890123456789')); 
    Coded a similar test for the rules I had (10 or so) and then just coded the rules until the tests ran ok.
    After those first runs, some issues popped up:
    Values gotten from a form post are strings, I might need some stronger type checking, since I will not be always validating form submissions.
    There needed to be done some refactoring on the test code, or I'd be ending up with some serious code duplication.
    As far as new code went, I was nowhere near what I had before

    But, there really is no substitute for the feeling you get when that green bar appears telling you the tests have passed.

    Then, and this is also totally credited to "SimpleTesting", I went back over my initial requirements I had set out. I took the concept of combining rules. I decided I wasn't going to leave this to the validator, but do it in the rules themselves, this way I could combine some rules together and just use that, for example to validate some column in some tabular data.
    English not being my forte, I came up with method names like "addRule()", "attachRule()", "add()", "attach()", ... but eventually I decided on "chain()", just sounded logical to me, "one chains rules together"...
    Based on those thinkings, I started on the tests: first I threw all tests in a directory group test, then I coded up 2 fake rules and defined 2 sets of valid and unvalid values in constants, wrote the apply methods to act on that, and so I had a way of testing the chaining of the rules without actually using "real" rules from the components under test.
    PHP Code:
        function testChainingOfRules()
          {
              
    $r1 =& new TestableRule1();
              
    $r2 =& new TestableRule2();
      
              
    $this->assertTrue($r1->apply(VALID_1));
              
    $this->assertFalse($r2->apply(VALID_1));
      
              
    $r1->chain($r2);
              
    $this->assertFalse($r1->apply(VALID_1));
          } 
    I should've refactored these to mocks btw

    Then, when I was coding the errr 'real' code, I stumbled across this issue:
    Since now rules should be able to be chained to eachother, each rule is responsible for applying its chained rules with the values that it gets passed.
    So I split up the actual applying of a (chained) rule in the base class:
    PHP Code:
        function apply($value)
          {
              
    $child_rules_apply true;
              if (! empty(
    $this->_rules))
              {
                 for (
    $i 0$j count($this->_rules); $i $j$i += 1)
                  {
                     if (! 
    $this->_rules[$i]->apply($value))
                      {
                         
    $child_rules_apply false;
                      }
                  }
              }
              return 
    $child_rules_apply && $this->check($value);
      
          function 
    check($value)
          {
              return 
    true;
          }
      
          } 
    This way sub classes only have to implement the check() method and have it return true or false, which seemed a far better idea than having to write the for loop everytime (duhu) or even than doing something like parent::apply()
    Also, I declared the method protected, so the basic, public api would remain clear and simple.
    I refactored the TestableRuleX classes, basically they extend Rule and implement the the check() method only. (I just hear lastcraft scream "MOCKS! you ignorant $-#!" )
    Coded 'till the tests ran green, which went in a straightforward, almost natural manner.

    Then, I felt the "return true;" in the base check() method should go, somehow, it felt "dangerous" to me to just return true by default in something like validation, it went like "suppose you forget to override it, it could have disastrous consequences" in my brain, so I substituted the return true; for an error trigger.
    PHP Code:
        function testNotImplementedError()
          {
              
    $r =& new Rule();
              
    $r->apply(VALID);
              
    $this->assertErrorPattern('/must_implement_method/');
          } 
    This triggered the need of the error handling.
    Returning true or false on application of a rule just isn't enough: components handling the error messages after validation may well not be the same that created them, they may very well not know (or even care to check for that matter) which rules have been applied (and probably rightfully so).
    Secondly, sometimes more information is needed than just true or false, ex. Applying a length/size/range rule whereby a value must be between 2 boundaries, when the validation of such a rule fails, it would be desirable if a message to the user could be relayed indicating whether the value he supplied was too small/little/low or too high/large/big, also an indication of whether or not those boundaries are considered valid must be given...

    In the previous code I had, I handled this by having the rules store their own signaled errors, later on retrieving them via a getErrors() method in the validator. That turned out not so well: Firstly, all those errors in all the rules you combine, you have to get them out again, that's a real drag, especially when one rule has to get the errors from the rules chained to it.
    Secondly, to remain reusable, the rule should have no knowledge of the context in which it is applied; suppose I have an EmailAddressRule, I could use it to validate an address in a submitted subscription form, but I could also be using it to validate 1000 email addresses from a database query result, what's more, I could be using the 2 validation processes in 1 request and since I've instantiated the rule for the form, I might as well use it for validating the list, cause I'm not instantiating 1000 EmailAddressRules, that's for sure
    Well, that's why I didn't want to store the error messages in the rule itself. I didn't know of any better solution than to just pass an object around where Rules would register their errors. I compromised api simplicity by adding a second parameter to the apply() method of a rule (the entry point of the actual start of the validation process).
    However, it appeared the gained functionality would make more then up for it: By passing different error-collecting objects, 1 rule could be used to validate unrelated data, by passing the same error collector different rules can be used to validate related data, and if no errors should be collected, I'd pull the Null.. object trick on it
    At the time I had 2 possible class names for that error collector: ErrorManager, ErrorList, since I'm not that keen on naming objects managers (all of a sudden, your code is nothing but managers, and we all know that when you've got too many managers, things are really going down the drain ) I decided on ErrorList, but as I'm writing this, I'm more thinking on the lines of ValidationErrorCollector, although I might drop the "Validation" part on grounds of exessive typing work, which I reckon is not really a valid reason.

    This had of course its implications on the tests and code. This is also where I first implemented a mock and have experienced the wonderful joy they bring to testing...
    This is also where WACT comes into the picture:
    In coding my own collection of reusable components, I've looked at WACT for 2 distinct things: The way WACT is actually loaded, and the way it does the error handling.
    I personally quite like the way error handling goes in PHP to a certain extend, however, I think it's too limited if you want to trigger some more info regarding an error, especially in a multi-langual situation. I've been resorting to things like errormessage files in php (global array or defines), flat text datafiles, hardcoded messages with slight variations for each situation (a mess), $err =& new Error(...); trigger_error(serialize($err)); ... and so on.

    From what I've experienced in that area, I've found the WACT implementation a very decent compromise. And so I integrated a similar way of error handling and loading global behavior into my code collection.

    Since the Error class definition is already known from loading 'the framework' I thought I'd use that for validation errors. Still I wanted the code of the rules to be simple (they should not be creating new error objects and then add them to the passed error list). Ideally, they'd do something like errorList->addError('value_too_small', array('min' => $this->_min))

    I decided to encapsulate the adding of errors to the list in a base method, since I hadn't actually written any code for an "ErrorList", chances would be high its interface changed, this way I only would have to change 1 method in the base class if that actually would happen. Basically this was the setError() method I had before, but since it really didn't set an error, nor added at an error (it signaled an error), I called it plain and simple error()

    Time had come to code on the test. First of I code up a mock, like this:
    PHP Code:
    class ErrorList
      
    {
          var 
    $_errors = array();
      
          function 
    ErrorList()
          {
          }
      
          function 
    addError($group$id$info)
          {
              
    $this->_errors[] =& new Error($group$id$info);
          }
      }
     
    Mock::generate('ErrorList'); 
    Then I wrote up a base RuleTestCase where other rule tests should extend from, in which I implemented the setup and tearDown methods to create a new clean ErrorList every time a test method ran:
    PHP Code:
    SimpleTestOptions::ignore('RuleTestCase');
      class 
    RuleTestCase extends UnitTestCase
      
    {
          var 
    $errorList;
      
          function 
    setUp()
          {
              
    $this->errorList =& new MockErrorList($this);
          }
          function 
    tearDown()
          {
              
    $this->errorList->tally();
          }
     } 
    This made it so much easier to write the tests to check if the rules were signaling the correct error codes:
    PHP Code:
    class LengthRuleTest extends RuleTestCase {
          function 
    LengthRuleTest() {
              
    $this->UnitTestCase('LengthRule');
          }
      
          function 
    testCreationWithTwoParameter() {
              
    $this->errorList->expectCallCount('addError'3);
              
    $this->errorList->expectArgumentsAt(
                  
    0'addError',
                 array(
    'validation''charlength_too_small', array('min' => 5))
              );
              
    $this->errorList->expectArgumentsAt(
                  
    1'addError',
                 array(
    'validation''charlength_too_small', array('min' => 5))
              );
              
    $this->errorList->expectArgumentsAt(
                  
    2'addError',
                 array(
    'validation''charlength_too_big', array('max' => 10))
              );
              
    $r =& new LengthRule(5,10);
              
    $this->assertFalse($r->apply(''$this->errorList));
              
    $this->assertFalse($r->apply('123'$this->errorList));
              
    $this->assertTrue($r->apply('0123456789'$this->errorList));
             
    $this->assertFalse($r->apply('01234567890123456789'$this->errorList));
          }
      
          function 
    testExactLength() {
              
    $this->errorList->expectCallCount('addError'2);
              
    $this->errorList->expectArgumentsAt(
                  
    0'addError',
                 array(
    'validation''charlength_not_exact', array('length' => 5))
              );
              
    $this->errorList->expectArgumentsAt(
                  
    1'addError',
                 array(
    'validation''charlength_not_exact', array('length' => 5))
              );
              
    $r =& new LengthRule(5,5);
              
    $this->assertTrue($r->apply('12345'$this->errorList));
              
    $this->assertFalse($r->apply('1234'$this->errorList));
              
    $this->assertFalse($r->apply('123456'$this->errorList));
          }
          
    //...
      

    Once again, writing the actual code went straightforward and without any hassles worth mentioning.

    At the moment, I have all the tests for the rules that I had, and the rules themselves.
    I've not started writing test code for the validator yet.
    It's weird that, by copying the error handling from WACT, my rule system has almost turned out exactly the same way. WACT's system however is far more evolved, also it's implemented differently because of the DataSpace SuperLayerType, if I'm not mistaking.

    Now, for the validator, I've not quite decided yet, in another thread someone uttered the name "firewall", kinda like that actually.
    I'm also thinking: filters, it's like rules, you apply them, maybe I build a firewall, whereby one registers filters and rules (what's the collective name for such things? FirewallRules? FireFilterAndRuleWall ? )

    But I think that'll be for another free weekend, I've waisted enough valuable forum space as it is, truly sorry, just felt like sharing this ...

    As a report: I estimated the time spend on it (rewrite/factor the original code to something more uselfull) around 20-25 hours, it took me around 25-30 (including test code and writing up error messages (1 language only))
    The original functionality exists, the api is simpler and cleaner, and the rule has become more flexible because of the elimination of the errorcide storage.

    Most "php masters" out here are probably laughing at those figures and results, but given the fact that these are my first steps in "SimpleTesting" and that I'm truly happy about the design so far, I'm supprised it only took that long really.

    And, I know I'm kinda late, but much much MUCH respect to lastcraft: You have created such an incredible tool, I don't think I ever got this excited about PHP development, not even the first time I read a voostind post

    EDIT 20040401: changed some initial test code, that I'd copypasted from a wrong version..
    Last edited by been; Apr 1, 2004 at 04:50.
    Per
    Everything
    works on a PowerPoint slide

  9. #9
    SitePoint Member
    Join Date
    Apr 2004
    Location
    Guangzhou, GD, China
    Posts
    13
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    PEAR - HTML_QuickForm

    I suggest you stick to the PEAR packages.

    I spent two years chaisng good code and also writing alot of my own code spending precious parts of my life debugging code that has already been written so many times by every one else.

    Looking at pear at the beginning is quite a daunting sight but if you spend the time to learn it will save you months in developing time in the future.

    A good example is here http://www.thelinuxconsultancy.co.uk/quickform.html

    If you want a head start grab a copy of Harrys new books PHP Anthology. These books took me from writing procedural (bug ridden) code to writing good solid applications.

    I now look to PEAR every time.

  10. #10
    SitePoint Guru
    Join Date
    Dec 2003
    Location
    oz
    Posts
    819
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Great post been.

    Yeh, test driven development is definitely the way to go. I find I catch alot of possible bugs doing it that way that I wouldn't have found otherwise.

    I really like ur interface because of the cleverly simple design. It's similar to pear's, but uses classes implemented for each rule rather passing another param. I don't think it needs to be too much more complex, but of course that's for you to decide.

    Thanks so much for all your help, and letting us know about your experiences on this.

    Eli

  11. #11
    SitePoint Guru
    Join Date
    Dec 2003
    Location
    oz
    Posts
    819
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hey Been, I'm thinking of creating the following Rule Classes:

    Required
    MinLength(min)
    MaxLength(max)
    RangeLength(min,max)
    OnlyAlpha : Regex
    NoAlpha : Regex
    OnlyNumeric : Regex
    NoNumeric : Regex
    OnlyAlphaNumeric : Regex
    NoPunctuation : Regex
    Email : Regex
    Date : Regex - "^\d{4}\-\d{2}\-\d{2}$"
    Time : Regex - "^\d{2}\:\2{2}$"
    Phone : Regex - "^\d{2,}[\-\d{2,}]*$"
    Equal(cmp_item)
    NotEqual(cmp_item)
    InList(list)

    Any comments, redundancy, missing classes?

  12. #12
    SitePoint Enthusiast NativeMind's Avatar
    Join Date
    Aug 2003
    Location
    USA
    Posts
    80
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    How does QuickForm work with Smarty (if at all)

  13. #13
    SitePoint Member
    Join Date
    Aug 2003
    Location
    Tolono
    Posts
    5
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here is a article I found on using Smarty with Quickform.
    http://www.thelinuxconsultancy.co.uk/smarty-guide.html

  14. #14
    SitePoint Enthusiast
    Join Date
    Mar 2004
    Location
    Bakersfield, CA
    Posts
    25
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I used this once. Not sure if this is what you are looking for or not.

    http://www.x-code.com/vdaemon_web_form_validation.php

  15. #15
    SitePoint Guru
    Join Date
    Dec 2003
    Location
    oz
    Posts
    819
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ahh interesting blockcipher. Thanks for the link.

    Tho, I'm using it in another language, and for a non-browser based application, and want something that I can use there.

    Eli

  16. #16
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Any comments, redundancy, missing classes?
    Not sure, I'm still trying to get some idea's on how to do this myself ?

    I'm thinking that if I have each FORM as an XML file, I could use the DOM - or better yet, XPATH - to manipulate this file, for example to append an error message dynamically to the file before it's transformed ?

    But I'm having some bother with layering. For example, should the error reporting parts could be seen as being presentation ?

    A Controller (not directly of course) would handle the user inputs, and putting the XML file to the View, though if the View handles the error reporting, how'd the best method be to alert the View to the bad user inputs ?

    As to what rules for validation, personally I cannot see how you'd need a MaxLength, since there is a tag just for this purpose.

  17. #17
    SitePoint Guru
    Join Date
    Dec 2003
    Location
    oz
    Posts
    819
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Widow Maker
    But I'm having some bother with layering. For example, should the error reporting parts could be seen as being presentation ?

    A Controller (not directly of course) would handle the user inputs, and putting the XML file to the View, though if the View handles the error reporting, how'd the best method be to alert the View to the bad user inputs ?
    Front end validation (ie javascript) would alert the user via java alert (popup) box. Back end validation allerts the user via a message on the page added to the page by the server page.
    Both front and back end validation have their advantages and disadvantages.

    Quote Originally Posted by Widow Maker
    As to what rules for validation, personally I cannot see how you'd need a MaxLength, since there is a tag just for this purpose.
    What tag are you talking about? I have no idea what tags you are refering to since I'm talking about validation classes.

    Eli

  18. #18
    Non-Member
    Join Date
    Jan 2004
    Location
    Planet Earth
    Posts
    1,764
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Back end validation allerts the user via a message on the page added to the page by the server page.
    Obviously

    I was meaning should the Form Processor add the message, or the View add the message

    As to the tag I was talking about, it's an attribute - should have been more clearer on this point - sorry

    Building up some notes, I'm thinking I could build a form on the fly, and leave it that.

    An XSL stylesheet could I suppose add in a generic message based on an attribute to act a flag within any given form element which has bad input from user - one way of doing it I suppose

  19. #19
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Widow Maker
    But I'm having some bother with layering. For example, should the error reporting parts could be seen as being presentation ?
    I think validation for forms is definitely two stage. One for detecting errors. Another for presenting them. The WACT design jumps through a lot of hoops to make sure these are separate stages. Including allowing validation error messages to be defined independently of the validation rule (which allows i18n or customization of validation error messages)

    Quote Originally Posted by Widow Maker
    As to what rules for validation, personally I cannot see how you'd need a MaxLength, since there is a tag just for this purpose.
    the MAXLENGTH attribute is client side. You going to trust that incoming data from the client?

  20. #20
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by been
    It's weird that, by copying the error handling from WACT, my rule system has almost turned out exactly the same way. WACT's system however is far more evolved, also it's implemented differently because of the DataSpace SuperLayerType, if I'm not mistaking.
    May I ask why you didn't just take the validation layer out of WACT as is? The reason I ask is that I notice alot of people using WACT throw away this part and re-implement it themselves. Which leads me to believe there is something fundamentally wrong with it. I have some ideas what that might be, but I am interested in hearing some feedback.

  21. #21
    SitePoint Addict
    Join Date
    Apr 2002
    Posts
    330
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Selkirk
    the MAXLENGTH attribute is client side. You going to trust that incoming data from the client?
    The length limit is not a validation rule but rather a constraint, which is a different thing.

    Since in normal conditions a browser would never submit a field value that has more characters then the MAXLENGTH, if a script gets more characters than it should, that maybe a buffer overflow attack.

    What a forms processing script should do is to discard the exceeding characters. That is at least what this forms class does automatically when the MAXLENGTH attribute is specified. Most databases also discard exceeding characters.
    Manuel Lemos

    Metastorage - Data object relational mapping layer generator
    PHP Classes - Free ready to use OOP components in PHP

  22. #22
    SitePoint Zealot
    Join Date
    Mar 2004
    Location
    New Jersey
    Posts
    140
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Always spamming your classes and your site, are you? Time to dig up some old threads on the php-dev mailing list.

  23. #23
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by plugged
    Always spamming your classes and your site, are you? Time to dig up some old threads on the php-dev mailing list.
    Take it easy mate, manuel is making a valid argument here, even if we don't agree with it. But that is no justification for an ad hominem attack.

  24. #24
    SitePoint Addict been's Avatar
    Join Date
    May 2002
    Location
    Gent, Belgium
    Posts
    284
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Selkirk
    May I ask why you didn't just take the validation layer out of WACT as is?
    (stupid) Pride, (stupid) vanity and (some) respect for other people's work.

    I already had half a validation system, and wanted to build from there.

    Think one of the biggest differences in both validation systems are the way Rules and the Validator interact (other than WACT's already a system and mine is just an attempt ):
    WACT's rules (the SingleFieldRules) are used to validate a collection of data, a rule will only validate that part of the collection it was set out to validate. This means that the data collection to validate can be passed as a whole to the validating method of the rule.

    In the rule system I've implemented (so far), 1 rule is applied to a single value (which could be an array), meaning that the necessary value has to be "taken out" of the data collection and then be passed to the validating method of the rule.

    Both implementations need to have a system so it can be determined which rule should apply to which part of the datacollection.
    WACT does this by storing a fieldname in the rule and comparing DataSpace keynames. (Determined at rule level)

    My intention is to do this by registering a keyname with the validator when registering a rule, so you'd register a certain rule for a certain key. (Determined at validator level)
    It seemed to me that by taking out the fieldname dependency in the rules, you could use them to validate other datastructures then key-based ones like associative arrays or DataSpaces.

    Mind you, I've never actually used WACT (I've browsed quite a bit through the code and online docs), so I'm not sure if I can tell you anything usefull about why people take out the validation part and implement their own.
    Random things that come to mind:

    - The aforementioned field name dependency, maybe making the rules not generic enough? Say you have a long list of email addresses and an EmailAddressRule of some kind; Validating this in WACT should need a little workaround converting the email addresses from the list into a DataSpace, no? Still, since DataSpace is somewhat the primary type in WACT, I reckon this shouldn't be really an obstacle?

    - Extending the rules by using inheritance isn't as intuitive as it maybe should be? (Because of the different error id's of parent and child: If not taken care for, the parent will add it's error to the ErrorList before the child does, trying to find an elegant solution to this myself.)

    - Maybe the documentation isn't clear enough?

    - People don't like the api? Although, from what I looked at, can't really see what could be wrong with it, as far as interface goes.

    One thing that caught my attention is how differently Rules and Filters are used: Filters are registered with a DataSpace, whereas rules rather "work on" a DataSpace. Could have a wrong perspective here on things, but other than that a rule leaves data unmodified and a filter changes it, I don't see much difference in the use of both.

    On that issue, here's a something that keeps on popping up in my head lately:
    PHP arrays are quite flexible, in WACT a DataSpace is used as a container for key/value pairs.
    My intention is to stick to PHP arrays for that, and implement Filters the same way as Rules, both would then apply() to a value.

    But, I'm also well aware of the fact that the collective knowledge of the whole WACT team exceeds mine by a multitude of times, so there are probably some things I haven't quite thought through or simply didn't notice, maybe you could post your main reasons why WACT doesn't use the PHP array as the SuperLayerType, if it's not asked too much?

    Quote Originally Posted by Selkirk
    ..., but I am interested in hearing some feedback.
    Well, it wasn't much, still I hope it can be of some use.




    Quote Originally Posted by lazy_yogi
    I'm thinking of creating the following Rule Classes:
    I'd say, go with the flow; have your base classes ready and under test, then code up the tests and the rules as you go along: everytime you need validation, re-evaluate your rules and code up those that you need, refactoring as you go along.
    I'm thinking that only then you can end up with a decent, usable system with a nice collection of rules covering most validation needs. As Joel Spolsky said: "Good software takes 10 years, get used to it"

    On the Min- Max- and RangeLength rules: Think you can throw them together in 1 class, checking the method argument count on construction (or have an optional argument) to set the minimum and maximum range.

    On the No* and Only* rules: Maybe this could be solved with a generic Negation/InvertionRule ? Not sure on this one.
    Per
    Everything
    works on a PowerPoint slide

  25. #25
    SitePoint Guru
    Join Date
    Nov 2002
    Posts
    841
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by been
    WACT's rules (the SingleFieldRules) are used to validate a collection of data, a rule will only validate that part of the collection it was set out to validate. This means that the data collection to validate can be passed as a whole to the validating method of the rule.

    In the rule system I've implemented (so far), 1 rule is applied to a single value (which could be an array), meaning that the necessary value has to be "taken out" of the data collection and then be passed to the validating method of the rule.

    Both implementations need to have a system so it can be determined which rule should apply to which part of the datacollection.
    WACT does this by storing a fieldname in the rule and comparing DataSpace keynames. (Determined at rule level)

    My intention is to do this by registering a keyname with the validator when registering a rule, so you'd register a certain rule for a certain key. (Determined at validator level)
    It seemed to me that by taking out the fieldname dependency in the rules, you could use them to validate other datastructures then key-based ones like associative arrays or DataSpaces.
    I see. The WACT validation system is dependent on the DataSpace structure. I can see where not everyone would be interested in using this structure. I have been putting some thoughts into revamping DataSpace to make it more obviously useful.

    On reason for using DataSpace is to be able to validate multiple related values, such as comparing two passwords to see if they are equal. There are other multi-field validations, such as determining a valid date based on month day and year. For example Feb 29 cannot be determined as a valid date without knowing the year.

    Associative arrays are easily converted into DataSpaces, although perhaps objects are not. I see the distinction about a non-dataspace based validator being more flexible. With WACT, DataSpaces are all over, but to use the WACT validator without the rest of WACT you can hardly do so if you eschew DataSpace.

    Quote Originally Posted by been
    Extending the rules by using inheritance isn't as intuitive as it maybe should be? (Because of the different error id's of parent and child: If not taken care for, the parent will add it's error to the ErrorList before the child does, trying to find an elegant solution to this myself.)
    I haven't seen anyone do this, but one way around this is not to inherit rules, but to chain them. There is no reason why one rule cannot be registered as a sub-rule of another. That way, that rule is only triggered if the first rule allows it, solving the "error cascade" issue.

    Quote Originally Posted by been
    Ouch. So true.

    Quote Originally Posted by been
    One thing that caught my attention is how differently Rules and Filters are used: Filters are registered with a DataSpace, whereas rules rather "work on" a DataSpace. Could have a wrong perspective here on things, but other than that a rule leaves data unmodified and a filter changes it, I don't see much difference in the use of both.
    ..
    My intention is to stick to PHP arrays for that, and implement Filters the same way as Rules, both would then apply() to a value.
    This is an area which I have been looking at. There is an experimental new DataSpace checked into CVS that has the concept of filters and calculated fields. The issue is that we must be able to access the orginal value as well as the "filtered" value.

    For example, lets say you want to trim spaces from input values. The trimming should be done pre-validation. The post-filtering values should be used in application calculations. However, when it is time to output the values back to the user, it would be inappropriate to write back the processed values. we always want to echo back to the user in the input fields exactly what they typed. This is more important for less trivial transformations than trim.

    Without having a buffer area, you cannot do this. This is the purpose of the DataSpace and I have been changing it more toward this view. I have also been looking for a better name for it.

    Interestingly, there is another place where this dual representation occurs and that is in the Data access layer. Internally, an application may interpret a value as a boolean, but in the database it might be stored as a character, or an integer, or even a boolean representation. The same buffering/conversion capabilities for input are applicable in a database abstraction layer.

    The WACT database abstraction layer also uses DataSpace, but does not take advantage of its capabilities as this type of buffer (yet).

    The DataSpace in WACT is very similiar to the (also) horribly named ActionForm class in struts.

    A few future plans for the validation architecture in WACT includes the ability to validate arrays stored in a DataSpace. This would occur when using tables in forms with array syntax: <input name="fieldname[]">. A length validation rule for this field could then be bound to fieldname[] and the validation rule would know how to apply this to every value of the array, not just a single value, and the error reporting structure would also know how to report these kinds of errors.

    Another future plan is to be able to automatically create some of the validation rules directly from the database structure. Is the fact that you name field must be less that 30 characters a real requirement, or just an artificial requirement imposed by your database implementation?

    WACT already uses the validation rules to generate "client" side validation. Currently, the only client side validation generated is to fill in the maxlength fields on input components. Whatever maxlength is defined in the template is overridden by the value defined in the validation rules. other "client" side validation capabilities are possible, but unimplemented, such as javascript or xforms.

    Put this together with database rule generation and it should be possible to simply change the length of fields in the database and have that constraint propagate all the way through to the generated HTML.

    Thank you for the in-depth reply.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •