07/09/2018, 16:09

Tìm hiểu về model và các mối quan hệ giữa các model trong Cakephp

Một trong những tính năng mạnh mẽ nhất của Cakephp là khả năng tạo liên kết quan hệ giữa các bảng cơ sở dữ liệu. Để cho ứng dụng của bạn hoạt động một cách hoàn hảo, bạn phải xác định cách các mối quan hệ làm việc cho phép bạn truy cập dữ liệu của bạn một cách trực quan và mạnh mẽ. Nắm vững các ...

Một trong những tính năng mạnh mẽ nhất của Cakephp là khả năng tạo liên kết quan hệ giữa các bảng cơ sở dữ liệu. Để cho ứng dụng của bạn hoạt động một cách hoàn hảo, bạn phải xác định cách các mối quan hệ làm việc cho phép bạn truy cập dữ liệu của bạn một cách trực quan và mạnh mẽ.

Nắm vững các mối quan hệ giữa các model sẽ giúp bạn giải quyết được vấn đề trên.

I. Các loại quan hệ

Có bốn loại quan hệ chính trong cakephp: hasOne, hasMany, belongsTo, và hasAndBelongsToMany (HABTM).

  1. Quan hệ một-một (hasOne): 1-1 một user có một profile
  2. Quan hệ một-nhiều (hasMany): 1-n một user có nhiều posts
  3. Quan hệ nhiều-một (belongsTo): n-1 nhiều posts thuộc về một user
  4. Quan hệ nhiều-nhiều (hasAndBelongsToMany): n-n một Group có nhiều users, một user có thể thuộc nhiều Group khác nhau
    Trong một project Cakephp quan hệ thường gặp nhất là hasMany(1-n) hay belongsTo(n-1), sau đó mới đến quan hệ hasAndBelongsToMany(n-n), quan hệ hasOne thường ít được sử dụng hơn.

Quan hệ được xác định bằng cách tạo ra một biến trong model được đặt tên theo quan hệ bạn đang xác định. Các biến quan hệ đôi khi có thể đơn giản như là một chuỗi, nhưng có thể phức tạp như một mảng đa chiều được sử dụng để xác định các chi tiết cụ thể liên quan như className, conditions,..

class User extends AppModel {
    public $hasOne = 'Profile';
    public $hasMany = array(
        'Recipe' => array(
            'className' => 'Recipe',
            'conditions' => array('Recipe.approved' => '1'),
            'order' => 'Recipe.created DESC'
        )
    );
}

Trong ví dụ trên 'Profile' và 'Recipe' dùng để phân biệt các quan hệ, thông thường nó là tên của class model mà bạn muốn tạo quan hệ. Nhưng nếu muốn bạn cũng có thể thay đổi nó theo ý thích của bạn với điều kiện nó phải là duy nhất:

class User extends AppModel {
    public $hasMany = array(
        'MyRecipe' => array(
            'className' => 'Recipe',
        )
    );
    public $hasAndBelongsToMany = array(
        'MemberOf' => array(
            'className' => 'Group',
        )
    );
}

class Group extends AppModel {
    public $hasMany = array(
        'MyRecipe' => array(
            'className' => 'Recipe',
        )
    );
    public $hasAndBelongsToMany = array(
        'Member' => array(
            'className' => 'User',
        )
    );
}

Nhưng đoạn code dưới đây sẽ không hoạt động tốt trong mọi tình huống:

class User extends AppModel {
    public $hasMany = array(
        'MyRecipe' => array(
            'className' => 'Recipe',
        )
    );
    public $hasAndBelongsToMany = array(
        'Member' => array(
            'className' => 'Group',
        )
    );
}

class Group extends AppModel {
    public $hasMany = array(
        'MyRecipe' => array(
            'className' => 'Recipe',
        )
    );
    public $hasAndBelongsToMany = array(
        'Member' => array(
            'className' => 'User',
        )
    );
}

Bởi vì quan hệ 'Menber' đại diện cho cả model User và model Group trong quan hệ (n-n). Tên quan hệ không được đặt duy nhất sẽ dẫn đến phát sinh lỗi trong khi truy xuất cơ sở dữ liệu.

CakePHP sẽ tự động tạo liên kết giữa các model objects. Vì vậy, ví dụ như trong model User của bạn, bạn có thể truy cập các model Recipe như sau:

$this->Recipe->someFunction();

Tương tự trong controller bạn cũng có thể truy cập model một cách dễ dàng thông qua các quan hệ:

$this->User->Recipe->someFunction();

Lưu ý: các quan hệ được tạo ra theo cách "một chiều", Nếu bạn định nghĩa User hasMany Recipe mà muốn truy cập model User từ model Recipe thì bạn cần phải bổ xung định nghĩa Recipe belongsTo User.

