Đối với một ứng dụng web bình thường thì chúng ta dùng query trực tiếp để thao tác với cơ sở dữ liệu, còn đối với CakePHP nó đã hỗ trợ sẳn cho chúng ta rất nhiều hàm để thao tác. Chúng thực sự rất đa dạng và rất có ích trong việc phát triển web, chúng giúp ta tiết kiệm thời gian hơn, code dễ đọc hơn và cũng tận dụng được tối đa sức mạnh của CakePHP trong đa số các trường hợp thường gặp.

Trong bài này ta cùng tìm hiểu qua cách lấy(truy xuất), lưu và xóa dữ liệu trong CakePHP:

Lấy(truy xuất) dữ liệu:

Với CakePHP 2.x, ta truy xuất dữ liệu thông qua hàm find() với cú pháp như sau:

   find(string $type = 'first', array $params = array())

Trong đó:

$type: có các giá trị all, first, count, list, neighbors, threaded và mặc định sẽ là first. Các giá trị này có phân biệt hoa thường viết sai sẽ báo lỗi.

  • all : lấy tất cả các dữ liệu, sẽ trả về dạng mảng.
  • first : lấy dữ liệu đầu tiên.
  • count : trả về kết quả sẽ là tổng số dữ liệu mà hàm find() đếm được.
  • list : sẽ trả về một mảng danh sách dữ liệu được index.
  • neighbors : tương tự như ‘first’ nhưng kết quả sẽ trả về dữ liệu trước và sau.
  • threaded : kết quả sẽ trả về là một mảng lồng nhau, và thường được dùng để dựng một kết quả lồng nhau với parent_id.

Biến $type này có thể tạo ra theo ý của mình. Đầu tiên là phải khai báo type cho biến Model::$findMethods

class Article extends AppModel {
  public $findMethods = array('available' =>true); 
  protected function _findAvailable($state, $query, $results = array()) {
    if ($state === 'before') {
     $query['conditions']['Article.published'] = true;
     return $query;
    }
    return $results;
  }
}

$type = ‘avaiable’, fucntion có tên findAvaiable sẽ là mục đích của mình để find(), như vậy là hoàn thành trong Model. Như vậy khi sử dụng find() trong Controller ta sẽ viết:

class ArticlesController extends AppController {
   //Will find all published articles and order them by the created column
   public function index() {
    $articles = $this->Article->find('available', array(
       'order' => array('created' => 'desc')
    ));
   }
}

$params: có thể có hoặc không, nó là một mảng:

array(
  'conditions' => array('Model.field' => $thisValue), //mảng các điều kiện
  'recursive' => 1, //kiểu int
  'fields' => array('Model.field1', 'DISTINCT Model.field2'),//mảng tên các trường được lấy
  'order' => array('Model.created', 'Model.field3 DESC'),//chuỗi hoặc mảng định nghĩa thứ tự order
  'group' => array('Model.field'), //mảng các trường sẽ GROUP BY
  'limit' => n, //kiểu int
  'page' => n, //kiểu int
  'offset' => n, //kiểu int
  'callbacks' => true //có thể là các giá trị khác như: false, 'before', 'after'
)
  • conditions: sẽ chứa một mảng các điều kiện, mặc định là null
  • recursive: một kiểu số, mặc định là 1(chi tiết sẽ có một bài riêng).
  • fields: mảng các trường được trả về mặc định là null.
  • order: nó sẽ sắp xếp dữ liệu tăng dần hoặc giảm dần như query thường, nhận giá trị sẽ là chuỗi hoặc mảng, mặc định null.
  • group: mảng các trường được group by, mặc định null.
  • limit: giới hạn dữ liệu trả về, mặc định null.
  • page: số page được dùng với những dữ liệu phân trang, mặc định null
  • offset: giống như query thông thường, mặc định null.
  • callbacks: có thể nhận các giá trị true, false, ‘before’ và ‘after’. Mặc định là true, tức là callback method sẽ được gọi khi dùng find(). Nếu set thành false sẽ hủy việc gọi này. Trường hợp dùng ‘before’ sẽ gọi before callback, ngược lại sẽ gọi after callback khi dùng ‘after’.

