Skip to content

Commit c870828

Browse files
committed
Validation feature
1 parent d2cd699 commit c870828

File tree

2 files changed

+399
-53
lines changed

2 files changed

+399
-53
lines changed

README.md

Lines changed: 216 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ This ORM Model extension is collected into [yidas/codeigniter-pack](https://gith
1717
FEATURES
1818
--------
1919

20-
- ***Elegant patterns** as Laravel Eloquent ORM & Yii2 Active Record*
20+
- ***ORM** Model with **Elegant patterns** as Laravel Eloquent ORM & Yii2 Active Record*
2121

22-
- ***Codeigniter Query Builder** integration*
22+
- ***[CodeIgniter Query Builder](#find)** integration*
2323

24-
- ***Timestamps Behavior** & **Soft Deleting** & **Query Scopes** support*
24+
- ***[Timestamps Behavior](#timestamps)** & **[Validation](#validation)** & **[Soft Deleting](#soft-deleted)** & **[Query Scopes](#query-scopes)** support*
2525

26-
- ***Read & Write Splitting** for Replications*
26+
- ***[Read & Write Splitting](#read--write-connections)** for Replications*
2727

2828
This package provide Base Model which extended `CI_Model` and provided full CRUD methods to make developing database interactions easier and quicker for your CodeIgniter applications.
2929

@@ -52,6 +52,7 @@ OUTLINE
5252
- [delete()](#delete)
5353
- [getLastInsertID()](#getlastinsertid)
5454
- [getAffectedRows()](#getaffectedrows)
55+
- [count()](#count)
5556
- [setAlias()](#setalias)
5657
- [Active Record (ORM)](#active-record-orm)
5758
- [Inserts](#inserts)
@@ -69,6 +70,15 @@ OUTLINE
6970
- [Query Scopes](#query-scopes)
7071
- [Configuration](#configuration-2)
7172
- [Methods](#method-3)
73+
- [Validation](#validation)
74+
- [Validating Input](#validating-input)
75+
- [validate()](#validate)
76+
- [getErrors()](#geterrors)
77+
- [Declaring Rules](#declaring-rules)
78+
- [rules()](#rules)
79+
- [Error Message with Language](#error-message-with-language)
80+
- [Filters](#filters)
81+
- [Filters()](#filters-1)
7282
- [Read & Write Connections](#read--write-connections)
7383
- [Configuration](#configuration-3)
7484
- [Load Balancing for Databases](#load-balancing-for-databases)
@@ -107,11 +117,12 @@ The Model would defined database coonnections and table itself.
107117

108118
```php
109119
$records = $this->Posts_model->find()
110-
->where('is_public', '1')
111-
->limit(25)
112-
->order_by('id')
113-
->get()
114-
->result_array();
120+
->select('*')
121+
->where('is_public', '1')
122+
->limit(25)
123+
->order_by('id')
124+
->get()
125+
->result_array();
115126
```
116127

117128
### CRUD
@@ -347,6 +358,7 @@ public CI_DB_query_builder find(boolean $withAll=false)
347358
*Example:*
348359
```php
349360
$records = $this->Model->find()
361+
->select('*')
350362
->where('is_public', '1')
351363
->limit(25)
352364
->order_by('id')
@@ -365,6 +377,8 @@ $records = $this->Model->find(true)
365377
$this->Model->withAll()->find();
366378
```
367379

380+
> After starting `find()` from a model, it return original `CI_DB_query_builder` for chaining. The query builder could refer [CodeIgniter Query Builder Class Document](https://www.codeigniter.com/userguide3/database/query_builder.html)
381+
368382
##### Query Builder Implementation
369383

370384
You could assign Query Builder as a variable to handle add-on conditions instead of using `$this->Model->getBuilder()`.
@@ -395,7 +409,7 @@ $this->Model->reset()->find();
395409
Insert a row with Timestamps feature into the associated database table using the attribute values of this record.
396410

397411
```php
398-
public boolean insert(array $attributes)
412+
public boolean insert(array $attributes, $runValidation=true)
399413
```
400414

401415
*Example:*
@@ -411,7 +425,7 @@ $result = $this->Model->insert([
411425
Insert a batch of rows with Timestamps feature into the associated database table using the attribute values of this record.
412426

413427
```php
414-
public integer batchInsert(array $data)
428+
public integer batchInsert(array $data, $runValidation=true)
415429
```
416430

417431
*Example:*
@@ -427,7 +441,7 @@ $result = $this->Model->batchInsert([
427441
Replace a row with Timestamps feature into the associated database table using the attribute values of this record.
428442

429443
```php
430-
public boolean replace(array $attributes)
444+
public boolean replace(array $attributes, $runValidation=true)
431445
```
432446

433447
*Example:*
@@ -444,7 +458,7 @@ $result = $this->Model->replace([
444458
Save the changes with Timestamps feature to the selected record(s) into the associated database table.
445459

446460
```php
447-
public boolean update(array $attributes, array|string $condition=NULL)
461+
public boolean update(array $attributes, array|string $condition=NULL, $runValidation=true)
448462
```
449463

450464
*Example:*
@@ -467,7 +481,7 @@ $result = $this->Model->update(['status'=>'off']);
467481
Update a batch of update queries into combined query strings.
468482

469483
```php
470-
public integer batchUpdate(array $dataSet, boolean $withAll=false, interger $maxLength=4*1024*1024)
484+
public integer batchUpdate(array $dataSet, boolean $withAll=false, interger $maxLength=4*1024*1024, $runValidation=true)
471485
```
472486

473487
*Example:*
@@ -527,6 +541,20 @@ $result = $this->Model->update(['name' => 'Nick Tsai'], 32);
527541
$affectedRows = $this->Model->getAffectedRows();
528542
```
529543

544+
#### `count()`
545+
546+
Get count from query
547+
548+
```php
549+
public integer count(boolean $resetQuery=true)
550+
```
551+
552+
*Example:*
553+
```php
554+
$result = $this->Model->find()->where("age <", 20);
555+
$totalCount = $this->Model->count();
556+
```
557+
530558
#### `setAlias()`
531559

532560
Set table alias
@@ -658,7 +686,7 @@ $this->Model->findAll();
658686
Active Record (ORM) save for insert or update
659687

660688
```php
661-
public boolean save()
689+
public boolean save($runValidation=true)
662690
```
663691

664692
#### `toArray()`
@@ -836,10 +864,179 @@ public self withAll()
836864
```php
837865
$this->Model->withAll()->find();
838866
```
867+
---
868+
869+
VALIDATION
870+
----------
871+
872+
As a rule of thumb, you should never trust the data received from end users and should always validate it before putting it to good use.
873+
874+
The ORM Model validation integrates [CodeIgniter Form Validation](https://www.codeigniter.com/userguide3/libraries/form_validation.html) that provides consistent and smooth way to deal with model data validation.
875+
876+
### Validating Input
877+
878+
Given a model populated with user inputs, you can validate the inputs by calling the `validate()` method. The method will return a boolean value indicating whether the validation succeeded or not. If not, you may get the error messages from `getErrors()` method.
879+
880+
#### `validate()`
881+
882+
Performs the data validation with filters
883+
884+
> ORM only performs validation for assigned properties.
885+
886+
```php
887+
public boolean validate($data=[], $returnData=false)
888+
```
889+
890+
*Exmaple:*
891+
892+
```php
893+
$this->load->model('PostsModel');
894+
895+
if ($this->PostsModel->validate($inputData)) {
896+
// all inputs are valid
897+
} else {
898+
// validation failed: $errors is an array containing error messages
899+
$errors = $this->PostsModel->getErrors();
900+
}
901+
```
902+
903+
> The methods of `yidas\Model` for modifying such as `insert()` and `update()` will also perform validation. You can turn off `$runValidation` parameter of methods if you ensure that the input data has been validated.
904+
905+
*Exmaple of ORM Model:*
906+
907+
```php
908+
$this->load->model('PostsModel');
909+
$post = new PostsModel;
910+
$post->title = '';
911+
// ORM assigned or modified attributes will be validated by calling `validate()` without parameters
912+
if ($post->validate()) {
913+
// Already performing `validate()` so that turn false for $runValidation
914+
$result = $post->save(false);
915+
} else {
916+
// validation failed: $errors is an array containing error messages
917+
$errors = post->getErrors();
918+
}
919+
```
920+
921+
> A ORM model's properties will be changed by filter after performing validation. If you have previously called `validate()`.
922+
You can turn off `$runValidation` of `save()` for saving without repeated validation.
923+
924+
### getErrors()
925+
926+
Validation - Get error data referenced by last failed Validation
927+
928+
```php
929+
public array getErrors()
930+
```
931+
932+
### Declaring Rules
933+
934+
To make `validate()` really work, you should declare validation rules for the attributes you plan to validate. This should be done by overriding the `rules()` method.
935+
936+
#### `rules()`
937+
938+
Returns the validation rules for attributes.
939+
940+
```php
941+
public array rules()
942+
```
943+
944+
*Example:*
945+
946+
```php
947+
class PostsModel extends yidas\Model
948+
{
949+
protected $table = "posts";
950+
951+
/**
952+
* Override rules function with validation rules setting
953+
*/
954+
public function rules()
955+
{
956+
return [
957+
[
958+
'field' => 'title',
959+
'rules' => 'required|min_length[3]',
960+
],
961+
];
962+
}
963+
}
964+
```
965+
966+
> The validation rules and pattern could refer [CodeIgniter Rule Reference](https://www.codeigniter.com/userguide3/libraries/form_validation.html#rule-reference)
967+
968+
#### Error Message with Language
969+
970+
When you are dealing with i18n issue of validation's error message, you can integrate [CodeIgniter language class](https://www.codeigniter.com/userguide3/libraries/language.html) into rules. The following sample code is available for you to implement:
971+
972+
```php
973+
public function rules()
974+
{
975+
/**
976+
* Set CodeIgniter language
977+
* @see https://www.codeigniter.com/userguide3/libraries/language.html
978+
*/
979+
$this->lang->load('error_messages', 'en-US');
980+
981+
return [
982+
[
983+
'field' => 'title',
984+
'rules' => 'required|min_length[3]',
985+
'errors' => [
986+
'required' => $this->lang->line('required'),
987+
'min_length' => $this->lang->line('min_length'),
988+
],
989+
],
990+
];
991+
}
992+
```
993+
994+
In above case, the language file could be `application/language/en-US/error_messages_lang.php`:
995+
996+
```php
997+
$lang['required'] = '`%s` is required';
998+
$lang['min_length'] = '`%s` requires at least %d letters';
999+
```
1000+
1001+
After that, the `getErrors()` could returns field error messages with current language.
1002+
1003+
### Filters
1004+
1005+
User inputs often need to be filtered or preprocessed. For example, you may want to trim the spaces around the username input. You may declare filter rules in `filter()` method to achieve this goal.
1006+
1007+
> In model's `validate()` process, the `filters()` will be performed before [`rules()`](#declaring-rules), which means the input data validated by [`rules()`](#declaring-rules) is already be filtered.
1008+
1009+
To enable filters for `validate()`, you should declare filters for the attributes you plan to perform. This should be done by overriding the `filters()` method.
1010+
1011+
#### `filters()`
1012+
1013+
Returns the filter rules for validation.
1014+
1015+
```php
1016+
public array filters()
1017+
```
1018+
1019+
*Example:*
1020+
1021+
```php
1022+
public function filters()
1023+
{
1024+
return [
1025+
[['title', 'name'], 'trim'], // Perform `trim()` for title & name input data
1026+
[['title'], 'static::method'], // Perform `public static function method($value)` in this model
1027+
[['name'], function($value) { // Perform defined anonymous function. 'value' => '[Filtered]value'
1028+
return "[Filtered]" . $value;
1029+
}],
1030+
];
1031+
}
1032+
```
1033+
1034+
> The filters format: `[[['attr1','attr2'], callable],]`
1035+
8391036

8401037
---
8411038

842-
Read & Write Connections
1039+
READ & WRITE CONNECTIONS
8431040
------------------------
8441041

8451042
Sometimes you may wish to use one database connection for `SELECT` statements, and another for `INSERT`, `UPDATE`, and `DELETE` statements. This Model implements Replication and Read-Write Splitting, makes database connections will always be used while using Model usages.
@@ -971,7 +1168,9 @@ $this->Model->getDB()->trans_complete();
9711168
HELPERS
9721169
-------
9731170

974-
### `indexBy()`
1171+
The model provides several helper methods:
1172+
1173+
#### `indexBy()`
9751174

9761175
Index by Key
9771176

0 commit comments

Comments
 (0)