TAGS :Viewed: 10 - Published at: a few seconds ago

[ Validation in Redbean PHP ]

I like the idea of using FUSE models for validation in RedbeanPHP.

My applications sometimes require accepting data through multiple sources (form, file, etc.), so putting the validation on the actual class update makes sense.

Looking at the examples on the Redbean site, the validation seems to be based on throwing an exception.

Of course, you can only throw one exception, so I am assuming I'd need to create an additional property of type "array" in my FUSE class to hold validations messages associated with individual fields.

Does anyone have any better ideas? Here's what I've been trying thus far...

<form action="" method="post">
    <p>your name: <input name="name" type="text"></p>

    <p>your email: <input name="email" type="text"></p>

    <p>your message:</p>
    <textarea name="message" id="" cols="30" rows="10"></textarea>
    <input name="send" value="send message" type="submit">
</form>

<?php

/**
 * @property $name string
 * @property $email string
 * @property $message string
 */
class Model_Comment extends RedBean_SimpleModel{
    public $invalid = array();
    public function update(){
        if(empty($this->name)) $this->invalid['name'] = "field is empty";
        if(empty($this->email)) $this->invalid['email'] = "field is empty";
        if(empty($this->message)) $this->invalid['message'] = "field is empty";
        if(count($this->invalid) > 0) throw new Exception('Validation Failed!');
    }
    public function getInvalid(){
        return $this->invalid;
    }
}

if(isset($_POST['send'])){

    $comment = R::dispense('comment');
    /* @var $comment Model_Comment */
    $comment->import($_POST,'name,email,message');

    try{
        R::store($comment);
    }
    catch(Exception $e){
        echo $e->getMessage();
        $invalid = $comment->getInvalid();
        print_r($invalid);
        exit;
    }
    echo '<p>thank you for leaving a message.</p>';
}
echo "<h2>What people said!</h2>";

$comments = R::find('comment');
/* @var $comments Model_Comment[] */

foreach($comments as $comment){
    echo "<p>{$comment->name}: {$comment->message}</p>";
}

?>

Answer 1


You can extend RedBean_SimpleModel class to add your own methods and fields to it, so it will work with all your model. Then, you can use transactions to manage your validations. It could look like this (code not tested):

class RedBean_MyCustomModel extends RedBean_SimpleModel {
  private $errors = array();
  public function error($field, $text) {
    $this->errors[$field] = $text;
  }
  public function getErrors() {
    return $this->errors;
  }
  public function update() {
    $this->errors = array(); // reset the errors array
    R::begin(); // begin transaction before the update
  }
  public function after_update() {
    if (count($this->errors) > 0) {
      R::rollback();
      throw new Exception('Validation failed');
    }
  }
}

Then, your model could look like this:

class Model_Comment extends RedBean_MyCustomModel {
    public function update(){
        parent::update();
        if(empty($this->name)) $this->error('name', 'field is empty');
        if(empty($this->email)) $this->error('name', 'field is empty');
        if(empty($this->message)) $this->error('name', 'field is empty');
    }
    public function getInvalid(){
        return $this->invalid;
    }
}