Sau khi sử dụng find() dữ liệu sẽ trả về có dạng mảng bao gồm cả dữ liệu của model chính và model liên kết nếu sử dụng hơp lý recursive. Ví dụ một mảng trả về như sau:

 Array(
  [0] => Array(
    [ModelName] => Array(
      [id] => 83
      [field1] => value1
      [field2] => value2
      [field3] => value3
    )
    [AssociatedModelName] => Array(
      [id] => 1
      [field1] => value1
      [field2] => value2
      [field3] => value3
    )
  )
)

findAllBy_(): Hàm này sẽ trả về kết quả giống như find(), nhưng nó sẽ find theo các trường được chỉ định, cú pháp:

   findAllBy<fieldName>(string $value, array $fields, array $order, int $limit, int $page, int $recursive)

fieldName: là tên trường trong database.

Ví dụ:

findAllBy<x> Example Corresponding SQL Fragment
$this->Product->findAllByOrderStatus('3'); Product.order_status = 3
$this->Recipe->findAllByType('Cookie'); Recipe.type = 'Cookie'
$this->User->findAllByLastName('Anderson'); User.last_name = 'Anderson'
$this->Cake->findAllById(7); Cake.id = 7
$this->User->findAllByEmailOrUsername('jhon', 'jhon'); User.email = 'jhon' ORUser.username = 'jhon';
$this->User->findAllByUsernameAndPassword('jhon','123'); User.username = 'jhon' ANDUser.password = '123';
$this->User->findAllByLastName('psychic', array(),array('User.user_name => 'asc')); User.last_name = 'psychic' ORDER BYUser.user_name ASC

 

findBy_(): Hàm này trả về duy nhất một kết quả dữ liệu giống find(‘first’) nhưng nó cũng chỉ định find theo tên một trường nào đó, cú pháp:

   findBy<fieldName>(string $value[, mixed $fields[, mixed $order]]);

Ví dụ:

findBy<x> Example Corresponding SQL Fragment
$this->Product->findByOrderStatus('3'); Product.order_status = 3
$this->Recipe->findByType('Cookie'); Recipe.type = 'Cookie'
$this->User->findByLastName('Anderson'); User.last_name = 'Anderson';
$this->User->findByEmailOrUsername('jhon','jhon'); User.email = 'jhon' OR User.username ='jhon';
$this->User->findByUsernameAndPassword('jhon','123'); User.username = 'jhon' AND User.password ='123';
$this->Cake->findById(7); Cake.id = 7

query(): truy xuất dữ liệu theo kiểu truyền thống  chỉ cần viết câu SQL bình thường và gọi hàm, cú pháp:

   query(string $query);

Ví dụ:

   $this->Picture->query("SELECT * FROM pictures LIMIT 2;");

Lưu, Cập nhật dữ liệu:

CakePHP cung cấp hàm save() để chúng ta lưu dữ liệu vào database, dữ liệu được đưa vào sẽ có định dạng:

  Array (
   [ModelName] =>Array (
      [fieldname1] => 'value'
      [fieldname2] => 'value'
   )
 )

Chỉ cần bạn có 1 mảng có format như trên là có thể lưu vào database một cách dễ dàng, càng dễ dàng hơn nếu chúng ta sử dụng FormHelper của CakePHP để tạo view, khi đó dữ liệu sẽ được gán vào $this->request->data, và chỉ cần dòng lệnh sau là dữ liệu sẽ được lưu:

   $this->User->save($this->request->data) ;

Khi hàm save() được gọi thì dữ liệu sẽ được kiểm tra (validate), nếu validate có lỗi có thể dùng biến Model::$validationError để xem lỗi với :

if ($this->Recipe->save($this->request->data)) {
//validate không có lỗi
}
debug($this->Recipe->validationErrors);

Một số hàm hỗ trợ cho lưu dữ liệu

a) Hàm set($one, $two = null)

Hàm này dùng để set một hay nhiều trường dữ liệu vào mảng dữ liệu bên trong model. Cũng có thể dùng nó để gán những giá trị mới tới nhiều trường. Ví dụ:

  // set các dữ liệu mới
  $this->Post->set(array(
    'title' => 'New title',
    'published' => false
   ));
   $this->Post->save(); //Lưu vào DB

b) Hàm clear(): nó sẽ xóa tất cả những dữ liệu chưa được save hay các lỗi khi validate.

