Skip to content

Commit

Permalink
Model validation placeholders. Fixes #772
Browse files Browse the repository at this point in the history
  • Loading branch information
lonnieezell committed Feb 6, 2018
1 parent 7502719 commit 75a8a59
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 4 deletions.
48 changes: 47 additions & 1 deletion system/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -1150,7 +1150,11 @@ public function validate($data): bool
}
else
{
$this->validation->setRules($this->validationRules, $this->validationMessages);
// Replace any placeholders (i.e. {id}) in the rules with
// the value found in $data, if exists.
$rules = $this->fillPlaceholders($this->validationRules, $data);

$this->validation->setRules($rules, $this->validationMessages);
$valid = $this->validation->run($data);
}

Expand All @@ -1159,6 +1163,48 @@ public function validate($data): bool

//--------------------------------------------------------------------

/**
* Replace any placeholders within the rules with the values that
* match the 'key' of any properties being set. For example, if
* we had the following $data array:
*
* [ 'id' => 13 ]
*
* and the following rule:
*
* 'required|is_unique[users,email,id,{id}]'
*
* The value of {id} would be replaced with the actual id in the form data:
*
* 'required|is_unique[users,email,id,13]'
*
* @param array $rules
* @param array $data
*
* @return array
*/
protected function fillPlaceholders(array $rules, array $data)
{
$replacements = [];

foreach ($data as $key => $value)
{
$replacements["{{$key}}"] = $value;
}

if (! empty($replacements))
{
foreach ($rules as &$rule)
{
$rule = strtr($rule, $replacements);
}
}

return $rules;
}

//--------------------------------------------------------------------

/**
* Returns the model's defined validation rules so that they
* can be used elsewhere, if needed.
Expand Down
5 changes: 3 additions & 2 deletions tests/_support/Models/ValidModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ class ValidModel extends Model
protected $allowedFields = ['name', 'description'];

protected $validationRules = [
'name' => 'required|min_length[3]'
'name' => 'required|min_length[3]',
'token' => 'in_list[{id}]'
];

protected $validationMessages = [
'name' => [
'required' => 'You forgot to name the baby.',
'min_length' => 'Too short, man!'
'min_length' => 'Too short, man!',
]
];
}
28 changes: 27 additions & 1 deletion tests/system/Database/Live/ModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,33 @@ public function testValidationBasics()

//--------------------------------------------------------------------

public function testSkipValidation()
public function testValidationPlaceholdersSuccess()
{
$model = new ValidModel($this->db);

$data = [
'name' => 'abc',
'id' => 13,
'token' => 13
];

$this->assertTrue($model->validate($data));
}

public function testValidationPlaceholdersFail()
{
$model = new ValidModel($this->db);

$data = [
'name' => 'abc',
'id' => 13,
'token' => 12
];

$this->assertFalse($model->validate($data));
}

public function testSkipValidation()
{
$model = new ValidModel($this->db);

Expand Down
31 changes: 31 additions & 0 deletions user_guide_src/source/database/model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,37 @@ and simply set ``$validationRules`` to the name of the validation rule group you
protected $validationRules = 'users';
}

Validation Placeholders
-----------------------

The model provides a simple method to replace parts of your rules based on data that's being passed into it. This
sounds fairly obscure but can be especially handy with the ``is_unique`` validation rule. Placeholders are simply
the name of the field (or array key) that was passed in as $data surrounded by curly brackets. It will be
replaced by the **value** of the matched incoming field. An example should clarify this::

protected $validationRules = [
'email' => 'required|valid_email|is_unique[users.email,id,{id}]'
];

In this set of rules, it states that the email address should be unique in the database, except for the row
that has an id matching the placeholder's value. Assuming that the form POST data had the following::

$_POST = [
'id' => 4,
'email' => '[email protected]'
]

then the ``{id}`` placeholder would be replaced with the number **4**, giving this revised rule::

protected $validationRules = [
'email' => 'required|valid_email|is_unique[users.email,id,4]'
];

So it will ignore the row in the database that has ``id=4`` when it verifies the email is unique.

This can also be used to create more dynamic rules at runtime, as long as you take care that any dynamic
keys passed in don't conflict with your form data.

Protecting Fields
-----------------

Expand Down

0 comments on commit 75a8a59

Please sign in to comment.