Skip to content

Commit ed3dd91

Browse files
committed
feat: Add optional dbGroup support in validation rules for multiple database connections
cs fixer docs format fix rules add test testIsNotUniqueWithDBConnectionAsParameter
1 parent 118c2c4 commit ed3dd91

File tree

4 files changed

+103
-37
lines changed

4 files changed

+103
-37
lines changed

system/Validation/Rules.php

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ public function greater_than_equal_to($str, string $min): bool
110110
* accept only one filter).
111111
*
112112
* Example:
113+
* is_not_unique[dbGroup.table.field,where_field,where_value]
113114
* is_not_unique[table.field,where_field,where_value]
114115
* is_not_unique[menu.id,active,1]
115116
*
@@ -122,16 +123,21 @@ public function is_not_unique($str, string $field, array $data): bool
122123
}
123124

124125
// Grab any data for exclusion of a single row.
125-
[$field, $whereField, $whereValue] = array_pad(
126-
explode(',', $field),
127-
3,
128-
null
129-
);
130-
131-
// Break the table and field apart
132-
sscanf($field, '%[^.].%[^.]', $table, $field);
126+
[$field, $whereField, $whereValue] = array_pad(explode(',', $field), 3, null);
127+
128+
// Break the dbGroup, table and field apart from the field string
129+
$parts = explode('.', $field, 3);
130+
$numParts = count($parts);
131+
132+
if ($numParts === 3) {
133+
[$dbGroup, $table, $field] = $parts;
134+
} elseif ($numParts === 2) {
135+
[$table, $field] = $parts;
136+
} else {
137+
throw new InvalidArgumentException('The field must be in the format "table.field" or "dbGroup.table.field".');
138+
}
133139

134-
$row = Database::connect($data['DBGroup'] ?? null)
140+
$row = Database::connect($dbGroup ?? $data['DBGroup'] ?? null)
135141
->table($table)
136142
->select('1')
137143
->where($field, $str)
@@ -170,6 +176,7 @@ public function in_list($value, string $list): bool
170176
* record updates.
171177
*
172178
* Example:
179+
* is_unique[dbGroup.table.field,ignore_field,ignore_value]
173180
* is_unique[table.field,ignore_field,ignore_value]
174181
* is_unique[users.email,id,5]
175182
*
@@ -181,15 +188,22 @@ public function is_unique($str, string $field, array $data): bool
181188
$str = (string) $str;
182189
}
183190

184-
[$field, $ignoreField, $ignoreValue] = array_pad(
185-
explode(',', $field),
186-
3,
187-
null
188-
);
189-
190-
sscanf($field, '%[^.].%[^.]', $table, $field);
191+
// Grab any data for exclusion of a single row.
192+
[$field, $ignoreField, $ignoreValue] = array_pad(explode(',', $field), 3, null);
193+
194+
// Break the dbGroup, table and field apart from the field string
195+
$parts = explode('.', $field, 3);
196+
$numParts = count($parts);
197+
198+
if ($numParts === 3) {
199+
[$dbGroup, $table, $field] = $parts;
200+
} elseif ($numParts === 2) {
201+
[$table, $field] = $parts;
202+
} else {
203+
throw new InvalidArgumentException('The field must be in the format "table.field" or "dbGroup.table.field".');
204+
}
191205

192-
$row = Database::connect($data['DBGroup'] ?? null)
206+
$row = Database::connect($dbGroup ?? $data['DBGroup'] ?? null)
193207
->table($table)
194208
->select('1')
195209
->where($field, $str)

system/Validation/StrictRules/Rules.php

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use CodeIgniter\Helpers\Array\ArrayHelper;
1717
use CodeIgniter\Validation\Rules as NonStrictRules;
1818
use Config\Database;
19+
use InvalidArgumentException;
1920

