11/08/2018, 20:56

Sử dụng CodeIgniter 3.0 để start project?! Tại sao không!

Giới thiệu Tản mạn chút : Chắc hẳn sẽ có nhiều bạn cảm thấy kì cục như kiểu mình ở nông thôn mới ra thành thị khi dùng một framework gần 10 năm tuổi và ít được cải tiến, ít tính năng hiện đại như CodeIgniter(CI). Kiểu như suy nghĩ này: ku này nhà quê vc, giờ ai còn dùng cái fw cùi bắp đó, ...

Giới thiệu

Tản mạn chút:
Chắc hẳn sẽ có nhiều bạn cảm thấy kì cục như kiểu mình ở nông thôn mới ra thành thị khi dùng một framework gần 10 năm tuổi và ít được cải tiến, ít tính năng hiện đại như CodeIgniter(CI).
Kiểu như suy nghĩ này: ku này nhà quê vc, giờ ai còn dùng cái fw cùi bắp đó, giờ phải tiếp cận mấy cái hiện đại như Laravel, Phalcon, Yii2 hay Symfony2 chứ

Ờ thì cũng có phần đúng, nếu để tiếp cận những cái hay cái đẹp cái mới của PHP thì chả ai lại dùng những framework vừa cũ vừa thiếu tính năng như CI cho mất thời gian code thêm :smile:.
Bài viết này không nhằm mục đích phân tích xem nên dùng Fw nào. Vì theo quan điểm cá nhân, mỗi fw lại có một cái hay riêng, một lượng fan riêng. Và dân lập trình chúng ta thường theo đạo (đạo ở đây không phải đạo Kito hay đạo Hồi đâu nha :smile:). PHP là một loại tôn giáo, và CodeIginter hẳn là một vị giám mục đáng kính nào đó có rất đông các tín đồ đi theo. Chả bởi thế mà có cái hình này
alt text

và đây nữa
alt text

Mình xin phép không đi sâu vào giới thiệu hay phân tích gì nữa mà để vào phần kết của bài hoặc ở comment nơi chúng ta chia sẽ quan điểm của mình (các bác đi qua ném cho em ít gạch, em đang cần gạch xây nhà @@).

Ah một lời nữa để mở đầu đoạn sau ( thằng cha viết bài này dài dòng văn tự vđ :D). Lý do khi mình start project bằng CI đơn giản là bởi ông khách hàng ổng yêu cầu thế :v, (có lẽ lão đó ngày xưa học PHP dùng CI nên giờ muốn làm = CI để tiện theo dõi bảo trì bảo dưỡng này kia :haha:)

Đó là lý do mà mình hì hụi quay lại cái fw cổ này, cái fw cách đây mấy năm đã đưa mình đến với khái niệm về framework và kiến trúc mvc :D.

Đi vào phần chính,

Các hạn chế của CI

Một trong những lý do mà các chế có suy nghĩ "thằng ku viết bài này dùng CI đúng là nông dân vc" đó là bởi vì CI tồn tại khá nhiều hạn chế khi mà thiếu các tính năng start 1 hệ thống mới cũng như support các tính năng hiện đại có sẵn, có thể kể đến như thiếu một template engine hoàn chỉnh, thiếu các build-in tool để quản lý các migration + seeder cho database. Các database model thì không có sẵn, các helper function còn thiếu và yếu (ví dụ như các helper về translate đa ngôn ngữ). Các mô hình về design pattern chưa cụ thể rõ ràng, các service build-in đương nhiên rất ít. Đến ngay cả cách cài đặt project ban đầu cũng không phải bắt đầu từ composer mà bắt đầu bằng cách download file zip về và giải nén :trollface: (mình lấy hướng dẫn của bản 3.0 trên trang chủ CI nha)

Nên có thể bạn nào đang đi từ 1 fw với đầy đủ tính năng sẽ bị hẫng, cảm thấy thất vọng, khi buộc phải sử dụng CI vì một lý do nào đó. Và mình cũng thế, và cách xử lý của mình đó là tìm cách đưa các khái niệm, các tooling của các framework khác sang CI, một phần phục vụ cho dự án hiện tại, một phần để tạo ra 1 bộ khung dành cho các dự án sau này nếu như có trường hợp nào đó lại yêu cầu dùng CI để triển khai dự án.

