2
\$\begingroup\$

I've developed a crud "helper" of sorts. Fields/columns are derived from the database and contain everything from the name of the field to the type and size of the field. Part of the system integrates CodeIgniter's form validation library. In the particular function in question, a field object is passed to the function and the following happens:

  1. The system automatically adds validation requirements based on the field object. For example, whether or not the field is required (db says field cannot be null), if the db field has a max_length constraint .etc.
  2. If the user has specified a set of validation rules themselves we first check to see if we have already set the rule (in 1) and as a special requirement we check to see if the user specified max_length is not greater than the max_length defined by the db. If that is the case, we use the db one. Note: user rules come in as a pipe-separated string, so we have to split it to get it as an array.
  3. We then generate a pipe-separated string that CI form validation can understand.

The problem is, I think there might be a better way to do this. It seems rather messy having to convert the user validation rules into an array and then back intro a string. And the solution for max_length doesn't seem ideal. I need help with refactoring.

Code works 100% btw.

Usage:

if (($rules = $this->field_validation_rules($field)) !== false) {
    $this->CI->form_validation->set_rules($field->name, $field->human_name, $rules);
}

Function:

/**
 * Gets validation rules for a field
 * 
 * Combines system rules and user rules
 * 
 * Required enforced if column cannot be null
 * 
 * Max length enforced for columns with max length attributes, overridden
 * by user max length of a smaller value than that which the db specifies
 * 
 * In list enforced for columns with type enum (if the field has user specified
 * in_list it will be removed as db one takes precedence)
 * 
 * @param obj $field
 * @return boolean|string
 */
protected function field_validation_rules($field) {
    $sdata = array();
    if (!$field->null) {
        $sdata['trim'] = 'trim';
        $sdata['required'] = 'required';
    }
    if (!is_null($field->max_length)) {
        if ($field->db_type == 'enum') {
            $sdata['in_list'] = implode(',', $this->get_enum_options($field));
        } else {
            $sdata['max_length'] = $field->max_length;
        }
    }
    if ($field->db_type == 'int') {
        $sdata['integer'] = 'integer';
    } elseif ($field->db_type == 'numeric') {
        $sdata['numeric'] = 'numeric';
    }
    $urules = array();
    if (isset($this->validation_rules[$field->name])) {
        if (count($sdata) == 0) {
            return $this->validation_rules[$field->name];
        } else {
            $urules = explode('|', $this->validation_rules[$field->name]);
            foreach ($urules as $index => $rule) {
                $f_rule = preg_filter('/\[(.*?)\]/', '', $rule);
                if (empty($f_rule)) {
                    $f_rule = $rule;
                }
                if (in_array($f_rule, array_keys($sdata))) {
                    if ($f_rule == 'max_length') {
                        if (preg_match('/\[(.*?)\]/', $rule, $matches) && intval($matches[1]) > $field->max_length) {
                            unset($urules[$index]);
                        } else {
                            unset($sdata['max_length']);
                        }
                    } else {
                        unset($urules[$index]);
                    }
                }
            }
        }
    }
    $srules = array();
    foreach ($sdata as $key => $val) {
        if ($key == $val) {
            $srules[] = $key;
        } else {
            $srules[] = $key . "[{$val}]";
        }
    }
    $rules = array_merge($srules, $urules);
    if (count($rules) !== 0) {
        return implode('|', $rules);
    } else {
        return false;
    }
}

Note: $this->validation_rules[$field->name] contains the user defined rules for the field (if any).

\$\endgroup\$
  • \$\begingroup\$ Please don't judge me by this code :) It is the ugliest thing I've ever written... (unless you count procedural days). \$\endgroup\$ – Alex Mar 5 '18 at 7:02
  • \$\begingroup\$ field_validation_rules($field) is clearly part of a class. A little more info on that class would be helpful. I ask because it seems to me that your function might be more useful and easier to implement if it was added to the CI_Form_validation class. It's hard to tell if that make sense without knowing what else is going on. \$\endgroup\$ – DFriend Mar 18 '18 at 5:26
  • \$\begingroup\$ I looked into that once but the problem with that approach is I'd still have to do it a similar way as the form validation library doesn't split the string into an array and assign it to a class property. All of the processing is done in like one function I believe. I don't feel like hacking into or extending the core. The class above that this function is a part of is an intermediary or base class. It extends a fields class which fetchs the fields from the database and each field is a part of the fields object where the current values and rules are added onto. This function is part of the fo \$\endgroup\$ – Alex Mar 18 '18 at 6:33
  • \$\begingroup\$ Form validation system \$\endgroup\$ – Alex Mar 18 '18 at 6:33
  • \$\begingroup\$ OK, that is kind of what I expected. Something you might find most helpful is looking at the definition of set_rules in system/libraries/Form_validation.php. You will find that the $rules argument can be an array and, when a string is supplied, it is converted into an array. It's actually more efficient to pass rules as an array. With that in mind I think you will find your function can be greatly simplified. \$\endgroup\$ – DFriend Mar 19 '18 at 2:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.