2021
/**
2122
* Validation Rules.
@@ -134,6 +135,7 @@ public function greater_than_equal_to($str, string $min): bool
134135
* accept only one filter).
135136
*
136137
* Example:
138+
* is_not_unique[dbGroup.table.field,where_field,where_value]
137139
* is_not_unique[table.field,where_field,where_value]
138140
* is_not_unique[menu.id,active,1]
139141
*
@@ -146,16 +148,21 @@ public function is_not_unique($str, string $field, array $data): bool
146148
}
147149

148150
// Grab any data for exclusion of a single row.
149-
[$field, $whereField, $whereValue] = array_pad(
150-
explode(',', $field),
151-
3,
152-
null
153-
);
154-
155-
// Break the table and field apart
156-
sscanf($field, '%[^.].%[^.]', $table, $field);
151+
[$field, $whereField, $whereValue] = array_pad(explode(',', $field), 3, null);
152+
153+
// Break the dbGroup, table and field apart from the field string
154+
$parts = explode('.', $field, 3);
155+
$numParts = count($parts);
156+
157+
if ($numParts === 3) {
158+
[$dbGroup, $table, $field] = $parts;
159+
} elseif ($numParts === 2) {
160+
[$table, $field] = $parts;
161+
} else {
162+
throw new InvalidArgumentException('The field must be in the format "table.field" or "dbGroup.table.field".');
163+
}
157164

158-
$row = Database::connect($data['DBGroup'] ?? null)
165+
$row = Database::connect($dbGroup ?? $data['DBGroup'] ?? null)
159166
->table($table)
160167
->select('1')
161168
->where($field, $str)
@@ -196,6 +203,7 @@ public function in_list($value, string $list): bool
196203
* record updates.
197204
*
198205
* Example:
206+
* is_unique[dbGroup.table.field,ignore_field,ignore_value]
199207
* is_unique[table.field,ignore_field,ignore_value]
200208
* is_unique[users.email,id,5]
201209
*
@@ -207,15 +215,23 @@ public function is_unique($str, string $field, array $data): bool
207215
return false;
208216
}
209217

210-
[$field, $ignoreField, $ignoreValue] = array_pad(
211-
explode(',', $field),
212-
3,
213-
null
214-
);
215-
216-
sscanf($field, '%[^.].%[^.]', $table, $field);
218+
// Grab any data for exclusion of a single row.
219+
[$field, $ignoreField, $ignoreValue] = array_pad(explode(',', $field), 3, null);
220+
221+
// Break the dbGroup, table and field apart from the field string
222+
// Break the dbGroup, table and field apart from the field string
223+
$parts = explode('.', $field, 3);
224+
$numParts = count($parts);
225+
226+
if ($numParts === 3) {
227+
[$dbGroup, $table, $field] = $parts;
228+
} elseif ($numParts === 2) {
229+
[$table, $field] = $parts;
230+
} else {
231+
throw new InvalidArgumentException('The field must be in the format "table.field" or "dbGroup.table.field".');
232+
}
217233

218-
$row = Database::connect($data['DBGroup'] ?? null)
234+
$row = Database::connect($dbGroup ?? $data['DBGroup'] ?? null)
219235
->table($table)
220236
->select('1')
221237
->where($field, $str)

tests/system/Validation/StrictRules/DatabaseRelatedRulesTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@ public function testIsUniqueWithDBConnection(): void
9797
$this->assertTrue($result);
9898
}
9999

100+
public function testIsUniqueWithDBConnectionAsParameter(): void
101+
{
102+
$this->validation->setRules(['email' => 'is_unique[tests.user.email]']);
103+
104+
$data = ['email' => '[email protected]'];
105+
106+
$result = $this->validation->run($data);
107+
108+
$this->assertTrue($result);
109+
}
110+
100111
public function testIsUniqueWithInvalidDBGroup(): void
101112
{
102113
$this->expectException(InvalidArgumentException::class);
@@ -296,4 +307,19 @@ public function testIsNotUniqueByManualRun(): void
296307

297308
$this->assertTrue($this->createRules()->is_not_unique('[email protected]', 'user.email,id,{id}', []));
298309
}
310+
311+
public function testIsNotUniqueWithDBConnectionAsParameter(): void
312+
{
313+
Database::connect()
314+
->table('user')
315+
->insert([
316+
'name' => 'Derek Travis',
317+
'email' => '[email protected]',
318+
'country' => 'Elbonia',
319+
]);
320+
321+
$data = ['email' => '[email protected]'];
322+
$this->validation->setRules(['email' => 'is_not_unique[tests.user.email]']);
323+
$this->assertTrue($this->validation->run($data));
324+
}
299325
}

user_guide_src/source/libraries/validation.rst

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,13 @@ Available Rules
886886
.. note:: Rule is a string; there must be **no spaces** between the parameters, especially the ``is_unique`` rule.
887887
There can be no spaces before and after ``ignore_value``.
888888

889+
.. note:: Since version v4.5.6, you can optionally include ``dbGroup`` in validation rules like ``is_unique`` and ``is_not_unique``.
890+
This allows specifying which database connection to use during validation, giving you more flexibility when working with multiple databases.
891+
To use ``dbGroup``, you place it before the table name in the validation rule, like this:
892+
``is_unique[dbGroup.table.field,ignore_field,ignore_value]`` or ``is_not_unique[dbGroup.table.field,where_field,where_value]``.
893+
In these examples, ``dbGroup`` is used to select the appropriate database connection for the specified table and field.
894+
If ``dbGroup`` is not provided, the default database group will be used.
895+
889896
.. literalinclude:: validation/038.php
890897
:lines: 2-
891898

@@ -949,13 +956,16 @@ is_natural No Fails if field contains anything other than
949956
is_natural_no_zero No Fails if field contains anything other than
950957
a natural number, except zero: ``1``, ``2``,
951958
``3``, etc.
952-
is_not_unique Yes Checks the database to see if the given value ``is_not_unique[table.field,where_field,where_value]``
959+
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]``
953960
exists. Can ignore records by field/value to
954961
filter (currently accept only one filter).
955-
is_unique Yes Checks if this field value exists in the ``is_unique[table.field,ignore_field,ignore_value]``
962+
(Since v4.5.6, you can optionally pass
963+
the dbGroup as a parameter)
964+
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]``
956965
database. Optionally set a column and value
957966
to ignore, useful when updating records to
958-
ignore itself.
967+
ignore itself. (Since v4.5.6, you can
968+
optionally pass the dbGroup as a parameter)
959969
less_than Yes Fails if field is greater than or equal to ``less_than[8]``
960970
the parameter value or not numeric.
961971
less_than_equal_to Yes Fails if field is greater than the parameter ``less_than_equal_to[8]``

0 commit comments

Comments
 (0)