Xin một chút dài dòng nữa thôi, phần quote này là cho các bạn mới bắt đầu tìm hiểu PHP hoặc bắt đầu làm quen với PHP framework.
Theo mình thì nếu bạn chuyển từ code PHP thuần hoặc 1 bộ khung PHP do bạn tự build sang sử dụng một PHP framework để start dự án thì CI là một hướng đi khá dễ chịu và hợp lý khi code của nó dễ dàng tiếp cận, các khái niệm cơ bản đều có sẵn và quen thuộc, đồng thời các khái niệm sơ khai về mô hình kiến trúc framework được gợi mở tốt. Nếu tìm hiểu sâu hơn, thậm chí tự mình cải tiến (điều này khá dễ chịu khi CI dễ code, dễ tiếp cận, dễ chỉnh sửa) bổ sung thêm tính năng cho fw cũng giúp bạn khá nhiều trong việc học - lưu ý ở đây là học nhé :D chứ còn để làm việc thì ưu tiên tốc độ hơn. Và nếu bạn là fan của CI thì cũng đừng có bi quan hay ái ngại vì thua kém chúng bạn khi các bạn của bạn đang sử dụng những framework thời thượng như anh L, chị S, anh Y :D, vì như mình đã nói, mỗi fw có 1 điểm mạnh riêng. Điểm mạnh của CI nằm ở hiệu năng, sự gọn nhẹ, tính tự do trong code, môi trường cài đặt thì siêu đơn giản (mà các cụ vẫn bảo là dễ như p** ấy .:stuck_out_tongue_closed_eyes:)

Vậy bác sĩ cho em hỏi, thuốc CodeIgniter diệt trừ giun như thế nào? àh dùng CodeIgniter để start project như thế nào?
Đầu tiên phải kể đến các package hay library mình lượm từ anh Google. List ra đây 1 chút nào

Cool package and tooling

  • Composer for CodeIgniter : Link https://getcomposer.org/
  • Template: Blade template stand-alone. Link https://github.com/laperla/codeigniter-Blade
  • Cli for codeiginiter, support migrate and seed database. Link https://github.com/kenjis/codeigniter-cli
  • Base model với CRUD, Observer, data-validation, relationship table. Link https://github.com/avenirer/CodeIgniter-MY_Model

Giới thiệu qua các package - tooling này.

Composer

Cái này thì nhiều bạn làm dự án PHP đã quen thuộc lắm rồi. Nhờ có ông này ra đời mà mấy ông framwork mới được mở rộng dễ dàng thế, chỉ cần khai báo trong json rồi update là xong.

Cho bạn nào chưa biết thì ông composer này là một thư viện giúp quản lý các thư viện khác bạn cần nhúng vào project. Ví dụ làm cái project về chia sẻ ảnh chẳng hạn, cần thư viện crop-image. Lên mạng search 1 hồi ra cái link github, đọc readme thấy có dòng composer : { "kiendt" : "crop-image"} thì cứ nhét vào 1 file json rồi gõ composer:update trong terminal và thế là dùng thôi. Thay cho cách truyền thống từ chục năm về trước là download source về folder project rồi nhét vào autoload hoặc require trong file config

Mặc định thì CI không hướng dẫn cài đặt project từ Composer ở trang chủ. Bạn có thể search Google để load CI về từ Composer. Tuy nhiên mình thì vô trang chủ CI, ấn download => giải nén ra folder project, nhét thêm file composer.json vào và done!

Blade template

Mình chọn ông Blade này vì mình thấy cú pháp hỗ trợ cũng khá ổn, nhiều tính năng hay ho như include, extend layout, khai báo section...

alt text

Blade mình nói ở đây là template engine không phải Honda Blade nha :trollface: Tìm hiểu thêm về cú pháp Blade thì ở đây https://laravel.com/docs/5.1/blade. Còn về Honda Blade thì ở đây :D
Thư viện Blade trên cài đặt đơn giản, chỉ cần download về cho vào thư mục libraries của CI, lúc nào dùng thì load ra. Ah nếu bạn đọc document của Laravel về Blade thì có thể thấy hàm extends của Blade sẽ không hoạt động trong thư viện này, Mình có sửa lại 1 chút code trong file Blade này để có thể dùng được như trong document của Laravel. Bạn có thể tự trải nghiệm rồi sửa lỗi như mình, hoặc nếu lười thì có thể down về tại đây bản mình đã sửa.

Commandline Interface for CodeIgniter

Nếu bạn dùng Symfony, Yii hay Laravel thì sẽ thấy hỗ trợ command-line tool được build-in trong framework. CI thì không có cái đó, vì thế nên theo tài liệu trên trang chủ của CI thì muốn tạo 1 migration cho database thì phải chuột phải => new file => viết code => save file đặt tên theo chuẩn.

Clgt, thế quái nào mà tù vãi linh hồn vậy

Thế nên mình quyết định tìm một thư viện cli hỗ trợ CodeIgniter. Tool cli của anh kenjis này hỗ trợ các dòng lệnh để tạo và quản lý migration, seeder, controller... và cũng cho phép chúng ta tự build lấy command-line theo ý thích, tức là khả năng scale khá thoải mái.