Mới trong phiên bản 2.4

c) Hàm save(array $data = null, boolean $validate = true, array $fieldList = array())

Hàm này sẽ lưu trữ dữ liệu được format theo dạng mảng. Nếu không muốn validate dữ liệu thì có thể set $validate = false, và $fieldList là để hạn chế các trường được lưu dạng mảng.

Hàm này còn có thể sử dụng theo cú pháp save(array$data = null, array $params = array()), trong đó biến $params là :

  • validate : true để validate dữ liệu và false ngược lại.
  • fieldList : mảng các trường sẽ được lưu vào DB.
  • callback : nếu set false sẽ bỏ callback, còn dùng before hay after sẽ gọi các hàm callbacks trước hoặc sau.
  • counterCache : là giá trị boolean điều khiển việc update bộ đếm cache.

Khi dữ liệu mới thêm thành công thì ID cho bản ghi được lưu vào DB sẽ tự động lưu giữ trong thuộc tính $id, ví dụ : $this->Post->id . Do vậy mà việc tạo mới hay cập nhật sẽ phụ thuộc vào $id có được set hay không? Nếu nó được set thì là cập nhật dữ liệu đã có, còn nếu không sẽ tạ ra một bản ghi mới trong DB.

  // Create: id không được set hoặc null => Thêm dữ liệu
  $this->Recipe->create();
  $this->Recipe->save($this->request->data);

  // Update: id là một giá trị => Cập nhật dữ liệu
  $this->Recipe->id = 2;
  $this->Recipe->save($this->request->data);

  $data = array('id' => 10, 'title' => 'My new title');
  // Sau đây sẽ update title của id=10
  $this->Recipe->save($data);

d) Hàm create(array $data = array())

Hàm này gần giống như clear(), nó sẽ reset trạng thái của model để lưu mới dữ liệu. Nghĩa là sẽ clear trạng thái của model và set $data để lưu chúng vào DB.

Nếu bạn muốn chèn dữ liệu mới thay vì cập nhật một dữ liệu có sẳn thì nên gọi create() đầu tiên. Điều này có thể tránh gây xung đột khi gọi save() trongcallbacks và những nơi khác.

e) Hàm saveField(string $fieldName, string $fieldValue, $validate = false)

Khi hàm này được gọi nó sẽ lưu một trường($fieldName) được chỉ định, chúng ta chỉ cần cho biết ID là được $this->ModelName->id = $id;

Hàm này còn có cách viết khác là : saveField(string $fieldName, string $fieldValue, array $params = array()) trong đó $params là mảng với các key sau:

  • validate : true là có validate và false không có validate.
  • callback : nếu set false sẽ bỏ callback, còn dùng ‘before’ hay ‘after’ sẽ gọi các hàm callbacks trước hoặc sau.
  • counterCache(phiên bản 2.4 trở lên) : là giá trị boolean điều khiển việc update bộ đếm cache

f) Hàm updateAll(array $fields, mixed $conditions): Cập nhật tất cả các trường có trong mảng $fields theo điều kiện trong mảng $conditions. Số record được cập nhật có thể là một hoặc nhiều tùy thuộc vào $conditions, nếu $conditions không được đưa vào hoặc set là true thì tất cả bản ghi sẽ được update. Ví dụ:

  $this->Ticket->updateAll(
    array('Ticket.status' => "'closed'"),
    array('Ticket.customer_id' => 453)
  );

Khi câu lệnh trên được thực thi thì trạng thái Ticket của khách hàng có id là 453 sẽ được cập nhật thành closed.

