บทความนี้จะ setup codeigniter 2.1 เพื่อให้ใช้งาน Doctrine 2.3.0 โดยใช้
OS: Windows 7
Server: WAMP (Apache: 2.2.22, PHP 5.3.13, MySql 5.2.24)
เป็นรูปแบการใช้งาน Doctrine ผ่าน hook ข้อดีก็คือเอาออกได้ทุกเวลา ข้อเสียคือเอาออก app ก็ error ทั้ง App ไม่มีการ buidin ลงไป หากต้องการที่จะใช้งานแบบ Library ให้อ่านที่ Integrating with CodeIgniter
ขั้นแรกให้เราเอา code ของ Codeigniter มาก่อน โดย
- fork Codeigniter มาจาก Github เมื่อได้มาให้ set brance เป็น 2.1 stable แล้ว clone ลงเครื่อง หรือ
- download มาจากเว็บของ Codeigniter สามารถทำได้ทั้งสองวิธี และไม่มีวิธีใหนดีกว่ากัน เพราะได้ source ออกมาเหมือนกัน (ที่ทำใช้ fork มาเพราะจะได้มีตัวอย่างเก็บไว้เป็น path ให้ดูบน git ให้ด้วย)
ในการติดตั้งครั้งนี้คงอยากรันเพื่อทดสอบว่าทำงานได้หรือไม่ ให้ setup vhost ไว้ก่อนเลยล่วงหน้า โดยการ set virtual host ให้ webserver รัน CodeIgniter ได้ตัวอย่างเช่น
Add local DNS ลงใน
C:\Windows\System32\drivers\etc\hosts
ว่า
127.0.0.1 codeigniter-doctrine.local
เพิ่ม config นี้ลงใน config ของ apache (หากงงให้หาวิธีการ setup virtual host ของ apache)
<virtualhost *:80>
DocumentRoot "C:/wamp/www/codeigniter-doctrine-2.3.0"
ServerName codeigniter-doctrine.local
ServerAlias codeigniter-doctrine.local
</virtualhost>
ให้ลองเข้า
http://codeigniter-doctrine.local/
ผ่านเว็บ browser หากได้ก็จะเจอหน้า Welcome to CodeIgniter!
จากนั้นเราจะติดตั้ง Doctrine ลงมา โดยเราเลือก version 2.3.0(ล่าสุดตอนที่เขียน) ลงมาด้วยการใช้ composer ช่วยเรา เพราะเวลา Install แล้ว composert จะทำ autoload library ให้เราด้วย
เข้าไปที่ codeigniter folder ที่เราได้มา แล้วสร้าง file ชื่อ composer.json แล้วเขียนใน file แบบนี้
{
"require": {
"doctrine/orm": "2.3.0"
}
}เมื่อได้ file composer ว่าเราต้องการใช้ doctrine เราก็ไป get composer ด้วยการเปิด command line แล้วเข้าไปที่ folder ที่เราทำงานอยู่นี้
แล้วเรียก composer มาใช้งานด้วย
curl -s https://getcomposer.org/installer | phpหากเครื่องไม่มี CURL ติดตั้งไว้ให้ใช้ PHP แทนก็ได้(อันนี้ยังไงก็ติดตั้งไว้แน่นอน)
php -r "eval('?>'.file_get_contents('https://getcomposer.org/installer'));"เมื่อได้ composer มาแล้วให้เรา run composer ด้วย
php composer.phar installรอสักพัก composer จะ download Doctrine ORM และสิ่งที่ Doctrine ต้องการทั้งหมดให้ รวมทั้งทำ autoload file ให้เราด้วย
folder ที่ composer ติดตั้งไว้นั้นจะ default ไว้ที่ folder vendor ตรงจุดที่ composer.phar ทำงาน
จากตรงนี้เราก็ได้ library ของทั้ง Codeigniter และ Doctrine 2.3.0 มาใช้งานแล้ว แต่ว่ายังไม่ได้เขียนให้ Codeigniter ใช้งาน Doctrine
ขั้นตอนต่อไปเราจะทำให้ Codeigniter ใช้งาน Doctrine ได้ด้วยการเขียน hook ให้ Codeigniter ไปเรียก library ของ Doctrine มาใช้งาน
ในกรณีนี้เราใช้งาน composer ให้ install Doctrine มาให้เรา แล้ว composer ได้ทำ file autoload ให้เราด้วยเราแค่เรียก autoload ตัวนี้มาใช้งานก็ได้สามาถที่จะใช้งานได้แล้ว
แนวทางของเราก็คือเราจะเขียน hook ให้กับ Codeigniter ไปเรียก autoload ของ composer ขั้นตอนตามนี้
enable hook in codeigniter-doctrine-2.3.0\application\config.php
/*
|--------------------------------------------------------------------------
| Enable/Disable System Hooks
|--------------------------------------------------------------------------
|
| If you would like to use the 'hooks' feature you must enable it by
| setting this variable to TRUE (boolean). See the user guide for details.
|
*/
$config['enable_hooks'] = TRUE;add hook โดยการเพิ่มลงใน codeigniter-doctrine-2.3.0\application\hooks.php ในช่วง pre_controller เราจะตั้งชื่อว่า load_composer.php และมี function ชื่อ load_composer
$hook['pre_controller'] = array(
'function' => 'load_composer',
'filename' => 'load_composer.php',
'filepath' => 'hooks'
);สร้าง hook ใน codeigniter-doctrine-2.3.0\application\hooks ชื่อ load_composer.php มีเนื้อ file คือ
/**
* Include Composer Autoload
*
* @return void
*/
function load_composer(){
require_once FCPATH . "vendor/autoload.php";
}เมื่อถึงตรงนี้ เราจะสามารถใช้งาน Doctrine ได้แล้ว ให้เราทำ hook เพื่อ config path ของ Entities ต่างๆของเราด้วย
add hook โดยการเพิ่มลงใน codeigniter-doctrine-2.3.0\application\hooks.php ในช่วง pre_controller ต่อจากของเดิม
หากเรา hook ที่เดียวกันมากกว่า 1 อันก็ให้สร้างเป็น array แทน
เราจะตั้งชื่อว่า doctrine_connection_configuration.php และมี function ชื่อ doctrine_connection_configuration()
$hook['pre_controller'][] = array(
'function' => 'load_composer',
'filename' => 'load_composer.php',
'filepath' => 'hooks'
);
$hook['pre_controller'][] = array(
'function' => 'doctrine_connection_configuration',
'filename' => 'doctrine_connection_configuration.php',
'filepath' => 'hooks'
);สร้าง folder Entiries ใน applicaion เพื่อเก็บ Entities (ไม่ใช้ folder models เพราะลดการงง)
สร้าง hook ใน codeigniter-doctrine-2.3.0\application\hooks ชื่อ doctrine_connection_configuration.php มีเนื้อ file คือ
<?php
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
/**
* Config the Dcotrine connection
*
* @return array return config at index 0 and entities manager at index 1
*/
function doctrine_connection_configuration(){
include_once(APPPATH . 'config/database.php');
$paths = array(APPPATH . "Entities");
$isDevMode = ENVIRONMENT == 'development';
// the connection configuration
$dbParams = array(
'driver' => 'pdo_' . $db[$active_group]['dbdriver'],
'user' => $db[$active_group]['username'],
'password' => $db[$active_group]['password'],
'dbname' => $db[$active_group]['database'],
);
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
$em = EntityManager::create($dbParams, $config);
return array($config, $em);
}หากต้องการให้ Entities อยู่นอก application เราสามารถ set Entities ให้อยู่ที่อื่นได้ ตาม path ที่ต้องการได้ (กรณีอยากให้ หลายๆ application อยู่ใน Entities เดียวกัน)
หากต้องการการปรับแต่ง config ที่มากกว่านี้ สามารถดูได้ที่ Doctrine configuration reference.
เวลาที่จะรัน CLI ของ Doctrine บน LINUX, UNIX เราจะรันที่
vendor/bin/doctrine
หรือ Windows
vendor\bin\doctrine\doctrine.php.bat
Doctrine จะทำการหา file cli-config.php ตรงจุดที่เรารันอยู่เพราะฉนั้นต้องหาที่อยู่ให้ file นี้ ในที่นี้จะให้อยู่ที่
application\bin\cli-config.php
โดยข้างในคือ
<?php
define('ENVIRONMENT', 'development');
define('APPPATH', dirname(getcwd()) . '/');
define('BASEPATH', dirname(APPPATH) . '/');
include_once(APPPATH . 'hooks/doctrine_connection_configuration.php');
list($config, $em) = doctrine_connection_configuration();
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em)
));หาก นำ file ไปอยู่ที่อื่น ก็ให้ set APPPATH และ BASEPATH ให้ตรงตามที่ต้องการจะ run ก็จะรันได้
มาทดสองตัวอย่างของ Doctrine กัน :)
สร้าง Article.php ใน \application\Entities\
<?php
/** @Entity */
class Article
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
/** @Column(type="string") */
private $headline;
/** @ManyToOne(targetEntity="User") */
private $author;
/** @OneToMany(targetEntity="Comment", mappedBy="article") */
private $comments;
/** @Column(type="boolean") */
private $isDisable;
public function __construct() {
$this->comments = new ArrayCollection();
}
public function getAuthor() { return $this->author; }
public function getComments() { return $this->comments; }
}จากนั้นเข้า command line ไปยัง
\application\bin\
จะเห็น cli-config.php ที่เราได้ทำการเขียนไว้ เราจะทำการรัน cli จากตรงนี้โดยใช้ command
C:\wamp\www\codeigniter-doctrine-2.3.0\application\bin>..\..\vendor\bin\doctrine.php.bat orm:generate-entities ..\..\application\EntitiesDoctrine จะช่วยสร้าง set get ให้เราจนได้เป็นแบบนี้
<?php
/** @Entity */
class Article
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
/** @Column(type="string") */
private $headline;
/** @ManyToOne(targetEntity="User") */
private $author;
/** @OneToMany(targetEntity="Comment", mappedBy="article") */
private $comments;
/** @Column(type="boolean") */
private $isDisable;
public function __construct() {
$this->comments = new ArrayCollection();
}
public function getAuthor() { return $this->author; }
public function getComments() { return $this->comments; }
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set headline
*
* @param string $headline
* @return Article
*/
public function setHeadline($headline)
{
$this->headline = $headline;
return $this;
}
/**
* Get headline
*
* @return string
*/
public function getHeadline()
{
return $this->headline;
}
/**
* Set isDisable
*
* @param boolean $isDisable
* @return Article
*/
public function setIsDisable($isDisable)
{
$this->isDisable = $isDisable;
return $this;
}
/**
* Get isDisable
*
* @return boolean
*/
public function getIsDisable()
{
return $this->isDisable;
}
/**
* Set author
*
* @param User $author
* @return Article
*/
public function setAuthor(\User $author = null)
{
$this->author = $author;
return $this;
}
/**
* Add comments
*
* @param Comment $comments
* @return Article
*/
public function addComment(\Comment $comments)
{
$this->comments[] = $comments;
return $this;
}
/**
* Remove comments
*
* @param Comment $comments
*/
public function removeComment(\Comment $comments)
{
$this->comments->removeElement($comments);
}
}ถือว่าสามารถใช้งาน CLI ได้
หากคุณใช้งาน MAMP ใน OSX คุณต้องปรับตรงนี้เพิ่มเติมด้วย
ใน codeigniter project/config/database.php ให้เติม unix sockpath ลงไปด้วย
เพราะ MAMP ย้ายจาก /var/mysql/mysql.sock ไปไว้ที่ /Applications/MAMP/tmp/mysql/mysql.sock ตัวอย่างคือ
...
...
...
$active_group = ENVIRONMENT;
$active_record = TRUE;
$db['development']['hostname'] = 'localhost';
$db['development']['username'] = 'root';
$db['development']['password'] = 'root';
$db['development']['database'] = 'gopress';
$db['development']['dbdriver'] = 'mysql';
$db['development']['dbprefix'] = '';
$db['development']['pconnect'] = TRUE;
$db['development']['db_debug'] = TRUE;
$db['development']['cache_on'] = FALSE;
$db['development']['cachedir'] = '';
$db['development']['char_set'] = 'utf8';
$db['development']['dbcollat'] = 'utf8_general_ci';
$db['development']['swap_pre'] = '';
$db['development']['autoinit'] = TRUE;
$db['development']['stricton'] = FALSE;
$db['development']['unix_socket'] = '/Applications/MAMP/tmp/mysql/mysql.sock';
$db['production']['hostname'] = 'localhost';
$db['production']['username'] = '';
$db['production']['password'] = '';
$db['production']['database'] = '';
$db['production']['dbdriver'] = 'mysql';
$db['production']['dbprefix'] = '';
$db['production']['pconnect'] = TRUE;
$db['production']['db_debug'] = TRUE;
$db['production']['cache_on'] = FALSE;
$db['production']['cachedir'] = '';
$db['production']['char_set'] = 'utf8';
$db['production']['dbcollat'] = 'utf8_general_ci';
$db['production']['swap_pre'] = '';
$db['production']['autoinit'] = TRUE;
$db['production']['stricton'] = FALSE;
$db['production']['unix_socket'] = '/var/mysql/mysql.sock';
...
...
...จากนั้นไปเพิ่ม unix socket ใน function doctrine_connection_configuration() ตัวแปล $dbParams ของ doctrine
...
...
...
// the connection configuration
$dbParams = array(
'driver' => 'pdo_' . $db[$active_group]['dbdriver'],
'user' => $db[$active_group]['username'],
'password' => $db[$active_group]['password'],
'dbname' => $db[$active_group]['database'],
'unix_socket' => $db[$active_group]['unix_socket'],
);
...
...
...เราก็จะต่อผ่าน socket path อื่น ได้