Sau khi tìm được tool này thì mình khá phấn khích và bắt đầu cảm thấy dùng CI cool hơn nhiều so với lúc đầu :stuck_out_tongue: Nhưng còn dài, còn nhiều thứ phải bổ sung lắm.

Base CRUD model

Tiếp đến là giới thiệu model MY_Model khá hay từ anh avenirer.
Nếu đi vào tìm hiểu CI thì bạn sẽ thấy CI không hỗ trợ sẵn một model chuẩn nào cả, cách viết và thực hiện query rất tự do, cởi mở. So sánh với các fw khác thì chắc bạn sẽ thấy bùi ngùi ghen tỵ lắm vì chúng bạn đều có 1 ORM ngon lành cành đào để dùng.
Nhưng cũng có nhiều anh nhiệt tâm cao, viết cho CI thư viện ORM này. Bạn chỉ cần down về, cho vào thư mục models, lúc tạo model nhớ extends base model này là được. Hỗ trợ các method CRUD tương đối ổn, cách sử dụng cũng linh hoạt. Vì document đã có sẵn, bạn có thể vọc ngay bây giờ trên github.

Tinh chỉnh cá nhân trong CI

Giờ là một chút tinh chỉnh của bản thân với CI sau khi sử dụng các package này.

Multi-language
Sau khi mình dùng Blade template của Laravel thì thấy khá cool, chuyển sang CI thì gặp vấn đề thiếu 1 số hàm helper để phục vụ ngoài template ví dụ như vấn đề về multi-language này. Ở Laravel thì dùng hàm trans để sử dụng language-text được khai báo trong language-file, ở CI cũng có hàm lang tuy nhiên cùi hơn vì file language của CI là một cấp. Để hiểu rõ hơn bạn có thể nhìn example này và so sánh.

CodeIginter

//khai báo đoạn này trong /applications/language/english/filename_lang.php
$lang['error_email_missing'] = 'You must submit an email address';
$lang['error_url_missing'] = 'You must submit a URL';
$lang['error_username_missing'] = 'You must submit a username';

và lúc sử dụng ngoài view:

echo lang('error_email_missing');
// Outputs: You must submit an email address

Cách translate của Laravel tiện hơn nhiều khi $lang được khai báo dạng mảng nhiều chiều

Laravel
Trong file language

$lang = [
    'homepage' => [
        'featured_series' => [
            'welcome_text' => 'The most concise screencasts for the working developer, updated daily.',
            'title' => 'Featured Series'
        ]
    ]
 ]; 

Ngoài view

echo trans('homepage.featured_series.title');
//Output Featured Series

Còn nhiều option nữa trong hàm translate của Laravel mà mình không liệt kê ở đây được, tuy nhiên mới chỉ dùng đến cách tổ chức translate-text theo dạng array đa chiều nên mình bổ sung thêm hàm trans vào helper của CI để dùng cho tiện. Và đây là code của mình, cho hàm này vào 1 file helper tên là translate_helper.php rồi load vào MY_Controller.php thôi.

if ( ! function_exists('trans'))
{
    /**
     * @author kiendt@hblab.vn
     * @param $id : to get index of array language data
     * @param array $parameters_array :
     * @param null $language
     * @return string
     * @TODO write trans function with accept parameters array
     */
    function trans ($id, $parameters_array = array(), $language = null) {
        $array_index = explode('.',$id);
        $lang_filename = $array_index[0];
        $line = $array_index[1];
        $result_text = ';
        $CI = get_instance();
        $CI->lang->load($lang_filename, $language);
        $array_text = $CI->lang->line($line);
        if(!is_array($array_text)) {
            return $array_text;
        }
        array_splice($array_index,0,2);

        foreach ( $array_index as $index) {
            $result_text = isset($array_text[$index]) ? $array_text[$index] : $result_text;
            //gán lại array text để lọc tiếp cho vòng lặp tiếp theo
            $array_text = $result_text;
        }
        return $result_text ? $result_text : $id;
    }
}

Ah cái đoạn TODO cũng như biến parameters_array mình để đấy để nhắc làm sau, đến tận giờ đã làm đâu, để lòe thiên hạ chơi :stuck_out_tongue:

Hàm asset
Tiếp đến 1 thứ nữa khi mình dùng trong Laravel là hàm asset. Hàm này để trả về đường dẫn tới thư mục public/assets chứa css, images, js.... Hàm này thì đơn giản rồi :), 1 dòng code là trả về được rồi

if ( ! function_exists('asset'))
{
    function asset($asset_path) {
        return PUBLICPATH . 'assets/' . $asset_path;
    }
}

