Ở bài Bài 8 chúng ta đã cùng tìm hiểu cách sử dụng Validation, biết được một số tập luật mà CakePHP hỗ trợ, cũng như tự tạo ra tập luật cho riêng mình, vậy tiếp theo ở bài này chúng ta sẽ cùng đi sâu hơn những vấn đề trên và tìm hiểu thêm vấn đề về Behavior.

Validation Cakephp:

Ở đây xin nhắc lại một chút về Validation, $validate được định nghĩa trong Model

Luật đơn giản nhất cho việc kiểm tra là theo kiểu: ‘tên trường dữ liệu’ => ‘tên rule được định nghĩa sẵn bởi CakePHP’ hay còn gọi là Simple Rules. Ví dụ:


class User extends AppModel {
 public $validate = array(
 'username' => 'alphaNumeric', //kí tự alphabe hay số
 'email' => 'email', // định dạng email
 'born' => 'date' // dữ liệu ngày tháng
 );
}

Các hàm mà CakePHP đã trang bị sẵn cho chúng ta sử dụng:

  • alphaNumeric(mixed $check) : chỉ cho phép chữ và số
  • lengthBetween(string $check, integer $min, integer $max) : trong khoảng
  • blank(mixed $check): đảm bảo không có ký tự khoảng trắng .
  • boolean(string $check) : chỉ được là giá trị boolean
  • cc(mixed $check, mixed $type = ‘fast’, boolean $deep = false, string $regex = null) : check credit card
  • comparison(mixed $check1, string $operator = null, integer $check2 = null) : so sánh 2 giá trị số
  • custom(mixed $check, string $regex = null) : được dùng khi cần đến một Regular Expression
  • date(string $check, mixed $format = ‘ymd’, string $regex = null) : kiểm tra ngày tháng năm
  • datetime(array $check, mixed $dateFormat = ‘ymd’, string $regex = null) : kiểm tra ngày giờ
  • decimal(string $check, integer $places = null, string $regex = null) : check xem có thỏa mãn giá trị thập phân không
  • email(string $check, boolean $deep = false, string $regex = null) : check xem có phải là email không
  • equalTo(mixed $check, mixed $compareTo) : so sánh hai chuỗi
  • extension(mixed $check, array $extensions = array(‘gif’, ‘jpeg’, ‘png’, ‘jpg’)) : kiểm tra đuôi mở rộng
  • fileSize($check, $operator = null, $size = null) : check kích cỡ của file
  • inList(string $check, array $list, boolean $caseInsensitive = false): check có nằm trong list hay không
  • ip(string $check, string $type = ‘both’): check xem có phải IP không
  • isUnique() : kiểm tra giá trị có phải đơn nhất
  • maxLength(string $check, integer $max) : check số kí tự tối đa
  • mimeType(mixed $check, array|string $mimeTypes) : kiểm tra format của mime
  • minLength(string $check, integer $min):check độ số kí tự tối thiểu
  • multiple(mixed $check, mixed $options = array(), boolean $caseInsensitive = false): check với trường hợp có thể chọn nhiều item
  • notEmpty(mixed $check): đảm bảo trường dữ liệu không là 0 hoặc chuỗi trống(nhỏ hơn phiên bản 2.7).
  • notBlank(mixed $check): đảm bảo trường dữ liệu không là 0 hoặc chuỗi trống(từ 2.7 trở lên)
  • numeric(string $check) : đảm bảo giá trị là số
  • naturalNumber(mixed $check, boolean $allowZero = false) : check số tự nhiên mới (trong phiên bản 2.2)
  • phone(mixed $check, string $regex = null, string $country = ‘all’xác nhận số điện thoại tùy theo quốc gia
  • postal(mixed $check, string $regex = null, string $country = ‘us’) xác nhận zipcode 
  • range(string $check, integer $lower = null, integer $upper = null): kiểm tra giá trị có trong khoảng giá trị
  • time(string $check) xác nhận chuỗi có là thời gian hợp lệ.
  • uploadError(mixed $check): kiểm tra file tải lệ có lỗi hay không (mới trong phiên bản 2.2)
  • url(string $check, boolean $strict = false): có đúng format của URL không.

Các cách định nghĩa luật lệ cho các trường dữ liệu:

a) One Rule Per Field (một luật một trường).

