พอดีช่วงนี้ผม กำลังหา Solution Framework ที่ทำงานเป็นทีมได้สะดวกๆ แล้วก็ไม่ทำให้โคด “เสียทรง” ในระหว่างที่กำลังพัฒนา รวมไปถึงไม่ต้องเสียเวลา Learning กับ Framework ตัวใหม่ๆ ซึ่ง ก่อนหน้านี้ก็ได้ลองเพิ่ม HMVC ให้กับ CI อันที่จริงตัวนี้ผมลองเล่นมานานแล้ว แต่ว่าเมื่อก่อน มันทำแปลกๆ โคดไม่เข้ากับระบบ โดยรวม ทำให้เวลา CI เปลี่ยน Version ต้องมาแก้ไอ้นี่กันตลอด แต่พอวันนี้ได้ไปดูอีกที เห็นว่า เปลี่ยนมาเขียนในรูปแบบ 3Party ของ CI (จริงๆ มันแค่ยืม Folder มาเก็บ) รวมไปถึงยัง extend controller ออกมาได้เหมือนเดิม ก็เลยลองใช้ดู พบว่าใช้ได้พอสมควร ก็เลยเอามาใส่
แต่เรื่องที่วันนี้จะมาเขียนไม่ได้เกี่ยวกับ HMVC ตัวนี้เลย เพราะว่าอันนี้ ใครเอาไปลองก็ทำได้ง่ายๆ วิธีติดตั้งเค้าก็เขียนมา ไม่มีอะไรซับซ้อน
ส่วนเรื่องที่จะเขียนจะเป็นเรื่องเกี่ยวกับการ รวมกลุ่ม ของ functions ให้ออกมาในรูปแบบของ utilities…..
เกริ่นซะหน่อยเดี๋ยวจะงง
ถ้าเกิดมีใครได้ลอง PHP Framework เดี๋ยวนี้ มักจะพบว่า แต่ละตัวก็จะมี utils ซึ่งบางตัวก็อาจจะใช้ชื่อต่างจากนี้ อันที่จริง มันไม่ใช่อะไร แต่เป็นการเขียน helpers ให้อยู่ในรูปแบบ ของ class ซึ่งจัมีประโยชน์ในด้าน naming ของโคด ทำให้ จัดกลุ่มได้อย่างสวยงาม ยกตัวอย่างเช่น ถ้าผมจะเขียนเกี่ยวกับเรื่อง Path ใน CodeIgniter ผมก็อาจจะไป extend url_helper ออกมา ให้เป็น MY_url_helper แล้วเขียน function เติมลงไป ซึ่งจริงๆ แล้วมันก็ไม่มีอะไรเสียหาย แต่ว่า ถ้าเกิดมีใครไป ตั้งชื่อ “แปลกๆ” อาทิเช่น user_info() ใน ไฟล์นี้ล่ะก็ รับรองได้ ต้องไล่โคดกันยาวววววว
แต่ถ้าผมเปลี่ยนมาเขียนในรูปแบบ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php class CIUrl { public static function getAssetsUrl($uri='') { return site_url('assets/'.$uri); } public static function getThumbnailUrl($uri='') { return "......"; } } |
เวลาเรียกใช้ ก็เรียกเหมือน helper ปกติ แบบนี้
1 2 3 | <?php CIUrl::getAssetsPath() |
ทีนี้พอเราเห็น คำว่า CIUrl ก็จะรู้ได้เลยว่าต้องไปหาที่ /utils/CIUrl.php ซึ่งใช้เวลาสั้นกว่ามาก อันที่จริงแล้วผมจัดกลุ่มด้วยตัวเอง ผมจะแบ่งออกเป็น
helpers = function ดิบๆ เช่นพวกทำงานกับ string, numeric หรือเรื่องพื้นๆ
utils = function ที่ต้องทำงานร่วมกับ model ในบางครั้ง
อันที่จริงแล้วถ้าผมจะเขียนแบบนี้ ผมไปเขียนใน helpers ก็ได้ แล้วก็เรียก load helper ตามปกติ แต่ว่ามันจะไม่ได้ในเรื่องของ naming ชื่อไฟล์ แล้วก็ ดูไม่เป็นสัดส่วน เหมือนกับไปหักดิบ Framework ที่เค้าออกแบบมา แล้ว
ดังนั้น ประเด็นวันนี้ที่เราจะมาทำกันก็คือ
1. เพิ่ม utils ให้กับ CI
2. ทำตัว load เฉพาะ ให้กับ utils
3. ทำส่วน autoload ให้กับ utils
มาๆ เริ่มกันเลย ข้อที่ 1
อันนี้โครตง่าย ไปสร้าง folder utils ที่
/application/utils เป็นอันเรียบร้อย
ข้อที่ 2, 3 อันนี้หัวใจเลยครับ ไป extend loader ออกมาไว้ที่
/application/core/MY_Loader.php
แล้วเติมส่วน load util, utils, autoload เข้าไปซะหน่อย ตามโคดข้างล่างนี่ (ขอไม่อธิบาย นะ ก็ Copy มาจาก ตัว load helper นั่นแหละ)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); /** * MY_Loader Class * * Append method to parent * * @package CodeIgniter * @subpackage Libraries * @author Tee++; * @category Loader * @link http://www.jquerytips.com */ class MY_Loader extends CI_Loader { /** * List of paths to load utils from * * @var array * @access protected */ protected $_ci_utils_paths = array(); /** * List of loaded utils * * @var array * @access protected */ protected $_ci_utils = array(); /** * Override Initialize * * This method is add utlis config * * @param array * @return void */ public function initialize($controller=null) { parent::initialize($controller); // config utils path and check autoloading $this->_ci_utils_paths = array(APPPATH, BASEPATH); $this->_ci_utils_autoloader(); } /** * Load Util * * This function loads the specified util file. * This is core function to really file. * * @access protected * @param mixed * @return void */ public function util($utils = array()) { foreach ($this->_ci_prep_filename($utils, 'CI', true) as $util) { if (isset($this->_ci_utils[$util])) { continue; } $ext_util = APPPATH.'utils/'.config_item('subclass_prefix').$util.'.php'; // Is this a util extension request? if (file_exists($ext_util)) { $base_util = BASEPATH.'utils/'.$util.'.php'; if ( ! file_exists($base_util)) { show_error('Unable to load the requested file: utils/'.$util.'.php'); } include_once($ext_util); include_once($base_util); $this->_ci_utils[$util] = TRUE; log_message('debug', 'util loaded: '.$util); continue; } // Try to load the util foreach ($this->_ci_utils_paths as $path) { if (file_exists($path.'utils/'.$util.'.php')) { include_once($path.'utils/'.$util.'.php'); $this->_ci_utils[$util] = TRUE; log_message('debug', 'Util loaded: '.$util); break; } } // unable to load the util if ( ! isset($this->_ci_utils[$util])) { show_error('Unable to load the requested file: utils/'.$util.'.php'); } } } /** * Load Utils * * This is simply an alias to the above function in case the * user has written the plural form of this function. * * @param array * @return void */ public function utils($utils) { foreach ($utils as $_util) $this->util($_util); } /** * Prep filename * Override from parent * * This function preps the name of various items to make loading them more reliable. * * @param mixed * @param string * @param bool * @return array */ protected function _ci_prep_filename($filename, $extension, $opposite=false) { if ($opposite == false) { return parent::_ci_prep_filename($filename, $extension); } // opposite prep in front if ( ! is_array($filename)) { return array($extension.ucfirst(str_replace('.php', '', str_replace($extension, '', $filename)))); } else { foreach ($filename as $key => $val) { $filename[$key] = $extension.ucfirst(str_replace('.php', '', str_replace($extension, '', $val))); } return $filename; } } /** * Utils Autoloader * * The config/autoload.php file contains an array that permits sub-systems, * utils to be loaded automatically. * * @param array * @return void */ private function _ci_utils_autoloader() { if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php')) { include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'); } else { include(APPPATH.'config/autoload.php'); } if ( ! isset($autoload)) { return FALSE; } // auto load utils if (isset($autoload['utils']) AND count($autoload['utils']) > 0) { $this->utils($autoload['utils']); } } } |
** ส่วน autoload ที่ไม่ override master มาแก้เพราะว่า master มันเป็น private function แล้วก็ยังไง $autoload มันก็ไม่มาอยู่ดีไม่อยากไปแก้ core มันเลยใช้วิธีเขียนซ้ำเอาครับ
ที่นี้เราลองมาเขียน util กันงานๆ สักตัวนึงที่
application/utils/CIUser.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <?php class CIUser { public static function getInfo($id) { $data = array( 'id' => 1, 'name' => "Pattanai", 'nickname' => "Tee++;", 'website' => "http://www.jquerytips.com" ); return new CIUserAttibutes($data); } public static function getAuthInfo() { return "Get User Who Logged In Info."; } } class CIUserAttibutes { private $_user_info; public function __construct($user_info) { $this->_user_info = $user_info; } public function getAttrs() { if (is_array($this->_user_info)) { return $this->_user_info; } return; } public function getAttr($attr) { if (array_key_exists($attr, $this->_user_info)) { return $this->_user_info[$attr]; } return; } } |
แล้วเราลองมาเรียกใช้ใน Controller กันดู
1 2 3 4 5 | public function test() { $this->load->util('user'); echo CIUser::getInfo(1)->getAttr('website'); } |
เท่านี้เราก็จะได้ข้อมูลตามที่เราต้องการแล้วครับ รวมไปถึงเรายังไปเขียน autoload ได้เหมือนเดิมที่
/application/config/autoload.php
1 2 3 4 5 6 7 8 9 10 11 | /* | ------------------------------------------------------------------- | Auto-load Utils | ------------------------------------------------------------------- | Prototype: | | $autoload['utils'] = array('user'); | */ $autoload['utils'] = array('user'); |
เท่านี้ก็เป็นอันจบ เราก็จะได้ utilities มาใช้ง่ายๆ เหมือน Framework อื่นๆ กันแล้วล่ะครับ