Hook
Controller trong CI không có sẵn các before_action hay before như của Yii, Symfony, Fuel hay Middleware như của Laravel. Nhưng cũng có cơ chế hỗ trợ bạn nếu bạn muốn filter data, hay thực hiện 1 lời gọi đơn giản nào đó đến database trước khi 1 controller bất kỳ được gọi. Và đó là hook. Phần này thì document sẵn rồi, mình chỉ bổ sung chút là trong project mình làm thì mình có thêm 1 service để thực hiện 1 vài query cho toàn page, và mình không muốn viết query này trong các controller hay trong base controller, đơn giản vì mình muốn nó giống 1 service hơn, có thể gọi ở đâu cũng được. :) và thế nên mình cho vào hook. Mình vào file hook.php trong folder config và thêm đoạn sau

$hook['post_controller_constructor'] = [
    [
        'class'=>'CommonService',
        'function'=>'get_instance',
        'filename'=>'CommonService.php',
        'filepath'=>'hooks'
    ]
];

Sau đó ở file /hooks/CommonService.php mình định nghĩa nó như 1 singleton pattern để cho... nguy hiểm :trollface:

Các bạn có thể tham khảo

class CommonService
{
    private static $instance;
    private static $service_result_a;
    public static function get_instance()
    {
        if (null === static::$instance) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    public function get_service_a()
    {
        if(null === static::$service_result_a) {
            $ci = &get_instance();
            static::$service_result_a = $ci->db
                        ->query('SELECT anything...')
                        ->get();
        }
        return static::$service_result_a;
    }
}

Và bên ngoài view mình tự tiện sử dụng mà không sợ bị chửi là sao mày lại nhét query vào view

CommonService::get_instance()->get_service_a();

Cấu trúc folder

  • folder public. Mình có thêm folder public để chứa file index.php và thêm thư mục asset chứa các css, image và js của project. Việc này chỉ là tùy chỉnh cá nhân, không đáng quan tâm lắm nhưng mình viết vào đây để các bạn tham khảo. :). Nhớ trỏ lại htacess nhé.
  • folder database Mặc định thì CI không có folder nào để chứa migration và seeder file của database nên mình tạo folder này cho dễ bề quản lý. Các file migration và seeder sẽ được cho vào 2 subfolder tương ứng trong folder này.

Debug tool and profiler
One more thing. Điều cuối trong loạt tips này là 1 tips nhỏ. Mặc định trong config của CI không có chế độ profiler. Nhưng nếu bạn search Google thì có thể thấy CI cũng có profiler để hiển thị benmark chương trình, router, controller và list query thực hiện trong request... nói chung khá đầy đủ những thứ bạn cần để debug. Bạn chỉ cần thêm dòng này vào file config

$config['enable_profiler'] = TRUE;

Và để debug cool hơn thì bạn có thể dùng thêm thư viện dump của bác Kint trên github , cài trong composer như này
"raveren/kint": "^1.0"

Lời kết

Đến đây thì mình tạm thấy phần base project của mình đã tạm ổn, có các tool hỗ trợ tiện lợi, có thể bắt đầu code được rồi :).
Chia sẻ chút về quan điểm cá nhân khi sử dụng CodeIgniter làm việc: mình nghĩ là nếu sau này có cơ hội, hoặc làm tutorial thì có thể mình sẽ lại sử dụng phần base-project này, cũng không tồi. Mình rất thích một câu nói:

Mèo trắng là mèo, mèo đen cũng là mèo, miễn bắt được chuột thì là mèo tốt

Nên mình nghĩ framework nào cũng được, bạn hãy sử dụng thứ bạn thân thuộc nhất, pro nhất để làm cho mình code thoải mái nhất. Tất cả phụ thuộc vào code của bạn chứ không phụ thuộc vào framework. Và ứng dụng của bạn dùng CI cũng được, Laravel cũng được, Yii hay Zend hay Cake cũng chả sao, miễn hiệu năng tốt, UI, UX ngon lành, được trả nhiều tiền hoặc nhiều người dùng thì mình tin răng nền tảng của bạn lựa chọn là tuyệt vời :+1:

Troll tí vui:

Trường giang sóng sau xô sóng trước.
Mấy bố dùng Laravel giờ đang vỗ ngực anh dùng fw ngon nhất, có lượng người dùng nhiều nhất, hiệu năng tốt nhất. Uh chờ đấy, giống mấy anh làm Yii ngày xưa thôi :)). Rồi mấy năm nữa lại có fw ngon hơn mà thôi :trollface:

Cảm ơn các bạn đã theo dõi bài viết dài lê thê này.
Rất hi vọng nó có ích với một số bạn :)

0