Kỹ thuật này cho phép kiểm soát tốt hơn việc các luật sẽ làm việc như thế nào.


public $validate = array(
 'fieldName1' => array(
 // hoặc có dạng : array('ruleName', 'param1', 'param2' ...)
 'rule' => 'ruleName',
 'required' => true,
 'allowEmpty' => false,
 // create hoặc update
 'on' => 'create',
 'message' => 'Thông báo'
 )
);

Tìm hiểu về các key trên:

  • rule : định nghĩa phương thức validate, có thể là một giá trị hay một mảng. Khi chỉ được nhập kí tự alphabe và số thì sẽ là một giá trị đơn (‘rule’ => ‘alphaNumeric’), còn nếu giá trị cần nhiều tham số thì sẽ là một mảng (‘rule’ => array(‘minLength’, 8)).
  • required : key này nhận vào giá trị boolean, chuỗi create hay update. Nếu giá trị set là true thì sẽ luôn bắt buộc, nếu set create thì chỉ bắt buộc khi tạo mới, cuối cùng update sẽ có hiệu lực khi cập nhật dữ liệu.
  • allowEmpty :nếu set key với giá trị false thì trường được áp luật lệ này không được empty.
  • on : key này có thể set là create hay update để điều khiển việc luật lệ sẽ được thực hiện khi tạo mới hay chỉ khi cập nhật dữ liệu.
  • message : nội dung thông báo lỗi.

b) Multiple Rules per Field (Nhiều luật một trường)

Chúng ta xem ví dụ:


public $validate = array(
 'login' => array(
 'rule1' => array(
 'rule' => 'alphaNumeric',
 'message' => 'Chỉ cho phép alphabets và numbers',
 'last' => false
 ),
 'rule2' => array(
 'rule' => array('minLength', 8),
 'message' => 'Tối thiểu 8 kí tự'
 )
 )
);

Cách định nghĩa này cũng tương tự như “một luật một trường” nhưng nó sẽ cho phép áp dụng nhiều luật lệ validation trên một trường dữ liệu. Chú ý có thêm key là last: có chức năng cho phép xác định xem luật lệ nào được dừng lại, nó nhận giá trị true, false. Như ví dụ trên, sẽ chạy validate từ rule1 đến rule2, vì ở rule1 last được set false nên dù rule1 có validate thất bại thì rule2 vẫn được tiến hành. Nếu muốn dừng validate khi rule1 thất bại thì cần chọn last => true.

c) Tuỳ chỉnh Rules Validation

Dùng Regular Expression: Bài 8 chúng ta cũng đã tìm hiểu qua phần này, xin nhắc lại một tý thông qua ví dụ sau:


public $validate = array(
 'login' => array(
 'rule' => '/^[a-z0-9]{3,}$/i',
 'message' => 'Có thể là số và ký tự, tối thiểu là 3'
 )
);

Tạo riêng hàm validate: CakePHP không thể hỗ trợ hết cho chúng ta nhưng thức cần thiết, nên việc hỗ trợ cho mình tự tạo ra các hàm validate là một điểm cộng cho CakePHP. Ví dụ: chúng ta có mã khuyến mãi và quy định mã này chỉ được sử dụng 25 lần, code chúng ta như sau:


class User extends AppModel {
 public $validate = array(
 'promotion_code' => array(
 'rule' => array('limitDuplicates', 25),
 'message' => 'Mã này đã được sử dụng quá số lần quy định.'
 )
 );

public function limitDuplicates($check, $limit) {
 $existingPromoCount = $this->find('count', array(
 'conditions' => $check,
 'recursive' => -1
 ));
 return $existingPromoCount < $limit;
}

Trong đó:

