Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [Validation] add support for dbGroup as parameter in is_unique and is_not_unique #9216

Open
wants to merge 4 commits into
base: 4.6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 31 additions & 17 deletions system/Validation/Rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public function greater_than_equal_to($str, string $min): bool
* accept only one filter).
*
* Example:
* is_not_unique[dbGroup.table.field,where_field,where_value]
* is_not_unique[table.field,where_field,where_value]
* is_not_unique[menu.id,active,1]
*
Expand All @@ -122,16 +123,21 @@ public function is_not_unique($str, string $field, array $data): bool
}

// Grab any data for exclusion of a single row.
[$field, $whereField, $whereValue] = array_pad(
explode(',', $field),
3,
null
);

// Break the table and field apart
sscanf($field, '%[^.].%[^.]', $table, $field);
[$field, $whereField, $whereValue] = array_pad(explode(',', $field), 3, null);

// Break the dbGroup, table and field apart from the field string
$parts = explode('.', $field, 3);
$numParts = count($parts);

if ($numParts === 3) {
[$dbGroup, $table, $field] = $parts;
} elseif ($numParts === 2) {
[$table, $field] = $parts;
} else {
throw new InvalidArgumentException('The field must be in the format "table.field" or "dbGroup.table.field".');
}

$row = Database::connect($data['DBGroup'] ?? null)
$row = Database::connect($dbGroup ?? $data['DBGroup'] ?? null)
->table($table)
->select('1')
->where($field, $str)
Expand Down Expand Up @@ -170,6 +176,7 @@ public function in_list($value, string $list): bool
* record updates.
*
* Example:
* is_unique[dbGroup.table.field,ignore_field,ignore_value]
* is_unique[table.field,ignore_field,ignore_value]
* is_unique[users.email,id,5]
*
Expand All @@ -181,15 +188,22 @@ public function is_unique($str, string $field, array $data): bool
$str = (string) $str;
}

[$field, $ignoreField, $ignoreValue] = array_pad(
explode(',', $field),
3,
null
);

sscanf($field, '%[^.].%[^.]', $table, $field);
// Grab any data for exclusion of a single row.
[$field, $ignoreField, $ignoreValue] = array_pad(explode(',', $field), 3, null);

// Break the dbGroup, table and field apart from the field string
$parts = explode('.', $field, 3);
$numParts = count($parts);

if ($numParts === 3) {
[$dbGroup, $table, $field] = $parts;
} elseif ($numParts === 2) {
[$table, $field] = $parts;
} else {
throw new InvalidArgumentException('The field must be in the format "table.field" or "dbGroup.table.field".');
}

$row = Database::connect($data['DBGroup'] ?? null)
$row = Database::connect($dbGroup ?? $data['DBGroup'] ?? null)
->table($table)
->select('1')
->where($field, $str)
Expand Down
50 changes: 33 additions & 17 deletions system/Validation/StrictRules/Rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use CodeIgniter\Helpers\Array\ArrayHelper;
use CodeIgniter\Validation\Rules as NonStrictRules;
use Config\Database;
use InvalidArgumentException;

