Question

The validation on Kohana ORM is done using rules

function rules()
{
  return array(
    'username' => array(
      array('not_empty'),
      array(array($this, 'availability')),
    )
  );
}

I'm struggling to validate a JSON encoded column using $_serialize_columns.

class Model_Admin extends ORM {
  protected $_belongs_to = array();
  protected $_has_many = array(
    'plans' => array(),
    'groups' => array(),
    'transactions' => array(),
    'logins' => array()
  );

  protected $_serialize_columns = array('data');

  /**
   * @param array $data
   * @param Validation $validation
   *
   * @return bool
   */
  public function data($data, $validation)
  {
     return 
       Validation::factory(json_decode($data, TRUE))
       // ... rules ...
       ->check();
  }

  public function rules()
  {
     return array(
       'data' => array(
         array(array($this, 'data'), array(':value',':validation')
       )
     );
  }
}

the array that gets encoded is:

array(
  'name' => '',
  'address' => '',
  'phone' => '',
  'postalcode' => ''
);

the data method receives the json encoded data, because the ORM runs the filters before doing the validation, so I need to convert it back to an associative array, then create a new validation object to check specifically for the content of that array. Because I can't merge Validation rules from another Validation instance

Was it helpful?

Solution

Updated Answer

The use of a second validation object is necessary since save() causes the internal model validation object to be checked. This means that rules added to the validation object being checked from a validation rule will be ignored (Validation->check() imports the rules into local scope before looping).

Since the data itself is technically another object (in the sense of object relationships, it has its own dataset that needs validation) the ideal solution would be to find a way to create a real model that saves the data.

There are numerous other benefits to saving data with proper database column definitions, not least if you need to perform data property lookups, make in-situ changes etc. (which would otherwise require unserializing the data column, potetnailly in all rows).

There are some alternatives, but they feel like kludges to me:

  1. Create a model that represents the data object and add rules to it, using check() to validate the data (problem: will require a lot of maintenance, no real-world table means columns must be manually defined).

  2. Set the data as real columns in the Admin model, and use a filter that will convert it into the data column on set (problem: again, must manually define the columns and exclude the additional columns from the save operation).

I hope this is of some use.

Original Answer

The Kohana ORM save() method permits the inclusion of an "extra" validation object, which is merged into the main ORM validation object namespace.

This is documented briefly here.

If I have understood correctly, I think you are looking to do something like this:

// another script, e.g., a controller

// Create the model
$admin = ORM::factory('Admin');

// $data = the data as an array, before serialization ...

$extra_validation = Validation::factory($data)
                    // add ->rule() calls here, but DO NOT chain ->check()
                    ;

// Set $data in the model if it is going to be saved, e.g., $admin->data = $data;
// Set other data... e.g., $admin->foo = 'bar';

// Save the model
try {
    $admin->save($extra_validation);
}
catch (ORM_Validation_Exception $e)
{
    // Manipulate the exception result
}

While in this example you must still create another validation object, you are now able to catch all exceptions in a single block. I would recommend using var_dump() or similar on $e->errors() to check the namespace if you are using i18n messages to provide a human-readable error message. You should find that a namespace called "_external" has been created in the response.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top