  • $check là điều kiện lọc dữ liệu khi nhập mà khuyến mãi, $check = array(‘promotion_code’ => ‘some-value’)
  • $limit có giá trị là 25.

Ở ví dụ trên ta tạo một hàm public (protectedprivate không được hỗ trợ) để xử lý việc validate và cách gọi thì giống với các key sẵn có của CakePHP. Bạn có thể để hàm validate của mình ở Model hoặc Behavior, vì các hàm ở Model/behavior sẽ được kiểm tra trước khi tìm đến lớp validation. Do vậy, bạn có thể viết chồng lên những hàm validate sẵn có của CakePHP. Điều cuối cùng bạn cần quan tâm là kết quả trả về của hàm custom của bạn : Nếu giá trị đúng thì trả về true, ngược lại hãy trả về false. Và nếu là một chuỗi thì đó được coi như một thông báo lỗi khi validate thất bại.

d) Tự động thay đổi các quy tắc: với quy tắc này ta có thể tự động thêm, cập nhật, xóa các luật lệ hiện có để có thể linh hoạt hơn trong lập trình.

Thêm vào luật lệ mới: add()

Mới trong phiên bản 2.2

$this->validator()->add('password', 'required', array(
 'rule' => 'notEmpty',
 'required' => 'create'
));

với đoạn trên nghĩa là thêm vào luật notEmpty đối với trường password, có thể dùng nhiều hàm add() để thêm nhiều luật cùng lúc cho password

$this->validator()
 ->add('password', 'required', array(
 'rule' => 'notBlank',
 'required' => 'create'
 ))
 ->add('password', 'size', array(
 'rule' => array('lengthBetween', 8, 20),
 'message' => 'Password should be at least 8 chars long'
 ));

//Hoặc có thể viết là

$this->validator()->add('password', array(
 'required' => array(
 'rule' => 'notBlank',
 'required' => 'create'
 ),
 'size' => array(
 'rule' => array('lengthBetween', 8, 20),
 'message' => 'Password should be at least 8 chars long'
 )
));

Chỉnh sửa luật hiện có: 

Mới trong phiên bản 2.2

CakePHP cung cấp một số hàm để có thể thay đổi, mở rộng hay bỏ luật lệ nào đó. Như với trường hợp trên, bạn muốn thay đổi luật lệ từ notEmpty sang required và thay vì chỉ lúc create sẽ là validate mọi lúc.

$this->validator()->getField('password')->setRule('required', array(
 'rule' => 'required', // thay đổi từ notEmpty sang required
 'required' => true // thay đổi từ create sang true
));

Nếu chỉ muốn thay đổi một thuộc tính của luật lệ thì bạn có thể dùng tên thuộc tính một cách trực tiếp như ví dụ sau :

$this->validator()->getField('password')->getRule('required')->message = 'Trường này không được rỗng';

Xóa bỏ luật lệ

Mới trong phiên bản 2.2

Dùng hàm remove() để làm điều này bạn có thể xóa tất cả hoặc chỉ một số luật chỉ định

// Xóa bỏ tất cả luật lệ cho trường username
$this->validator()->remove('username');

// Chỉ bỏ đi luật 'required' khỏi trường password
$this->validator()->remove('password', 'required');

Behavior:

Là cách tổ chức những hàm chức năng được định nghĩa trong Model, nó cho phép chúng ta tách và tái sử dụng logic, nó cũng không bắt buộc việc kế thừa. CakePHP cung cấp cho ta bốn loại behavior là ACL, Containable, Translate, Tree. Ở bài này chúng ta đề cập đến cách sử dụng, cách tạo ra behavior. Phần chi tiết của từng loại sẽ đề cập sau.

a) Sử dụng behavior: sử dụng biến $actAs thì các behavior sẽ được attach vào Model. Khai báo đơn giản public $actsAs array(‘Tree’); nó sẽ TreeBehavior. Một vài Behavior nó cho phép hoặc bắt buộc một số khai báo trong cú pháp:

class Category extends AppModel {
  public $actsAs = array(
    'Tree' => array(
       'left' => 'left_node',
       'right' => 'right_node'
     ),
     'Translate'
   );
}

Như trên đã có setting cho TreeBehavior biết tên của trường ‘left’ là ‘left_node’ và ‘right’ là ‘right_node’. Trong ví dụ trên có khai báo thêm behavior Translate làm tượng tự với các Behavior khác.