/**
* Validation Rules.
Expand Down Expand Up @@ -134,6 +135,7 @@ public function greater_than_equal_to($str, string $min): bool
* accept only one filter).
*
* Example:
* is_not_unique[dbGroup.table.field,where_field,where_value]
* is_not_unique[table.field,where_field,where_value]
* is_not_unique[menu.id,active,1]
*
Expand All @@ -146,16 +148,21 @@ public function is_not_unique($str, string $field, array $data): bool
}

// Grab any data for exclusion of a single row.
[$field, $whereField, $whereValue] = array_pad(
explode(',', $field),
3,
null
);

// Break the table and field apart
sscanf($field, '%[^.].%[^.]', $table, $field);
[$field, $whereField, $whereValue] = array_pad(explode(',', $field), 3, null);

// Break the dbGroup, table and field apart from the field string
$parts = explode('.', $field, 3);
$numParts = count($parts);

if ($numParts === 3) {
[$dbGroup, $table, $field] = $parts;
} elseif ($numParts === 2) {
[$table, $field] = $parts;
} else {
throw new InvalidArgumentException('The field must be in the format "table.field" or "dbGroup.table.field".');
}

$row = Database::connect($data['DBGroup'] ?? null)
$row = Database::connect($dbGroup ?? $data['DBGroup'] ?? null)
->table($table)
->select('1')
->where($field, $str)
Expand Down Expand Up @@ -196,6 +203,7 @@ public function in_list($value, string $list): bool
* record updates.
*
* Example:
* is_unique[dbGroup.table.field,ignore_field,ignore_value]
* is_unique[table.field,ignore_field,ignore_value]
* is_unique[users.email,id,5]
*
Expand All @@ -207,15 +215,23 @@ public function is_unique($str, string $field, array $data): bool
return false;
}

[$field, $ignoreField, $ignoreValue] = array_pad(
explode(',', $field),
3,
null
);

sscanf($field, '%[^.].%[^.]', $table, $field);
// Grab any data for exclusion of a single row.
[$field, $ignoreField, $ignoreValue] = array_pad(explode(',', $field), 3, null);

// Break the dbGroup, table and field apart from the field string
// Break the dbGroup, table and field apart from the field string
$parts = explode('.', $field, 3);
$numParts = count($parts);

if ($numParts === 3) {
[$dbGroup, $table, $field] = $parts;
} elseif ($numParts === 2) {
[$table, $field] = $parts;
} else {
throw new InvalidArgumentException('The field must be in the format "table.field" or "dbGroup.table.field".');
}

$row = Database::connect($data['DBGroup'] ?? null)
$row = Database::connect($dbGroup ?? $data['DBGroup'] ?? null)
->table($table)
->select('1')
->where($field, $str)
Expand Down
26 changes: 26 additions & 0 deletions tests/system/Validation/StrictRules/DatabaseRelatedRulesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ public function testIsUniqueWithDBConnection(): void
$this->assertTrue($result);
}

public function testIsUniqueWithDBConnectionAsParameter(): void
{
$this->validation->setRules(['email' => 'is_unique[tests.user.email]']);

$data = ['email' => '[email protected]'];

$result = $this->validation->run($data);

$this->assertTrue($result);
}

public function testIsUniqueWithInvalidDBGroup(): void
{
$this->expectException(InvalidArgumentException::class);
Expand Down Expand Up @@ -296,4 +307,19 @@ public function testIsNotUniqueByManualRun(): void

$this->assertTrue($this->createRules()->is_not_unique('[email protected]', 'user.email,id,{id}', []));
}

public function testIsNotUniqueWithDBConnectionAsParameter(): void
{
Database::connect()
->table('user')
->insert([
'name' => 'Derek Travis',
'email' => '[email protected]',
'country' => 'Elbonia',
]);

$data = ['email' => '[email protected]'];
$this->validation->setRules(['email' => 'is_not_unique[tests.user.email]']);
$this->assertTrue($this->validation->run($data));
}
}
2 changes: 2 additions & 0 deletions user_guide_src/source/changelogs/v4.6.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ Libraries
See :ref:`FileCollection::retainMultiplePatterns() <file-collections-retain-multiple-patterns>`.
- **Validation:** Added ``min_dims`` validation rule to ``FileRules`` class. See
:ref:`Validation <rules-for-file-uploads>`.
- **Validation:** Rule ``is_unique`` and ``is_not_unique`` now accept an optional
``dbGroup`` as parameter. See :ref:`Validation <rules-for-general-use>`.

Helpers and Functions
=====================
Expand Down
18 changes: 14 additions & 4 deletions user_guide_src/source/libraries/validation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,13 @@ Available Rules
.. note:: Rule is a string; there must be **no spaces** between the parameters, especially the ``is_unique`` rule.
There can be no spaces before and after ``ignore_value``.

.. note:: Since version v4.6.0, you can optionally include ``dbGroup`` in validation rules like ``is_unique`` and ``is_not_unique``.
This allows specifying which database connection to use during validation, giving you more flexibility when working with multiple databases.
To use ``dbGroup``, you place it before the table name in the validation rule, like this:
``is_unique[dbGroup.table.field,ignore_field,ignore_value]`` or ``is_not_unique[dbGroup.table.field,where_field,where_value]``.
In these examples, ``dbGroup`` is used to select the appropriate database connection for the specified table and field.
If ``dbGroup`` is not provided, the default database group will be used.

Comment on lines +889 to +895
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we should add such an extensive description of these changes here.

The description in the following table is sufficient for me. The user guide cannot be covered with continuous notes, because it becomes unreadable.

.. literalinclude:: validation/038.php
:lines: 2-

Expand Down Expand Up @@ -949,13 +956,16 @@ is_natural No Fails if field contains anything other than
is_natural_no_zero No Fails if field contains anything other than
a natural number, except zero: ``1``, ``2``,
``3``, etc.
is_not_unique Yes Checks the database to see if the given value ``is_not_unique[table.field,where_field,where_value]``
is_not_unique Yes Checks the database to see if the given value ``is_not_unique[table.field,where_field,where_value]`` or ``is_not_unique[dbGroup.table.field,where_field,where_value]``
exists. Can ignore records by field/value to
filter (currently accept only one filter).
is_unique Yes Checks if this field value exists in the ``is_unique[table.field,ignore_field,ignore_value]``
(Since v4.6.0, you can optionally pass
the dbGroup as a parameter)
is_unique Yes Checks if this field value exists in the ``is_unique[table.field,ignore_field,ignore_value]`` or ``is_unique[dbGroup.table.field,ignore_field,ignore_value]``
database. Optionally set a column and value
to ignore, useful when updating records to
ignore itself.
ignore itself. (Since v4.6.0, you can
optionally pass the dbGroup as a parameter)
less_than Yes Fails if field is greater than or equal to ``less_than[8]``
the parameter value or not numeric.
less_than_equal_to Yes Fails if field is greater than the parameter ``less_than_equal_to[8]``
Expand Down Expand Up @@ -1094,7 +1104,7 @@ min_dims Yes Fails if the minimum width and height of an
parameter is the field name. The second is
the width, and the third is the height. Will
also fail if the file cannot be determined
to be an image. (This rule was added in
to be an image. (This rule was added in
v4.6.0.)
mime_in Yes Fails if the file's mime type is not one ``mime_in[field_name,image/png,image/jpeg]``
listed in the parameters.
Expand Down
Loading