g) Hàm saveMany(array $data = null, array $options = array()): lưu nhiều dòng dữ liệu của cùng model một lúc, các options :

  • validate : true là có validate và false không có validate, còn set là first thì validate tất cả dữ liệu trước khi lưu và đây là giá trị mặc định.
  • atomic : mặc định là true, việc lưu sẽ được thực hiên trên 1 transaction. Nếu DB hay bảng không hỗ trợ transaction thì sẽ set false.
  • fieldList : mảng các trường sẽ được lưu vào DB.
  • deep(phiên bản 2.1 trở lên) : nếu set là true thì sẽ lưu cả các model liên kết
  • callbacks : nếu set false sẽ bỏ callback, còn dùng before hay after sẽ gọi các hàm callbacks trước hoặc sau.
  • counterCache(phiên bản 2.4 trở lên) : là giá trị boolean điều khiển việc update bộ đếm cache.
   $data = array(
     array('title' => 'title 1', 'Assoc' => array('field' => 'value')),
     array('title' => 'title 2'),
   );
   $data = array(
     array(
       'Article' => array('title' => 'title 1'),
       'Assoc' => array('field' => 'value')
     ),
     array('Article' => array('title' => 'title 2')),
   );
   $Model->saveMany($data, array('deep' => true));

h) Hàm saveAssociated(array $data = null, array $options = array()): hàm này được sử dụng để save dữ liệu có nhiều model liên kết với nhau, các option là:

  • validate : true là có validate và false không có validate, còn set là first thì validate tất cả dữ liệu trước khi lưu và đây là giá trị mặc định.
  • atomic : mặc định là true, việc lưu sẽ được thực hiên trên 1 transaction. Nếu DB hay bảng không hỗ trợ transaction thì sẽ set false.
  • fieldList : mảng các trường sẽ được lưu vào DB.
  • deep(phiên bản 2.1 trở lên) : nếu set là true thì sẽ lưu cả các model liên kết, mặc định là false.
  • counterCache(phiên bản 2.4 trở lên) : là giá trị boolean điều khiển việc update bộ đếm cache.
  $data = array(
    'Article' => array('title' => 'My first article'),
    'Comment' => array(
       array('body' => 'Comment 1', 'user_id' => 1),
       array(
            'body' => 'Save a new user as well',
            'User' => array('first' => 'mad', 'last' => 'coder')
       ),
     ),
   );
   $Article->saveAssociated($data, array('deep' => true));

Hãy cẩn thận khi sử dụng saveAssociated() với option atomic set là false. Nó sẽ trả về một mảng thay vì kiểu boolean.

Ngoài những hàm trên thì CakePHP còn một số hàm liên quan đến việc lưu dữ liệu khi chúng có các quan hệ như_ hasOne, hasMany, belongsTo(Xem thêm). Vần đề này sẽ được đề cập đến ở một bài khác.

Xóa dữ liệu: đã thêm, sửa rồi thì đương nhiên còn một vấn đề nữa là xóa dữ liệu. Trong CakePHP có hỗ trợ chúng ta 2 hàm: delete() và deleteAll()

delete(integer $id = null, boolean $cascade = true): Hàm này sẽ xóa dữ liệu dựa theo ID được đưa vào, và mặc định nó sẽ xóa cả dữ liêu có quan hệ với model chỉ định. Ví dụ khi ta xóa một Post thì những Comment của post đó cũng sẽ bị xóa theo.

deleteAll(mixed $conditions, $cascade = true, $callbacks = false). nó cũng giống hàm delete() nhưng điểm khác là nó sẽ xóa tất cả bản ghi theo điều kiện, nó sẽ trả về true ngay cả khi không có dữ liệu được xóa.

  • conditions : điều kiện
  • cascade : nếu true thì sẽ xóa cả những dữ liệu có quan hệ với model bị xóa.
  • callbacks : true sẽ gọi callback, còn false sẽ vô hiệu hóa callbacks.
   $this->Comment->deleteAll(array('Comment.spam' => true), false);

Bài hướng dẫn này xin được kết thúc tại đây.

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 16 – Truy xuất, lưu và xóa dữ liệu