1. hasOne

Trong CakePHP mối quan hệ đó được thể hiện bằng biến $hasOne. Giả sử, tại một thời điểm, một user chỉ có thể có một Profile, như vậy mối quan hệ giữa User và Profile là quan hệ một-một ngay tại thời điểm đó.

class User extends AppModel {
    var $name = 'User';
    var $hasOne = array(
        'Profile' => array(
            'className' => 'Profile',
            'conditions' => array('Profile.published' => '1'),
            'dependent' => true
    ));
}

className: tên lớp của model có quan hệ với model hiện tại.

foreignKey: tên của khóa ngoại được tìm thấy ở model có quan hệ với model hiện tại.

conditions: phần bổ sung để làm rõ hơn quan hệ bằng cách đặt tên Model phía trước tên trường. Vi dụ: ghi là “Profile.approved = 1” thì tốt hơn chỉ ghi “approved = 1.”

fields: Danh sách các trường được trả về khi lấy dữ liệu từ quan hệ được thiết lập, mặc định sẽ trả về tất cả các trường.

order: thứ tự sắp xếp các dòng được trả về.

dependent: xác định xem khi xóa dữ liệu từ model hiện tại thì model có quan hệ với model hiện tại có bị xóa hay không.

2. hasMany

Đây là mối quan hệ một nhiều, thường gặp nhất trong các mối quan hệ giữa các model với nhau. Ví dụ như một user có thể post nhiều bài posts chẳng hạn. Trong CakePHP, mối quan hệ này được định nghĩa bằng biến $hasMany.

class User extends AppModel {
    var $name = 'User';
    var $hasMany = array(
        'Post' => array(
            'className' => 'Post',
            'foreignKey' => 'user_id',
            'conditions' => array('Post.published => '1'),
            'order' => 'Post.created DESC',
            'limit' => '5',
            'dependent'=> true
    ));
}

Ngoài các giá trị array() có thể chứa trong phần 1. hasOne thì nó có thể chứa thêm 'limit' là giới hạn số bản ghi lớn nhất trả về.

3. belongsTo

Đây cũng là mối quan hệ một-nhiều như hasMany, nhưng là theo chiều ngược lại. Như ví dụ ban nãy, một User có thể post nhiều bài posts, thì bây giờ mối belongsTo có nghĩa là một bài post chỉ thuộc về một user mà thôi. CakePHP định nghĩa quan hệ này bằng biến $belongsTo:

class Profile extends AppModel {
    var $name = 'Profile';
    var $belongsTo = array(
        'User' => array(
            'className' => 'User',
            'foreignKey' => 'user_id'
    ));
}

4. hasAndBelongsToMany

Mối quan hệ n-n là mối quan hệ phức tạp trong CakePHP. Nó khác với mối quan hệ 1-n ở chỗ nếu như quan hệ 1-n thì các model chỉ có quan hệ theo một hướng thì ở quan hệ n-n sẽ đi theo 2 hướng. Ví dụ: một post thì có nhiều tags, và ngược lại, một tag cũng sẽ có nhiều posts. Mối quan hệ n-n nói nôm na là sự kết hợp 2 chiều của mối quan hệ một-nhiều. Trong mối quan hệ nhiều-nhiều, sẽ có một table trung gian, được gọi là join table, chỉ chứa khóa chính của 2 bảng chính mà thôi. Ví dụ posts có quan hệ nhiều nhiều với tags thì join table ở đây sẽ là posts_tags, table này chỉ chứa 2 id của 2 table posts và tags làm khóa chính và đồng thời là khóa ngoại của join table. CakePHP biểu diễn mối quan hệ nhiều nhiều bằng biến $hasAndBelongsToMany như sau:

class Post extends AppModel {
    var $name = 'Post';
    var $hasAndBelongsToMany = array(
        'Tag' =>array(
            'className' => 'Tag',
            'joinTable' => 'posts_tags',
            'foreignKey' => 'post_id',
            'associationForeignKey' => 'tag_id',
            'unique' => true,
            'conditions' => ',
            'fields' => ',
            'order' => ',
            'limit' => ',
            'offset' => ',
    ));
}

II. Tổng kết và tài liệu tham khảo

Cackephp với cách thiết lập các mối quan hệ đơn giản sẽ giúp bạn dễ dàng quản lý các bảng trong cơ sở dữ liệu và các quan hệ giữa chúng, qua đó chúng ta cũng sẽ biết cách để lấy dữ liệu như thế nào cho phù hợp với yêu cầu đặt ra.

0