mirror of
https://github.com/codeigniter4/CodeIgniter4.git
synced 2025-02-20 11:44:28 +08:00
Merge pull request #2897 from jreklund/validation-placeholders-again
Make validation placeholders always available
This commit is contained in:
commit
73d6ae6030
@ -1439,10 +1439,6 @@ class Model
|
||||
return true;
|
||||
}
|
||||
|
||||
// Replace any placeholders (i.e. {id}) in the rules with
|
||||
// the value found in $data, if exists.
|
||||
$rules = $this->fillPlaceholders($rules, $data);
|
||||
|
||||
$this->validation->setRules($rules, $this->validationMessages);
|
||||
$valid = $this->validation->run($data, null, $this->DBGroup);
|
||||
|
||||
@ -1495,6 +1491,10 @@ class Model
|
||||
*
|
||||
* 'required|is_unique[users,email,id,13]'
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @deprecated use fillPlaceholders($rules, $data) from Validation instead
|
||||
*
|
||||
* @param array $rules
|
||||
* @param array $data
|
||||
*
|
||||
|
@ -155,6 +155,10 @@ class Validation implements ValidationInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
// Replace any placeholders (i.e. {id}) in the rules with
|
||||
// the value found in $data, if exists.
|
||||
$this->rules = $this->fillPlaceholders($this->rules, $data);
|
||||
|
||||
// Need this for searching arrays in validation.
|
||||
helper('array');
|
||||
|
||||
@ -603,6 +607,64 @@ class Validation implements ValidationInterface
|
||||
return $this->rules;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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): array
|
||||
{
|
||||
$replacements = [];
|
||||
|
||||
foreach ($data as $key => $value)
|
||||
{
|
||||
$replacements["{{$key}}"] = $value;
|
||||
}
|
||||
|
||||
if (! empty($replacements))
|
||||
{
|
||||
foreach ($rules as &$rule)
|
||||
{
|
||||
if (is_array($rule))
|
||||
{
|
||||
foreach ($rule as &$row)
|
||||
{
|
||||
// Should only be an `errors` array
|
||||
// which doesn't take placeholders.
|
||||
if (is_array($row))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$row = strtr($row, $replacements);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$rule = strtr($rule, $replacements);
|
||||
}
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------
|
||||
// Errors
|
||||
|
@ -112,4 +112,35 @@ class UniqueRulesTest extends CIDatabaseTestCase
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @group DatabaseLive
|
||||
*/
|
||||
public function testIsUniqueIgnoresParamsPlaceholders()
|
||||
{
|
||||
$this->hasInDatabase('user', [
|
||||
'name' => 'Derek',
|
||||
'email' => 'derek@world.co.uk',
|
||||
'country' => 'GB',
|
||||
]);
|
||||
|
||||
$db = Database::connect();
|
||||
$row = $db->table('user')
|
||||
->limit(1)
|
||||
->get()
|
||||
->getRow();
|
||||
|
||||
$data = [
|
||||
'id' => $row->id,
|
||||
'email' => 'derek@world.co.uk',
|
||||
];
|
||||
|
||||
$this->validation->setRules([
|
||||
'email' => "is_unique[user.email,id,{id}]",
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->validation->run($data));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
|
@ -64,11 +64,11 @@ The Form
|
||||
Using a text editor, create a form called **Signup.php**. In it, place this
|
||||
code and save it to your **app/Views/** folder::
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>My Form</title>
|
||||
</head>
|
||||
<body>
|
||||
<html>
|
||||
<head>
|
||||
<title>My Form</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?= $validation->listErrors() ?>
|
||||
|
||||
@ -90,8 +90,8 @@ code and save it to your **app/Views/** folder::
|
||||
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
The Success Page
|
||||
================================================
|
||||
@ -99,18 +99,18 @@ The Success Page
|
||||
Using a text editor, create a form called **Success.php**. In it, place
|
||||
this code and save it to your **app/Views/** folder::
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>My Form</title>
|
||||
</head>
|
||||
<body>
|
||||
<html>
|
||||
<head>
|
||||
<title>My Form</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h3>Your form was successfully submitted!</h3>
|
||||
|
||||
<p><?= anchor('form', 'Try it again!') ?></p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
The Controller
|
||||
================================================
|
||||
@ -118,43 +118,43 @@ The Controller
|
||||
Using a text editor, create a controller called **Form.php**. In it, place
|
||||
this code and save it to your **app/Controllers/** folder::
|
||||
|
||||
<?php namespace App\Controllers;
|
||||
<?php namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\Controller;
|
||||
|
||||
class Form extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
helper(['form', 'url']);
|
||||
class Form extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
helper(['form', 'url']);
|
||||
|
||||
if (! $this->validate([]))
|
||||
{
|
||||
echo view('Signup', [
|
||||
'validation' => $this->validator
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo view('Success');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! $this->validate([]))
|
||||
{
|
||||
echo view('Signup', [
|
||||
'validation' => $this->validator
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo view('Success');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Try it!
|
||||
================================================
|
||||
|
||||
To try your form, visit your site using a URL similar to this one::
|
||||
|
||||
example.com/index.php/form/
|
||||
example.com/index.php/form/
|
||||
|
||||
If you submit the form you should simply see the form reload. That's
|
||||
because you haven't set up any validation rules yet.
|
||||
|
||||
**Since you haven't told the Validation class to validate anything
|
||||
yet, it returns false (boolean false) by default. The** ``validate()`` **method
|
||||
only returns true if it has successfully applied your rules without any
|
||||
of them failing.**
|
||||
.. note:: Since you haven't told the **Validation class** to validate anything
|
||||
yet, it **returns false** (boolean false) **by default**. The ``validate()``
|
||||
method only returns true if it has successfully applied your rules without
|
||||
any of them failing.
|
||||
|
||||
Explanation
|
||||
================================================
|
||||
@ -171,7 +171,7 @@ The form (Signup.php) is a standard web form with a couple of exceptions:
|
||||
#. At the top of the form you'll notice the following function call:
|
||||
::
|
||||
|
||||
<?= $validation->listErrors() ?>
|
||||
<?= $validation->listErrors() ?>
|
||||
|
||||
This function will return any error messages sent back by the
|
||||
validator. If there are no messages it returns an empty string.
|
||||
@ -364,19 +364,17 @@ Or pass all settings in an array::
|
||||
{
|
||||
public $signup = [
|
||||
'username' => [
|
||||
'label' => 'Username',
|
||||
'rules' => 'required',
|
||||
'errors' => [
|
||||
'required' => 'You must choose a {field}.'
|
||||
'required' => 'You must choose a Username.'
|
||||
]
|
||||
],
|
||||
'email' => [
|
||||
'rules' => 'required|valid_email',
|
||||
'errors' => [
|
||||
'valid_email' => 'Please check the Email field. It does not appear to be valid.'
|
||||
]
|
||||
],
|
||||
'email' => 'required|valid_email'
|
||||
];
|
||||
|
||||
public $signup_errors = [
|
||||
'email' => [
|
||||
'valid_email' => 'Please check the Email field. It does not appear to be valid.'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
@ -417,6 +415,37 @@ you previously set, so ``setRules()``, ``setRuleGroup()`` etc. need to be repeat
|
||||
}
|
||||
}
|
||||
|
||||
Validation Placeholders
|
||||
=======================================================
|
||||
|
||||
The Validation class 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::
|
||||
|
||||
$validation->setRules([
|
||||
'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' => 'foo@example.com'
|
||||
];
|
||||
|
||||
then the ``{id}`` placeholder would be replaced with the number **4**, giving this revised rule::
|
||||
|
||||
$validation->setRules([
|
||||
'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.
|
||||
|
||||
Working With Errors
|
||||
************************************************
|
||||
|
||||
@ -487,7 +516,9 @@ at least 6 characters.”
|
||||
Translation Of Messages And Validation Labels
|
||||
=============================================
|
||||
|
||||
To use translated strings from language files, we can simply use the dot syntax. Let's say we have a file with translations located here: ``app/Languages/en/Rules.php``. We can simply use the language lines defined in this file, like this::
|
||||
To use translated strings from language files, we can simply use the dot syntax.
|
||||
Let's say we have a file with translations located here: ``app/Languages/en/Rules.php``.
|
||||
We can simply use the language lines defined in this file, like this::
|
||||
|
||||
$validation->setRules([
|
||||
'username' => [
|
||||
@ -611,10 +642,10 @@ autoloader can find it. These files are called RuleSets. To add a new RuleSet, e
|
||||
add the new file to the ``$ruleSets`` array::
|
||||
|
||||
public $ruleSets = [
|
||||
\CodeIgniter\Validation\Rules::class,
|
||||
\CodeIgniter\Validation\FileRules::class,
|
||||
\CodeIgniter\Validation\CreditCardRules::class,
|
||||
];
|
||||
\CodeIgniter\Validation\Rules::class,
|
||||
\CodeIgniter\Validation\FileRules::class,
|
||||
\CodeIgniter\Validation\CreditCardRules::class,
|
||||
];
|
||||
|
||||
You can add it as either a simple string with the fully qualified class name, or using the ``::class`` suffix as
|
||||
shown above. The primary benefit here is that it provides some extra navigation capabilities in more advanced IDEs.
|
||||
@ -658,41 +689,41 @@ If your method needs to work with parameters, the function will need a minimum o
|
||||
the parameter string, and an array with all of the data that was submitted the form. The $data array is especially handy
|
||||
for rules like ``require_with`` that needs to check the value of another submitted field to base its result on::
|
||||
|
||||
public function required_with($str, string $fields, array $data): bool
|
||||
{
|
||||
$fields = explode(',', $fields);
|
||||
public function required_with($str, string $fields, array $data): bool
|
||||
{
|
||||
$fields = explode(',', $fields);
|
||||
|
||||
// If the field is present we can safely assume that
|
||||
// the field is here, no matter whether the corresponding
|
||||
// search field is present or not.
|
||||
$present = $this->required($str ?? '');
|
||||
// If the field is present we can safely assume that
|
||||
// the field is here, no matter whether the corresponding
|
||||
// search field is present or not.
|
||||
$present = $this->required($str ?? '');
|
||||
|
||||
if ($present)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ($present)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Still here? Then we fail this test if
|
||||
// any of the fields are present in $data
|
||||
// as $fields is the lis
|
||||
$requiredFields = [];
|
||||
// any of the fields are present in $data
|
||||
// as $fields is the lis
|
||||
$requiredFields = [];
|
||||
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
if (array_key_exists($field, $data))
|
||||
{
|
||||
$requiredFields[] = $field;
|
||||
}
|
||||
}
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
if (array_key_exists($field, $data))
|
||||
{
|
||||
$requiredFields[] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any keys with empty values since, that means they
|
||||
// weren't truly there, as far as this is concerned.
|
||||
$requiredFields = array_filter($requiredFields, function ($item) use ($data) {
|
||||
return ! empty($data[$item]);
|
||||
});
|
||||
// Remove any keys with empty values since, that means they
|
||||
// weren't truly there, as far as this is concerned.
|
||||
$requiredFields = array_filter($requiredFields, function ($item) use ($data) {
|
||||
return ! empty($data[$item]);
|
||||
});
|
||||
|
||||
return empty($requiredFields);
|
||||
}
|
||||
return empty($requiredFields);
|
||||
}
|
||||
|
||||
Custom errors can be returned as the fourth parameter, just as described above.
|
||||
|
||||
@ -701,12 +732,20 @@ Available Rules
|
||||
|
||||
The following is a list of all the native rules that are available to use:
|
||||
|
||||
.. 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:: 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``.
|
||||
|
||||
::
|
||||
|
||||
// is_unique[table.field,ignore_field,ignore_value]
|
||||
|
||||
$validation->setRules([
|
||||
'name' => "is_unique[supplier.name,uuid, $uuid]", // is not ok
|
||||
'name' => "is_unique[supplier.name,uuid,$uuid ]", // is not ok
|
||||
'name' => "is_unique[supplier.name,uuid,$uuid]", // is ok
|
||||
'name' => "is_unique[supplier.name,uuid,{uuid}]", // is ok - see "Validation Placeholders"
|
||||
]);
|
||||
|
||||
- "is_unique[supplier.name,uuid, $uuid]" is not ok
|
||||
- "is_unique[supplier.name,uuid,$uuid ]" is not ok
|
||||
- "is_unique[supplier.name,uuid,$uuid]" is ok
|
||||
|
||||
======================= =========== =============================================================================================== ===================================================
|
||||
Rule Parameter Description Example
|
||||
@ -802,5 +841,5 @@ is_image Yes Fails if the file cannot be determined to be
|
||||
The file validation rules apply for both single and multiple file uploads.
|
||||
|
||||
.. note:: You can also use any native PHP functions that permit up
|
||||
to two parameters, where at least one is required (to pass
|
||||
the field data).
|
||||
to two parameters, where at least one is required (to pass
|
||||
the field data).
|
||||
|
@ -24,7 +24,7 @@ You can access models within your classes by creating a new instance or using th
|
||||
::
|
||||
|
||||
// Create a new class manually
|
||||
$userModel = new App\Models\UserModel();
|
||||
$userModel = new \App\Models\UserModel();
|
||||
|
||||
// Create a new class with the model function
|
||||
$userModel = model('App\Models\UserModel', false);
|
||||
@ -59,14 +59,14 @@ Creating Your Model
|
||||
To take advantage of CodeIgniter's model, you would simply create a new model class
|
||||
that extends ``CodeIgniter\Model``::
|
||||
|
||||
<?php namespace App\Models;
|
||||
<?php namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class UserModel extends Model
|
||||
{
|
||||
class UserModel extends Model
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
This empty class provides convenient access to the database connection, the Query Builder,
|
||||
and a number of additional convenience methods.
|
||||
@ -85,10 +85,10 @@ connection.
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class UserModel extends Model
|
||||
{
|
||||
protected $DBGroup = 'group_name';
|
||||
}
|
||||
class UserModel extends Model
|
||||
{
|
||||
protected $DBGroup = 'group_name';
|
||||
}
|
||||
|
||||
You would replace "group_name" with the name of a defined database group from the database
|
||||
configuration file.
|
||||
@ -100,29 +100,29 @@ The model class has a few configuration options that can be set to allow the cla
|
||||
to work seamlessly for you. The first two are used by all of the CRUD methods to determine
|
||||
what table to use and how we can find the required records::
|
||||
|
||||
<?php namespace App\Models;
|
||||
<?php namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class UserModel extends Model
|
||||
{
|
||||
protected $table = 'users';
|
||||
protected $primaryKey = 'id';
|
||||
class UserModel extends Model
|
||||
{
|
||||
protected $table = 'users';
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = true;
|
||||
|
||||
protected $allowedFields = ['name', 'email'];
|
||||
protected $allowedFields = ['name', 'email'];
|
||||
|
||||
protected $useTimestamps = false;
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
protected $deletedField = 'deleted_at';
|
||||
protected $useTimestamps = false;
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
protected $deletedField = 'deleted_at';
|
||||
|
||||
protected $validationRules = [];
|
||||
protected $validationMessages = [];
|
||||
protected $skipValidation = false;
|
||||
}
|
||||
protected $validationRules = [];
|
||||
protected $validationMessages = [];
|
||||
protected $skipValidation = false;
|
||||
}
|
||||
|
||||
**$table**
|
||||
|
||||
@ -231,49 +231,49 @@ insert(), update(), delete() and more.
|
||||
|
||||
Returns a single row where the primary key matches the value passed in as the first parameter::
|
||||
|
||||
$user = $userModel->find($user_id);
|
||||
$user = $userModel->find($user_id);
|
||||
|
||||
The value is returned in the format specified in $returnType.
|
||||
|
||||
You can specify more than one row to return by passing an array of primaryKey values instead
|
||||
of just one::
|
||||
|
||||
$users = $userModel->find([1,2,3]);
|
||||
$users = $userModel->find([1,2,3]);
|
||||
|
||||
If no parameters are passed in, will return all rows in that model's table, effectively acting
|
||||
like findAll(), though less explicit.
|
||||
|
||||
**findColumn()**
|
||||
|
||||
Returns null or an indexed array of column values::
|
||||
Returns null or an indexed array of column values::
|
||||
|
||||
$user = $userModel->findColumn($column_name);
|
||||
$user = $userModel->findColumn($column_name);
|
||||
|
||||
$column_name should be a name of single column else you will get the DataException.
|
||||
$column_name should be a name of single column else you will get the DataException.
|
||||
|
||||
**findAll()**
|
||||
|
||||
Returns all results::
|
||||
|
||||
$users = $userModel->findAll();
|
||||
$users = $userModel->findAll();
|
||||
|
||||
This query may be modified by interjecting Query Builder commands as needed prior to calling this method::
|
||||
|
||||
$users = $userModel->where('active', 1)
|
||||
->findAll();
|
||||
$users = $userModel->where('active', 1)
|
||||
->findAll();
|
||||
|
||||
You can pass in a limit and offset values as the first and second
|
||||
parameters, respectively::
|
||||
|
||||
$users = $userModel->findAll($limit, $offset);
|
||||
$users = $userModel->findAll($limit, $offset);
|
||||
|
||||
**first()**
|
||||
|
||||
Returns the first row in the result set. This is best used in combination with the query builder.
|
||||
::
|
||||
|
||||
$user = $userModel->where('deleted', 0)
|
||||
->first();
|
||||
$user = $userModel->where('deleted', 0)
|
||||
->first();
|
||||
|
||||
**withDeleted()**
|
||||
|
||||
@ -281,20 +281,20 @@ If $useSoftDeletes is true, then the find* methods will not return any rows wher
|
||||
To temporarily override this, you can use the withDeleted() method prior to calling the find* method.
|
||||
::
|
||||
|
||||
// Only gets non-deleted rows (deleted = 0)
|
||||
$activeUsers = $userModel->findAll();
|
||||
// Only gets non-deleted rows (deleted = 0)
|
||||
$activeUsers = $userModel->findAll();
|
||||
|
||||
// Gets all rows
|
||||
$allUsers = $userModel->withDeleted()
|
||||
->findAll();
|
||||
// Gets all rows
|
||||
$allUsers = $userModel->withDeleted()
|
||||
->findAll();
|
||||
|
||||
**onlyDeleted()**
|
||||
|
||||
Whereas withDeleted() will return both deleted and not-deleted rows, this method modifies
|
||||
the next find* methods to return only soft deleted rows::
|
||||
|
||||
$deletedUsers = $userModel->onlyDeleted()
|
||||
->findAll();
|
||||
$deletedUsers = $userModel->onlyDeleted()
|
||||
->findAll();
|
||||
|
||||
Saving Data
|
||||
-----------
|
||||
@ -305,12 +305,12 @@ An associative array of data is passed into this method as the only parameter to
|
||||
row of data in the database. The array's keys must match the name of the columns in a $table, while
|
||||
the array's values are the values to save for that key::
|
||||
|
||||
$data = [
|
||||
'username' => 'darth',
|
||||
'email' => 'd.vader@theempire.com'
|
||||
];
|
||||
$data = [
|
||||
'username' => 'darth',
|
||||
'email' => 'd.vader@theempire.com'
|
||||
];
|
||||
|
||||
$userModel->insert($data);
|
||||
$userModel->insert($data);
|
||||
|
||||
**update()**
|
||||
|
||||
@ -318,20 +318,20 @@ Updates an existing record in the database. The first parameter is the $primaryK
|
||||
An associative array of data is passed into this method as the second parameter. The array's keys must match the name
|
||||
of the columns in a $table, while the array's values are the values to save for that key::
|
||||
|
||||
$data = [
|
||||
'username' => 'darth',
|
||||
'email' => 'd.vader@theempire.com'
|
||||
];
|
||||
$data = [
|
||||
'username' => 'darth',
|
||||
'email' => 'd.vader@theempire.com'
|
||||
];
|
||||
|
||||
$userModel->update($id, $data);
|
||||
$userModel->update($id, $data);
|
||||
|
||||
Multiple records may be updated with a single call by passing an array of primary keys as the first parameter::
|
||||
|
||||
$data = [
|
||||
'active' => 1
|
||||
];
|
||||
'active' => 1
|
||||
];
|
||||
|
||||
$userModel->update([1, 2, 3], $data);
|
||||
$userModel->update([1, 2, 3], $data);
|
||||
|
||||
When you need a more flexible solution, you can leave the parameters empty and it functions like the Query Builder's
|
||||
update command, with the added benefit of validation, events, etc::
|
||||
@ -346,24 +346,24 @@ update command, with the added benefit of validation, events, etc::
|
||||
This is a wrapper around the insert() and update() methods that handle inserting or updating the record
|
||||
automatically, based on whether it finds an array key matching the $primaryKey value::
|
||||
|
||||
// Defined as a model property
|
||||
$primaryKey = 'id';
|
||||
// Defined as a model property
|
||||
$primaryKey = 'id';
|
||||
|
||||
// Does an insert()
|
||||
$data = [
|
||||
'username' => 'darth',
|
||||
'email' => 'd.vader@theempire.com'
|
||||
];
|
||||
// Does an insert()
|
||||
$data = [
|
||||
'username' => 'darth',
|
||||
'email' => 'd.vader@theempire.com'
|
||||
];
|
||||
|
||||
$userModel->save($data);
|
||||
$userModel->save($data);
|
||||
|
||||
// Performs an update, since the primary key, 'id', is found.
|
||||
$data = [
|
||||
'id' => 3,
|
||||
'username' => 'darth',
|
||||
'email' => 'd.vader@theempire.com'
|
||||
];
|
||||
$userModel->save($data);
|
||||
// Performs an update, since the primary key, 'id', is found.
|
||||
$data = [
|
||||
'id' => 3,
|
||||
'username' => 'darth',
|
||||
'email' => 'd.vader@theempire.com'
|
||||
];
|
||||
$userModel->save($data);
|
||||
|
||||
The save method also can make working with custom class result objects much simpler by recognizing a non-simple
|
||||
object and grabbing its public and protected values into an array, which is then passed to the appropriate
|
||||
@ -373,59 +373,59 @@ class is responsible for maintaining the business logic surrounding the object i
|
||||
elements in a certain way, etc. They shouldn't have any idea about how they are saved to the database. At their
|
||||
simplest, they might look like this::
|
||||
|
||||
namespace App\Entities;
|
||||
namespace App\Entities;
|
||||
|
||||
class Job
|
||||
{
|
||||
protected $id;
|
||||
protected $name;
|
||||
protected $description;
|
||||
class Job
|
||||
{
|
||||
protected $id;
|
||||
protected $name;
|
||||
protected $description;
|
||||
|
||||
public function __get($key)
|
||||
{
|
||||
if (property_exists($this, $key))
|
||||
{
|
||||
return $this->$key;
|
||||
}
|
||||
}
|
||||
public function __get($key)
|
||||
{
|
||||
if (property_exists($this, $key))
|
||||
{
|
||||
return $this->$key;
|
||||
}
|
||||
}
|
||||
|
||||
public function __set($key, $value)
|
||||
{
|
||||
if (property_exists($this, $key))
|
||||
{
|
||||
$this->$key = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function __set($key, $value)
|
||||
{
|
||||
if (property_exists($this, $key))
|
||||
{
|
||||
$this->$key = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
A very simple model to work with this might look like::
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class JobModel extends Model
|
||||
{
|
||||
protected $table = 'jobs';
|
||||
protected $returnType = '\App\Entities\Job';
|
||||
protected $allowedFields = [
|
||||
'name', 'description'
|
||||
];
|
||||
}
|
||||
class JobModel extends Model
|
||||
{
|
||||
protected $table = 'jobs';
|
||||
protected $returnType = '\App\Entities\Job';
|
||||
protected $allowedFields = [
|
||||
'name', 'description'
|
||||
];
|
||||
}
|
||||
|
||||
This model works with data from the ``jobs`` table, and returns all results as an instance of ``App\Entities\Job``.
|
||||
When you need to persist that record to the database, you will need to either write custom methods, or use the
|
||||
model's ``save()`` method to inspect the class, grab any public and private properties, and save them to the database::
|
||||
|
||||
// Retrieve a Job instance
|
||||
$job = $model->find(15);
|
||||
// Retrieve a Job instance
|
||||
$job = $model->find(15);
|
||||
|
||||
// Make some changes
|
||||
$job->name = "Foobar";
|
||||
// Make some changes
|
||||
$job->name = "Foobar";
|
||||
|
||||
// Save the changes
|
||||
$model->save($job);
|
||||
// Save the changes
|
||||
$model->save($job);
|
||||
|
||||
.. note:: If you find yourself working with Entities a lot, CodeIgniter provides a built-in :doc:`Entity class </models/entities>`
|
||||
that provides several handy features that make developing Entities simpler.
|
||||
that provides several handy features that make developing Entities simpler.
|
||||
|
||||
Deleting Data
|
||||
-------------
|
||||
@ -434,7 +434,7 @@ Deleting Data
|
||||
|
||||
Takes a primary key value as the first parameter and deletes the matching record from the model's table::
|
||||
|
||||
$userModel->delete(12);
|
||||
$userModel->delete(12);
|
||||
|
||||
If the model's $useSoftDeletes value is true, this will update the row to set ``deleted_at`` to the current
|
||||
date and time. You can force a permanent delete by setting the second parameter as true.
|
||||
@ -452,7 +452,7 @@ previously::
|
||||
|
||||
Cleans out the database table by permanently removing all rows that have 'deleted_at IS NOT NULL'. ::
|
||||
|
||||
$userModel->purgeDeleted();
|
||||
$userModel->purgeDeleted();
|
||||
|
||||
Validating Data
|
||||
---------------
|
||||
@ -464,81 +464,81 @@ prior to saving to the database with the ``insert()``, ``update()``, or ``save()
|
||||
The first step is to fill out the ``$validationRules`` class property with the fields and rules that should
|
||||
be applied. If you have custom error message that you want to use, place them in the ``$validationMessages`` array::
|
||||
|
||||
class UserModel extends Model
|
||||
{
|
||||
protected $validationRules = [
|
||||
'username' => 'required|alpha_numeric_space|min_length[3]',
|
||||
'email' => 'required|valid_email|is_unique[users.email]',
|
||||
'password' => 'required|min_length[8]',
|
||||
'pass_confirm' => 'required_with[password]|matches[password]'
|
||||
];
|
||||
class UserModel extends Model
|
||||
{
|
||||
protected $validationRules = [
|
||||
'username' => 'required|alpha_numeric_space|min_length[3]',
|
||||
'email' => 'required|valid_email|is_unique[users.email]',
|
||||
'password' => 'required|min_length[8]',
|
||||
'pass_confirm' => 'required_with[password]|matches[password]'
|
||||
];
|
||||
|
||||
protected $validationMessages = [
|
||||
'email' => [
|
||||
'is_unique' => 'Sorry. That email has already been taken. Please choose another.'
|
||||
]
|
||||
];
|
||||
}
|
||||
protected $validationMessages = [
|
||||
'email' => [
|
||||
'is_unique' => 'Sorry. That email has already been taken. Please choose another.'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
The other way to set the validation message to fields by functions,
|
||||
|
||||
.. php:function:: setValidationMessage($field, $fieldMessages)
|
||||
|
||||
:param string $field
|
||||
:param array $fieldMessages
|
||||
:param string $field:
|
||||
:param array $fieldMessages:
|
||||
|
||||
This function will set the field wise error messages.
|
||||
This function will set the field wise error messages.
|
||||
|
||||
Usage example::
|
||||
Usage example::
|
||||
|
||||
$fieldName = 'name';
|
||||
$fieldValidationMessage = array(
|
||||
'required' => 'Your name is required here',
|
||||
);
|
||||
$model->setValidationMessage($fieldName, $fieldValidationMessage);
|
||||
$fieldName = 'name';
|
||||
$fieldValidationMessage = [
|
||||
'required' => 'Your name is required here',
|
||||
];
|
||||
$model->setValidationMessage($fieldName, $fieldValidationMessage);
|
||||
|
||||
.. php:function:: setValidationMessages($fieldMessages)
|
||||
|
||||
:param array $fieldMessages
|
||||
:param array $fieldMessages:
|
||||
|
||||
This function will set the field messages.
|
||||
This function will set the field messages.
|
||||
|
||||
Usage example::
|
||||
Usage example::
|
||||
|
||||
$fieldValidationMessage = array(
|
||||
'name' => array(
|
||||
'required' => 'Your baby name is missing.',
|
||||
'min_length' => 'Too short, man!',
|
||||
),
|
||||
);
|
||||
$model->setValidationMessages($fieldValidationMessage);
|
||||
$fieldValidationMessage = [
|
||||
'name' => [
|
||||
'required' => 'Your baby name is missing.',
|
||||
'min_length' => 'Too short, man!',
|
||||
],
|
||||
];
|
||||
$model->setValidationMessages($fieldValidationMessage);
|
||||
|
||||
Now, whenever you call the ``insert()``, ``update()``, or ``save()`` methods, the data will be validated. If it fails,
|
||||
the model will return boolean **false**. You can use the ``errors()`` method to retrieve the validation errors::
|
||||
|
||||
if ($model->save($data) === false)
|
||||
{
|
||||
return view('updateUser', ['errors' => $model->errors()];
|
||||
}
|
||||
if ($model->save($data) === false)
|
||||
{
|
||||
return view('updateUser', ['errors' => $model->errors()];
|
||||
}
|
||||
|
||||
This returns an array with the field names and their associated errors that can be used to either show all of the
|
||||
errors at the top of the form, or to display them individually::
|
||||
|
||||
<?php if (! empty($errors)) : ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php foreach ($errors as $field => $error) : ?>
|
||||
<p><?= $error ?></p>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php if (! empty($errors)) : ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php foreach ($errors as $field => $error) : ?>
|
||||
<p><?= $error ?></p>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
If you'd rather organize your rules and error messages within the Validation configuration file, you can do that
|
||||
and simply set ``$validationRules`` to the name of the validation rule group you created::
|
||||
|
||||
class UserModel extends Model
|
||||
{
|
||||
protected $validationRules = 'users';
|
||||
}
|
||||
class UserModel extends Model
|
||||
{
|
||||
protected $validationRules = 'users';
|
||||
}
|
||||
|
||||
Retrieving Validation Rules
|
||||
---------------------------
|
||||
@ -580,7 +580,7 @@ that has an id matching the placeholder's value. Assuming that the form POST dat
|
||||
$_POST = [
|
||||
'id' => 4,
|
||||
'email' => 'foo@example.com'
|
||||
]
|
||||
];
|
||||
|
||||
then the ``{id}`` placeholder would be replaced with the number **4**, giving this revised rule::
|
||||
|
||||
@ -602,14 +602,14 @@ in addition to these will be removed prior to hitting the database. This is grea
|
||||
or primary keys do not get changed.
|
||||
::
|
||||
|
||||
protected $allowedFields = ['name', 'email', 'address'];
|
||||
protected $allowedFields = ['name', 'email', 'address'];
|
||||
|
||||
Occasionally, you will find times where you need to be able to change these elements. This is often during
|
||||
testing, migrations, or seeds. In these cases, you can turn the protection on or off::
|
||||
|
||||
$model->protect(false)
|
||||
->insert($data)
|
||||
->protect(true);
|
||||
$model->protect(false)
|
||||
->insert($data)
|
||||
->protect(true);
|
||||
|
||||
Working With Query Builder
|
||||
--------------------------
|
||||
@ -624,13 +624,13 @@ This builder is already set up with the model's $table.
|
||||
You can also use Query Builder methods and the Model's CRUD methods in the same chained call, allowing for
|
||||
very elegant use::
|
||||
|
||||
$users = $userModel->where('status', 'active')
|
||||
->orderBy('last_login', 'asc')
|
||||
->findAll();
|
||||
$users = $userModel->where('status', 'active')
|
||||
->orderBy('last_login', 'asc')
|
||||
->findAll();
|
||||
|
||||
.. note:: You can also access the model's database connection seamlessly::
|
||||
|
||||
$user_name = $userModel->escape($name);
|
||||
$user_name = $userModel->escape($name);
|
||||
|
||||
Runtime Return Type Changes
|
||||
----------------------------
|
||||
@ -640,23 +640,23 @@ $returnType. There may be times that you would like the data back in a different
|
||||
provides methods that allow you to do just that.
|
||||
|
||||
.. note:: These methods only change the return type for the next find*() method call. After that,
|
||||
it is reset to its default value.
|
||||
it is reset to its default value.
|
||||
|
||||
**asArray()**
|
||||
|
||||
Returns data from the next find*() method as associative arrays::
|
||||
|
||||
$users = $userModel->asArray()->where('status', 'active')->findAll();
|
||||
$users = $userModel->asArray()->where('status', 'active')->findAll();
|
||||
|
||||
**asObject()**
|
||||
|
||||
Returns data from the next find*() method as standard objects or custom class intances::
|
||||
|
||||
// Return as standard objects
|
||||
$users = $userModel->asObject()->where('status', 'active')->findAll();
|
||||
// Return as standard objects
|
||||
$users = $userModel->asObject()->where('status', 'active')->findAll();
|
||||
|
||||
// Return as custom class instances
|
||||
$users = $userModel->asObject('User')->where('status', 'active')->findAll();
|
||||
// Return as custom class instances
|
||||
$users = $userModel->asObject('User')->where('status', 'active')->findAll();
|
||||
|
||||
Processing Large Amounts of Data
|
||||
--------------------------------
|
||||
@ -669,11 +669,11 @@ parameter is a Closure that will be called for each row of data.
|
||||
This is best used during cronjobs, data exports, or other large tasks.
|
||||
::
|
||||
|
||||
$userModel->chunk(100, function ($data)
|
||||
{
|
||||
// do something.
|
||||
// $data is a single row of data.
|
||||
});
|
||||
$userModel->chunk(100, function ($data)
|
||||
{
|
||||
// do something.
|
||||
// $data is a single row of data.
|
||||
});
|
||||
|
||||
Model Events
|
||||
============
|
||||
@ -695,15 +695,15 @@ must return the original $data array so other callbacks have the full informatio
|
||||
|
||||
::
|
||||
|
||||
protected function hashPassword(array $data)
|
||||
{
|
||||
if (! isset($data['data']['password']) return $data;
|
||||
protected function hashPassword(array $data)
|
||||
{
|
||||
if (! isset($data['data']['password']) return $data;
|
||||
|
||||
$data['data']['password_hash'] = password_hash($data['data']['password'], PASSWORD_DEFAULT);
|
||||
unset($data['data']['password'];
|
||||
$data['data']['password_hash'] = password_hash($data['data']['password'], PASSWORD_DEFAULT);
|
||||
unset($data['data']['password'];
|
||||
|
||||
return $data;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
Specifying Callbacks To Run
|
||||
---------------------------
|
||||
@ -712,8 +712,8 @@ You specify when to run the callbacks by adding the method name to the appropria
|
||||
etc). Multiple callbacks can be added to a single event and they will be processed one after the other. You can
|
||||
use the same callback in multiple events::
|
||||
|
||||
protected $beforeInsert = ['hashPassword'];
|
||||
protected $beforeUpdate = ['hashPassword'];
|
||||
protected $beforeInsert = ['hashPassword'];
|
||||
protected $beforeUpdate = ['hashPassword'];
|
||||
|
||||
Event Parameters
|
||||
----------------
|
||||
@ -764,14 +764,14 @@ Model gives you out of the box, and create a fully custom experience.
|
||||
|
||||
<?php namespace App\Models;
|
||||
|
||||
use CodeIgniter\Database\ConnectionInterface;
|
||||
use CodeIgniter\Database\ConnectionInterface;
|
||||
|
||||
class UserModel
|
||||
{
|
||||
protected $db;
|
||||
class UserModel
|
||||
{
|
||||
protected $db;
|
||||
|
||||
public function __construct(ConnectionInterface &$db)
|
||||
{
|
||||
$this->db =& $db;
|
||||
}
|
||||
}
|
||||
public function __construct(ConnectionInterface &$db)
|
||||
{
|
||||
$this->db =& $db;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user