Nếu muốn bỏ đi hiệu lực của Behavior thì có thể dùng, ví dụ : $this->Category->Behaviors->unload(‘Translate’); Trong thực tế chúng ta thường sẽ vô hiệu hóa việc behavior handle những callbacks của Model : $this->Category->Behaviors->disable(‘Translate’); và khi cần thì bật nó lên:

if (!$this->Category->Behaviors->enabled('Translate')) {
    $this->Category->Behaviors->enable('Translate');
}

Trong trường hợp cần attach mới một behavior nào đó bằng hàm load() : $this->Category->Behaviors->load(‘Christmas’);

$this->Category->Behaviors->load(‘Tree’, array(‘left’ => ‘new_left_node’)); cách này để cài đặt lại behavior đã được định nghĩa trước đó.

Cuối cùng, CakePHP cho phép xem danh sách những behavior nào đang được attach vào Model rồi bằng hàm loaded(): $behaviors = $this->Category->Behaviors->loaded();

b) Tạo ra Behaviors

Khi behavior được attach vào Model thì callbacks sẽ được gọi một cách tự động. Những callbacks tương tự như trong Models : beforeFind, afterFind, beforeValidate, afterValidate, beforeSave, afterSave, beforeDelete, afterDeleteonError. Behavior được đặt trong thư mục app/Model/Behavior. Và tên thì sẽ đặt dạng có hậu tố là Behavior, ví dụ như NameBehavior.php .Khi tạo behaviors thì hàm setup() sẽ được gọi.

public function setup(Model $Model, $settings = array()) {
   if (!isset($this->settings[$Model->alias])) {
      $this->settings[$Model->alias] = array(
        'option1_key' => 'option1_default_value',
        'option2_key' => 'option2_default_value',
        'option3_key' => 'option3_default_value',
      );
   }
     $this->settings[$Model->alias] = array_merge(
     $this->settings[$Model->alias], (array)$settings);
  }

c) Tạo phương thức

Phương thức của behavior có thể sử dụng ở bất kì một model nào làm việc với behavior. Ví dụ:

class Duck extends AppModel {
   public $actsAs = array('Flying');
}

Chúng ta có thể gọi y như trong Model bằng cách: $this->Duck->fly(‘caolanh’,’thapmuoi’);

d) Những callbacks trong behavior. Chúng sẽ được trigger trước khi mà những callbacks của Model được gọi:

  • setup(Model $Model, array $settings = array()):được gọi khi một behavior được attach vào model
  • cleanup(Model $Model): dùng khi detach behavior khỏi model
  • beforeFind(Model $Model, array $query): nếu mà trả về false thì sẽ không thực hiện hàm find()
  • afterFind(Model $Model, mixed $results, boolean $primary = false):có thể dùng để bổ sung kết quả find()
  • beforeValidate(Model $Model, array $options = array()):có ích khi muốn modify validate của model hay handle những logic nào đó trước khi validate.
  • afterValidate(Model $Model):có thể dùng để thực hiên cleanup hay chuẩn bị gì đó khi cần
  • beforeSave(Model $Model, array $options = array()):có thể trả về true để tiếp tục việc lưu dữ liệu hay trả về false để bỏ việc lưu trữ
  • afterSave(Model $Model, boolean $created, array $options = array()):có thể dùng để thực hiện cleanup sau khi lưu trữ thành công
  • beforeDelete(Model $Model, boolean $cascade = true): trả về true để tiếp tục việc lưu dữ liệu hay trả về false để bỏ việc lưu trữ
  • afterDelete(Model $Model): dùng để thực hiện cleanup sau khi xóa thành công.

Tóm lại: nội dung của bài là từ việc trích xuất dữ liệu ra, rồi validate dữ  liệu trước khi chúng được lưu vào DB và cuối cùng là khái niệm cũng như cách sử dụng của Behavior.

Các link tham khảo:

  1. Behaviors
  2. Data-validation

Kết luận

  1. Nếu có thắc mắc gì các bạn để lại comment bên dưới mình sẽ trả lời sớm nhất có thể.
  2. Cảm ơn các bạn đã đọc.

Nongdanit.info

 

[Cakephp] Bài 17 – Validation và Behavior