Hello guys, this is my first post on this community (I'm a newbie on CI, but I love this.). I write this because I have spent many hours looking for a solution for my problem, so I hope that the information is useful to someone or is worth to improve this great framework...
Okay, the problem is this, I recently write a model for manage a table on my database, on this table I need to save a lot of IP's addresses. On the counterpart, I coded a function which gives me an array with lots of IP addresses, like a Scraper. The problem appears when I try to save the IP's addresses to the database using the model.
This is an example of my model:
PHP Code:
class IPListModel extends Model
{
protected $table = 'ip_list';
protected $primaryKey = 'id';
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $allowedFields = ['ip'];
protected $useTimestamps = true;
protected $dateFormat = 'int';
protected $createdField = 'first_seen';
protected $updatedField = 'last_seen';
protected $deletedField = 'deleted';
protected $validationRules = [
'ip' => 'required|valid_ip[ipv4]|is_unique[ip_list.ip,id,{id}]',
];
protected $validationMessages = [];
protected $skipValidation = false;
}
And this is what I do for save the IP's:
PHP Code:
$ipList = array(
array('ip' => '1.1.1.1'),
array('ip' => '1.1.1.2'),
array('ip' => '1.1.1.1'),
array('ip' => '1.1.1.4')
);
$ipListModel = new IPListModel();
//Loop until All IP's
foreach ($ipList as $ip) {
if (!is_array($ip) || !isset($ip['ip'])) {
continue;
}
if ($ipListModel->save($ip) === false) {
echo 'Can\'t Save the IP '.$ip['ip'].' on the DataBase'.PHP_EOL;
print_r($ipListModel->errors());
} else {
echo 'IP'.$ip['ip'].' Saved on the DataBase'.PHP_EOL;
}
}
If anyone run this code will see the following output:
Quote:IP 1.1.1.1 Saved on the DataBase
IP 1.1.1.2 Saved on the DataBase
Can't Save the IP 1.1.1.1 on the DataBase
Array
(
[ip] => The ip field must contain a unique value.
)
Can't Save the IP 1.1.1.4 on the DataBase
Array
(
[ip] => The ip field must contain a unique value.
)
As we can see, thanks to the 'is_unique' validation the third address was not added, since it was the first to be saved. This is nice, but what about the fourth address? Don't exists on the Database, but still show the 'is_unique' error.
I look on the CI code and on the file
./system/Validation/Validation.php I found this:
PHP Code:
/**
* Runs the validation process, returning true/false determining whether
* validation was successful or not.
*
* @param array $data The array of data to validate.
* @param string $group The pre-defined group of rules to apply.
* @param string $db_group The database group to use.
*
* @return boolean
*/
public function run(array $data = null, string $group = null, string $db_group = null): bool
{
$data = $data ?? $this->data;
// i.e. is_unique
$data['DBGroup'] = $db_group;
$this->loadRuleSets();
$this->loadRuleGroup($group);
// If no rules exist, we return false to ensure
// the developer didn't forget to set the rules.
if (empty($this->rules))
{
return false;
}
// Need this for searching arrays in validation.
helper('array');
// Run through each rule. If we have any field set for
// this rule, then we need to run them through!
foreach ($this->rules as $rField => $rSetup)
{
// Blast $rSetup apart, unless it's already an array.
$rules = $rSetup['rules'] ?? $rSetup;
if (is_string($rules))
{
$rules = $this->splitRules($rules);
}
$value = dot_array_search($rField, $data);
$this->processRules($rField, $rSetup['label'] ?? $rField, $value ?? null, $rules, $data);
}
return ! empty($this->getErrors()) ? false : true;
}
Now we know that the function for doing the validations checks the function 'getErrors' (On the return) for check if any validation error was trigered... So, in this case I assumed that the problem is about this class and the persistence of the previous errors on the new database queries, since I searched on google and on the official documentation but I don't found anything relevant.
In this way my solution has been the following, on the file
./system/Model.php (The base model), in the 'save' function, I called the function 'reset' of the 'validation' library before all (Than among other things resets the 'errors' array), giving the following as result:
PHP Code:
public function save($data): bool
{
//Called to clean previous errors
$this->validation->reset();
if (empty($data))
{
return true;
}
if (is_object($data) && isset($data->{$this->primaryKey}))
{
$response = $this->update($data->{$this->primaryKey}, $data);
}
elseif (is_array($data) && ! empty($data[$this->primaryKey]))
{
$response = $this->update($data[$this->primaryKey], $data);
}
else
{
$response = $this->insert($data, false);
// call insert directly if you want the ID or the record object
if ($response !== false)
{
$response = true;
}
}
return $response;
}
This prevents past queries errors from affecting the current query (And now the code works perfect!). But now my question is the next:
Is this some quality or characteristic of CI that can be deactivated and I am so noob that I don't know her? Or is really a bug?
P.S: Sorry for my bad english.
EDIT: Sorry, I forgot to say that I'm using the version 4.0.0 rc3, thanks.
//Regards.