Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Validation unique field in create and edit
  • Hello. :)

    I´m doing a sing up system and everything were ok... until i made de unique validation rule to check if the username already exist... since when its a new record (Sign Up) it validates and if there is not a username like the one the user have chosen, then it returns true and the new record is saved.... But, when its a update to a existing record, i got arror because when it checks if there is a username already like the one i´m updating ... obviously there is one already.

    I knwo i have to add a if statement in the unique function to check if the query result is the same to the one im editing, but i´m not sure how to do so. Here are my code:

    public static function _validation_check_user($val)
    {
    $query = DB::select('id')->where('username', '=', $val)->from('users')->execute();
    if($query->count() > 0)
    {
    return FALSE;
    }
    }

    How can i compare the record found, if  there is one, and the current object?
  • HarroHarro
    Accepted Answer
    You can access other data using $validation->input('fieldname').

    Use that to fetch the 'id' of the record being updates (for example via a hidden field on the form), and add that as a where clause in the query, so that you select only records that don't have the same 'id'.

    In case of an add, make 'id' zero, so the same code works for both insert and update.

    How you get the validation object depends a bit on how you have organised your validation rules, so check the docs on that.
  • Humm i dont get it to work... where can i use that $validation->input('fieldname'), my custom rule is in a Custom Class file....

    I tried:

    public static function _validation_check_mail($val)
    31    {
    32        
    33        $input $val->input('id');

    But i got this error

    ErrorException [ Error ]: Call to a member function input() on a non-object
  • HarroHarro
    Accepted Answer
    It depends on how you have implemented the validation rule.

    To be able to access the other posted and validated value, you need access to the validation object. If you have validation rules in the model or in a separate class, you can fetch the validation object using
    $validation = \Validation::active();
  • Well i have written my own unique validation rule and for those who are in the same situation, it looks like this: 

    public static function _validation_unique($value, $options, $id = 0)
    {
    list($table, $field) = explode('.', $options);
    $val = Validation::active();
    $id = $val->input('id');
    $check = DB::select('id', $field)->where($field, '=', $value)->from($table)->execute();
    $result = $check->current();
    if($check->count() > 0)
    {
    if($result['id'] === $id)
    {
    return TRUE;
    }
    else
    {
    return FALSE;
    }
    }
    else
    return true;
    }

    You have to include a hidden input field with the id of the current record in the edit form, for the create function, you do not need, since you are setting id to 0 in the function.

    Thank you WanWizard for your suppor... if there is any error or suggestion with the code, please let me know to improve it
  • Hey, I ran across the same issue. However, I wanted a slightly different approach that goes by 'convention over configuration'. That's why I adopted your code a little bit. Here's the code


    public static function _validation_unique($val, $options)
    {
    // Initialize variable
    $model = false;

    // Is $options an array?
    if ( is_array($options) )
    {
    // Is it associative?
    if ( \Arr::is_assoc($options) )
    {
    // Then the key is the model
    $keys = array_keys($options);
    $model = reset($keys);
    // And the key's value is table.field
    $tbl_field = $options[$model];
    }
    // No associative array, just an array of [table.field, model]
    elseif ( count($options) == 2 )
    {
    $tbl_field = array_shift($options);
    $model = array_shift($options);
    }
    elseif ( count($options) == 1 )
    {
    $tbl_field = array_shift($options);
    }
    // Invalid options
    else
    {
    throw new \InvalidArgumentException('Parameter $options must be either an associative array of [model => table.field] or an array of [table.field, model].');
    }
    }
    // Just a string
    else
    {
    $tbl_field = $options;
    }

    // Get the table and field separately
    list($table, $field) = explode('.', $tbl_field);

    // Create the query
    $query = \DB::select($field)
    ->where($field, '=', $val)
    ->from($table);

    // Do we have a model?
    if ( $model )
    {
    // Then get it's primary keys
    foreach ( $model::primary_key() as $pk )
    {
    // And see if there is a post value for these
    if ( $value = \Input::post($pk, false) )
    {
    // Then exclude them from the query
    $query->and_where($pk, '!=', $value);
    }
    }
    }

    // Execute query
    $result = $query->execute();

    // No results?
    if ( $result->count() == 0)
    {
    // Then it's unique
    return true;
    }

    // Set the message
    \Validation::active()->set_message('unique', 'The field :label must be unique');

    // And invaldiate it since the value is not unique
    return false;
    }


    And here's how you'd use it: In your model, when creating the validation-property in $_properties, you do one of the following


    protected static $_properties = array(
    'name' => array(
    'data_type' => 'varchar',
    'character_maximum_length' => 255,
    'validation' => array(
    'required',
    'unique' => array(array('table.field', '\\Groups\\Model\\Group'))
    ),
    ),
    );



    or


    protected static $_properties = array(
    'name' => array(
    'data_type' => 'varchar',
    'character_maximum_length' => 255,
    'validation' => array(
    'required',
    'unique' => array(array('\\Groups\\Model\\Group' => 'table.field'))
    ),
    ),
    );



    or


    protected static $_properties = array(
    'name' => array(
    'data_type' => 'varchar',
    'character_maximum_length' => 255,
    'validation' => array(
    'required',
    'unique' => array('table.field')
    ),
    ),
    );



    This could come in handy for others, too
  • You're checking if "name" is unique against a column called "field" in a table called "table"? Which is possibly services by a different model then the one that contains the "name" field?

    Just trying to understand what you intend to do here...
  • You're right.

    Given a Model 'user' with a column 'username', you'd have the actual code look like this:

    'unique' => array(array('users.username', '\\Model\\User'))

    and the method I posted above automatically searches through $_POST to find the primary-key(s) of \Model\User to exclude from the query to find usernames that match $val.

    There could be references created using this method, however, I don't know of any use-cases that would require referencing other models.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion