Tìm hiểu quy trình load model trong codeigniter

Việc load model rất quen thuộc với những bạn sử dụng framwork codeigniter nhưng đôi lúc ta lại tò mò không biết quá trình nó load như thế nào, bài này tôi và các bạn sẽ tìm hiểu quy trình load model như thế nào nhé.

Function load model codeigniter nằm ở đâu?

Đây là câu hỏi đầu tiên để tìm hiểu một chức năng, đối tượng trong một framwork nào đó, và cách đơn giản nhất các bạn hãy dùng chương trình search project của các editor, ở đây tui dùng netbeans để search và tôi đã tìm ra nó nằm trong file system/core/Loader.php. Các bạn mở file này lên và tìm tới dòng 232 sẽ có một function load model như sau:

public function model($model, $name = '', $db_conn = FALSE)
	{
		if (is_array($model))
		{
			foreach ($model as $babe)
			{
				$this->model($babe);
			}
			return;
		}

		if ($model == '')
		{
			return;
		}

		$path = '';

		// Is the model in a sub-folder? If so, parse out the filename and path.
		if (($last_slash = strrpos($model, '/')) !== FALSE)
		{
			// The path is in front of the last slash
			$path = substr($model, 0, $last_slash + 1);

			// And the model name behind it
			$model = substr($model, $last_slash + 1);
		}

		if ($name == '')
		{
			$name = $model;
		}

		if (in_array($name, $this->_ci_models, TRUE))
		{
			return;
		}

		$CI =& get_instance();
		if (isset($CI->$name))
		{
			show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
		}

		$model = strtolower($model);

		foreach ($this->_ci_model_paths as $mod_path)
		{
			if ( ! file_exists($mod_path.'models/'.$path.$model.'.php'))
			{
				continue;
			}

			if ($db_conn !== FALSE AND ! class_exists('CI_DB'))
			{
				if ($db_conn === TRUE)
				{
					$db_conn = '';
				}

				$CI->load->database($db_conn, FALSE, TRUE);
			}

			if ( ! class_exists('CI_Model'))
			{
				load_class('Model', 'core');
			}

			require_once($mod_path.'models/'.$path.$model.'.php');

			$model = ucfirst($model);

			$CI->$name = new $model();

			$this->_ci_models[] = $name;
			return;
		}

		// couldn't find the model
		show_error('Unable to locate the model you have specified: '.$model);
	}
Nhìn hơi căng nhỉ, bây giờ ta sẽ mổ xẻ nó nhé

Mổ xẻ function load model trong codeigniter

tham số truyền vào

Trong function load model có 3 tham số truyền vào gồm $model, $name, $db_conn, trong đó:

  • $model là tên model cần load, có thể truyền vào một mảng danh sách các model cần load nhưng trường hợp này tham số $name sẽ không có tác dụng.
  • $name là tên alias mà bạn muốn sau khi load model nó sẽ gán vào instance của Codeigniter
  • $db_conn là tên database mà bạn khai báo ở file application/config/database.php, mặc định là defaul

code xử lý bên trong hàm

Ta có quy trình xử lý gọi model trong codeigniter như sau:

Đoạn 1:

// Nếu model truyền vào là một mảng
    // thì duyệt danh sách mảng và gọi đệ quy load từng model
    if (is_array($model)) {
        foreach ($model as $babe) {
            $this->model($babe);
        }
        return;
    }
Qua phần comment giải thích tôi đã nói rõ rồi phải không nào. Riêng phần gọi lại đệ quy hơi khó chút xíu, tức là nếu model truyền vào là một danh sách thì sẽ lặp các mảng và load lại từng model một, các bạn có thể tham khảo bài đệ quy trong php để tìm hiểu thêm nhé.

Đoạn 2:

// Nếu model truyền vào rỗng thì ngưng xử lý
    if ($model == '') {
        return;
    }

    // Định nghĩa một biến $path để lưu đường dẫn đến file model
    $path = '';
Đoạn 3:

// Nếu model truyền vào ở dạng subfolder, ví dụ news/category_model
    // thì xử lý để lấy tên subfolder và tên model 
    if (($last_slash = strrpos($model, '/')) !== FALSE) {
        // Lấy đường dẫn đến model
        $path = substr($model, 0, $last_slash + 1);

        // Lấy tên model
        $model = substr($model, $last_slash + 1);
    }
Trong đoạn code này nó sẽ kiểm tra model truyền vào có phải dạng subfolder hay không, ví dụ news/category_model.php, shop/news/category_model.php.

Biến $last_slash là vị trí xuất hiện dấu / cuối cùng trong chuỗi string model nhập vào, dựa vào vị trí này ta lấy được đường dẫn đến file model $path và tên model $model bằng cách dùng hàm substr($string, $start, $end), nếu bạn chưa biết cách sử dụng hàm substr này thì đọc qua bài này nhé.

Đoạn 4:

// Nếu không sử dụng alias thì lấy tên model làm alias
    if ($name == '') {
        $name = $model;
    }

    // Kiểm tra tên này có trong danh sách model đã load chưa? 
    // Nếu có rồi thì không cần load lại
    if (in_array($name, $this->_ci_models, TRUE)) {
        return;
    }

    // Kiểm tra tên alias tồn tại trong hệ thống CI chưa,
    // nếu tồn tại rồi thì ngưng xử lý
    $CI = & get_instance();
    if (isset($CI->$name)) {
        show_error('The model name you are loading is the name of a resource that is already being used: ' . $name);
    }
Đoạn code 1 kiểm tra xem biến alias $name có truyền vào hay không, nếu không thì lấy tên model làm alias luôn, tức là  $name = $model.

Đoạn code 2 kiểm tra xem model này có nằm trong danh sách model đã load của hệ thông hay không, nếu có tức là load rồi nên không cần load lại làm gì.

Đoạn code 3 kiểm tra tên alias có trong danh sách đối tượng load của CI chưa (gồm library, model), nếu có rồi thì ngưng không xử lý tiếp, điều này có nghĩa giả sử bạn 1 model tên news và một library tên news, nếu bạn load library news trước sau đó load model news thì model này sẽ không được load, bởi vì đối tượng news đã tồn tại trong hệ thống CI.

Đoạn 5:

// Đưa tên model về dạng chữ thường
    $model = strtolower($model);
Đoạn này sẽ đưa tên model về chữ thường, phòng trường hợp bạn truyền tên model vào có chữ hoa.

Đoạn 6:

// Duyệt qua danh sách folder đã khai báo với CI
    // mặc định là folder application/models
    foreach ($this->_ci_model_paths as $mod_path) 
    {
        if (!file_exists($mod_path . 'models/' . $path . $model . '.php')) {
            continue;
        }

        // Nếu có truyền tên database cần load khai báo ở file config/database.php
        // thì thực hiện load kết nối với database
        if ($db_conn !== FALSE AND ! class_exists('CI_DB')) {
            if ($db_conn === TRUE) {
                $db_conn = '';
            }

            $CI->load->database($db_conn, FALSE, TRUE);
        }

        // Load thư viện core Model
        // Kiểm tra core đã load chưa
        // nếu chưa load thì mới load
        if (!class_exists('CI_Model')) {
            load_class('Model', 'core');
        }

        // Require model
        require_once($mod_path . 'models/' . $path . $model . '.php');

        // Chuyển tên model thành chữ hoa đầu tiên
        $model = ucfirst($model);

        // khởi tạo model và gán vào danh sách object của CI
        $CI->$name = new $model();

        // đưa model vào danh sách models đã load
        $this->_ci_models[] = $name;
        return;
    }
Đoạn này hơi căng nên các bạn đọc phần comment nhé. Mình sẽ giải thích một hàm quan trọng đó là hàm load_class('Model', 'core'), hàm này có ý nghĩa load thư viện Model nằm trong folder core của system, như vậy muốn load file nào trong hệ thống nào thì chỉ cần truyền vào tên file và tên hệ thống, ví dụ:

load_class('Loader', 'core') load file Loader.php trong thư mục core của system.

load_class('Router', 'core') load file Router.php nằm trong thư mục core của system

Khai Báo Thêm Một Thư Mục Chứa Model

Phần này rất có ích với những bạn muốn custom bộ core của CI nên nếu có hứng thì  bạn nên xem kỹ nhé.

Trước tiên tôi sẽ giải thích thư mục chứa folder là gì? Như bạn biết mặc định hệ thống có một thư mục chứa danh sách model đó là application/models, và thư mục chứa library là application/libraries, vậy thêm một thư mục chứa model tức là thêm một thư mục nào đó để chứa model, ví dụ thư mục application/my_model_folder.

Như tôi giải thích ở trên hàm load model sẽ duyệt qua hết danh sách các thư mục chứa model nên việc bạn tạo model ở thư mục nào nó đều load được.

Để thêm một thư mục ta dùng hàm sau trong file system/core/Loader.php, tức là cùng file với hàm load model.

        public function add_package_path($path, $view_cascade=TRUE)
	{
		$path = rtrim($path, '/').'/';

		array_unshift($this->_ci_library_paths, $path);
		array_unshift($this->_ci_model_paths, $path);
		array_unshift($this->_ci_helper_paths, $path);

		$this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;

		// Add config file path
		$config =& $this->_ci_get_component('config');
		array_unshift($config->_config_paths, $path);
	}
Hàm này sẽ thêm một thư mục chứa các thư viện model, library, helper. Như vậy ở controller ta sẽ thêm nó bằng cách sau.

Bạn tạo 1 folder tên models trong thư mục third_party.

Sau đó ở controller nào đó bạn thêm dòng này

$this->load->add_package_path('third_party');
Như vậy là folder third_party/models cũng có thể chứa model của bạn.

Nhưng lời khuyên là không nên dùng hàm này ở controller, vì như vậy controller nào ta cũng phải thêm đoạn code add package này. Giải pháp là bạn tạo một file MY_Loader trong application/core, nếu bạn chưa  biết tạo thì tham khảo tại đây, sau đó copy nội dung này vào.

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

class MY_Loader extends CI_Loader 
{
    function __construct() {
        parent::__construct();
        $this->add_package_path(APPATH.'third_party/');
    }
}

?>
Vậy là xong.

Lời kết

Bài viết này dành cho những bạn có kiến thức sử dụng codeigniter thuần thục muốn tìm hiểu nâng cao bộ core của Codeigniter để dễ dàng custom trong quá trình làm việc. Hy vọng qua bài tìm hiểu quy trình load model này sẽ giải đáp được một số thắc mắc của các bạn, xin chào và hẹn gặp lại ở một bài gần nhất.

Hãy để lại link bài viết gốc khi chia sẻ bài viết này, mình sẽ report DMCA với những website lấy nội dung mà không để nguồn hoặc copy bài với số lượng lớn.

Nguồn: freetuts.net

Profile photo of adminTheHalfHeart

TheHalfHeart

Có sở thích viết tuts nên đã từng tham gia viết ở một số diễn đàn, đến năm 2014 mới có điều kiện sáng lập ra freetuts.net. Sinh năm 90 và có 1 vợ 2 con, thích ca hát và lập trình.

ĐĂNG BÌNH LUẬN: Đăng câu hỏi trên Group Facebook để được hỗ trợ nhanh nhất.