Advertisement
Guest User

Untitled

a guest
Aug 20th, 2016
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 28.53 KB | None | 0 0
  1. <?php
  2. /**
  3. * Class untuk berinteraksi dengan database
  4. *
  5. * @author Khaerul Amin
  6. * @version 1.0
  7. * @license FreeBSD
  8. */
  9.  
  10. if (!defined('HARMONI')) {
  11. exit;
  12. }
  13.  
  14. class DataBase {
  15. /**
  16. * Konstan untuk index numeric dan asosiatif
  17. *
  18. */
  19. const BOTH = 1;
  20.  
  21. /**
  22. * Konstan untuk index numeric
  23. *
  24. */
  25. const NUM = 2;
  26.  
  27. /**
  28. * Konstan untuk index asosiatif
  29. *
  30. */
  31. const ASSOC = 4;
  32.  
  33. /**
  34. * Konstan untuk objek
  35. *
  36. */
  37. const OBJ = 8;
  38.  
  39. /**
  40. * Konstan untuk mendapatkan data sekaligus
  41. *
  42. * @var int
  43. * @access public
  44. * @constant
  45. */
  46. const ALL = 16;
  47.  
  48. /**
  49. * Konstan untuk mengurutkan hasil query secara ascending (a-z)
  50. *
  51. * @var int
  52. * @access public
  53. * @constant
  54. */
  55. const ASC = 32;
  56.  
  57. /**
  58. * Konstan untuk mengurutkan hasil query secara descending (z-a)
  59. *
  60. * @var int
  61. * @access public
  62. * @constant
  63. */
  64. const DESC = 64;
  65.  
  66. /**
  67. * Tempat untuk menyimpan koneksi ke database
  68. *
  69. * @var object PDO
  70. * @access protected
  71. */
  72. protected static $pdo_dbh;
  73.  
  74. /**
  75. * Tempat untuk menyimpan hasil query terakhir
  76. *
  77. * @var obj
  78. * @access protected
  79. */
  80. protected $pdo_stmt;
  81.  
  82. /**
  83. * Internal token untuk membuat perintah sql
  84. *
  85. * @var array
  86. * @access protected
  87. */
  88. protected $arr_token;
  89.  
  90. /**
  91. * Array konfigurasi untuk terhubung ke database
  92. *
  93. * @var array
  94. * @access protected
  95. */
  96. protected $arr_config;
  97.  
  98. /**
  99. * Punctuation untuk klausa and dan or
  100. *
  101. * @var string
  102. * @access protected
  103. */
  104. protected $str_punc;
  105.  
  106. /**
  107. * Perintah yang sedang dijalankan
  108. *
  109. * @var string
  110. * @access protected
  111. */
  112. protected $str_cmd;
  113.  
  114.  
  115. /**
  116. * Membuat instance baru
  117. *
  118. * @param array $config array konfigurasi untuk mengakses database
  119. * @return object PDO
  120. * @access public
  121. * @constructor
  122. */
  123. function __construct(array $config) {
  124. $this->str_punc = '';
  125. $this->str_cmd = '';
  126. $this->arr_token = [
  127. 'select' => [],
  128. 'insert' => [],
  129. 'update' => [],
  130. 'delete' => [],
  131. 'create' => [],
  132. 'clone' => [],
  133. 'copy' => []
  134. ];
  135. $this->arr_config = $config;
  136. if (self::$pdo_dbh === null) {
  137. $this->internalConnect();
  138. }
  139. }
  140.  
  141. /**
  142. * Destructor untuk class ini
  143. *
  144. * @return void
  145. * @access public
  146. */
  147. function __destruct() {
  148. self::$pdo_dbh = null;
  149. $this->pdo_stmt = null;
  150. }
  151.  
  152. /**
  153. * Fungsi untuk menjalankan query string
  154. *
  155. * @return bool true jika berhasil dijalankan atau false jika gagal
  156. * @access public
  157. */
  158. function exec() {
  159. $this->pdo_stmt = null;
  160. $data = $this->internalBuildQuery();
  161.  
  162. $sql = $data[0]; $filler = $data[1];
  163. $stmt = self::$pdo_dbh->prepare($sql);
  164.  
  165. if ($filler) {
  166. $filler = $this->internalGetType($filler);
  167.  
  168. // Isi semua placeholder
  169. foreach ($filler as $f) {
  170. $stmt->bindValue($f['index'], $f['value'], $f['type']);
  171. }
  172. }
  173.  
  174. $stmt->execute();
  175. $this->pdo_stmt = $stmt;
  176.  
  177. return $this;
  178. }
  179.  
  180. /**
  181. * Mengambil nilai dari hasil PDO::exec
  182. *
  183. * Fungsi ini hanya boleh dipanggil ketika perintah sebelumnya adalah
  184. * DataBase::select jika tidak maka akan menampilkan error
  185. *
  186. * @param mixed &$var variable yang akan menerima hasil dari PDO::fetch
  187. * @param int $flag key yang akan dipakai
  188. * @return bool true jika masih ada data
  189. * @access public
  190. */
  191. function fetch(&$var, $flag = self::BOTH) {
  192. $cmd = $this->str_cmd;
  193. $stmt = $this->pdo_stmt;
  194.  
  195. // Handle pemanggilan yang invalid
  196. if ($cmd !== 'select') {
  197. throw new Exception('DataBase::fetch: Hanya bisa dipanggil jika perintah terakhirnya DataBase::select');
  198. }
  199.  
  200. // Handle jika sudah tidak ada data lagi
  201. if ($stmt === null) {
  202. $var = null;
  203. return false;
  204. }
  205.  
  206. // Handle type berdasarkan flag.
  207. if (self::BOTH & $flag) {
  208. $type = PDO::FETCH_BOTH;
  209. }
  210.  
  211. else if (self::ASSOC & $flag) {
  212. $type = PDO::FETCH_ASSOC;
  213. }
  214.  
  215. else if (self::NUM & $flag) {
  216. $type = PDO::FETCH_NUM;
  217. }
  218.  
  219. else if (self::OBJ & $flag) {
  220. $type = PDO::FETCH_OBJ;
  221. }
  222.  
  223. else {
  224. $type = PDO::FETCH_BOTH;
  225. }
  226.  
  227. // Handle jika user ingin mengambil data sekaligus
  228. if (self::ALL & $flag) {
  229. $var = $stmt->fetchAll($type);
  230. $this->pdo_stmt = null;
  231.  
  232. return true;
  233. }
  234.  
  235. $var = $stmt->fetch($type);
  236.  
  237. !$var && $this->pdo_stmt = null;
  238.  
  239. return $var !== false;
  240. }
  241.  
  242. /**
  243. * Shortcut untuk DataBase::select('*', blablabla) yang terlihat nanggung
  244. *
  245. * @param string $table nama table tempat data berada
  246. * @return self
  247. * @access public
  248. */
  249. function selectAll($table) {
  250. return $this->select([ '*' ], $table);
  251. }
  252.  
  253. /**
  254. * Fungsi untuk menjalankan Query yang rumit
  255. *
  256. * @param string $query kueri yang akan dieksekusi
  257. * @return mixed
  258. * @access public
  259. */
  260. function query($query) {
  261. return self::$pdo_dbh->query($query);
  262. }
  263.  
  264. /**
  265. * Membuat perintah SELECT di sql
  266. *
  267. * @param mixed $column array yang berisi nama kolom yang akan dipilih. akan di rubah ke array jika bulan array
  268. * @param string $table nama table yang akan dipilih
  269. * @return self
  270. * @access public
  271. */
  272. function select($column, $table) {
  273. $this->str_cmd = 'select';
  274.  
  275. // Reset setiap pemanggilan agar tidak terjadi konflik
  276. $this->arr_token['select'] = [];
  277. $token =& $this->arr_token['select'];
  278.  
  279. !is_array($column) && $column = [ $column ];
  280.  
  281. $token['column'] = $column;
  282. $token['table'] = $table;
  283. $token['where'] = [];
  284. $token['filter'] = [];
  285. $token['tokenize'] = true;
  286.  
  287. return $this;
  288. }
  289.  
  290. /**
  291. * Membuat perintah INSERT di sql
  292. *
  293. * @param string $table nama table yang akan dimasukan data baru
  294. * @param array $data nama kolom dan value yang akan dimasukan
  295. * @return self
  296. * @access public
  297. */
  298. function insert($table, array $data) {
  299. $this->str_cmd = 'insert';
  300.  
  301. // Reset setiap pemanggilan agar tidak terjadi konflik
  302. $this->arr_token['insert'] = [];
  303. $token =& $this->arr_token['insert'];
  304.  
  305. $token['table'] = $table;
  306. $token['column'] = array_keys($data);
  307. $token['data'] = array_values($data);
  308. $token['where'] = [];
  309. $token['tokenize'] = true;
  310.  
  311. return $this;
  312. }
  313.  
  314. /**
  315. * Menjalankan perintah UPDATE di sql
  316. *
  317. * @param string $table table yang akan diubah
  318. * @param array $data kolom yang akan dirubah dan nilai barunya
  319. * @return self
  320. * @access public
  321. */
  322. function update($table, array $data) {
  323. $this->str_cmd = 'update';
  324.  
  325. // Reset setiap pemanggilan agar tidak terjadi konflik
  326. $this->arr_token['update'] = [];
  327. $token =& $this->arr_token['update'];
  328.  
  329. $token['table'] = $table;
  330. $token['column'] = array_keys($data);
  331. $token['data'] = array_values($data);
  332. $token['where'] = [];
  333. $token['tokenize'] = true;
  334.  
  335. return $this;
  336. }
  337.  
  338. /**
  339. * Menjalankan fungsi DELETE di sql
  340. *
  341. * Untuk alasan keamanan database, fungsi ini akan menampilkan error jika
  342. * dipanggil tanpa ada WHERE klausa karena bisa menghapus semua data dalam suatu table
  343. *
  344. * @param string $table nama table dimana data akan dihapus
  345. * @return self
  346. * @access public
  347. */
  348. function delete($table) {
  349. $this->str_cmd = 'delete';
  350.  
  351. // Reset setiap pemanggilan agar tidak terjadi konflik
  352. $this->arr_token['delete'] = [];
  353. $token =& $this->arr_token['delete'];
  354.  
  355. $token['table'] = $table;
  356. $token['where'] = [];
  357. $token['tokenize'] = true;
  358.  
  359. return $this;
  360. }
  361.  
  362. /**
  363. * Menjalankan perintah CREATE TABLE di sql
  364. *
  365. * @param string $table nama table yang akan dibuat
  366. * @param array $data array untuk nama kolom dan tipe data
  367. * misal: ['id' => 'SERIAL']
  368. * @param array $config konfigurasi meliputi:
  369. * [x] use_if => true Haruskah menggunakan klausa IF NOT EXISTS
  370. * [x] truncate => false Akan menghapus table jika table sudah ada
  371. * [x] engine => InnoDB default storage engine
  372. * [x] charset => utf-8 default charset
  373. * [x] primary_key => ''
  374. * [x] unique => '' kolom yang akan menjadi index
  375. * @return self
  376. * @access public
  377. */
  378. function create($table, array $data = [], array $config = []) {
  379. $this->str_cmd = 'create';
  380.  
  381. // Reset setiap pemanggilan agar tidak terjadi konflik
  382. $this->arr_token['create'] = [];
  383. $token =& $this->arr_token['create'];
  384.  
  385. // Default config
  386. // TODO: Mensupport multiple unique dan primary key
  387. static $default_config = [
  388. 'use_if' => true,
  389. 'truncate' => false,
  390. 'engine' => 'InnoDB',
  391. 'charset' => 'utf8',
  392. 'primary_key' => '',
  393. 'unique' => ''
  394. ];
  395.  
  396. $config = array_merge($default_config, $config);
  397.  
  398. $token['table'] = $table;
  399. $token['data'] = $data;
  400. $token['config'] = $config;
  401. $token['where'] = [];
  402. $token['tokenize'] = true;
  403.  
  404. return $this;
  405. }
  406.  
  407. /**
  408. * Membuat perintah CREATE TABLE LIE di sql
  409. *
  410. * Fungsi ini bertugas untuk mengcopy table satu ketable yang lain dalam satu database
  411. * Fungsi ini hanya mengcopy tablenya saja, jika ingin isinya juga gunakan DataBase::clone
  412. * Jika parameter pertama beripa array, maka akan diasumsikan bahwa key berupa $original_table dan valuenya $new_table
  413. *
  414. * @param string $original_table table asal yang akan dicopy
  415. * @param string $new_table nama table hasil dari copyan
  416. * @param array $config array konfigurasi meliputi:
  417. * [x] use_if => true Jika true maka akan menggunakan klausa IF NOT EXIST
  418. * [x] truncate => false Jika true akan menghapus table yang sudah ada
  419. * @return self
  420. * @access public
  421. */
  422. function cloneTable($original_table, $new_table = '', array $config = []) {
  423. $this->str_cmd = 'clone';
  424.  
  425. // Reset dalam setiap pemanggilan
  426. $this->arr_token['clone'] = [];
  427. $token =& $this->arr_token['clone'];
  428.  
  429. static $default_config = [
  430. 'use_if' => true,
  431. 'truncate' => false
  432. ];
  433.  
  434. $config = array_merge($default_config, $config);
  435. $data = $original_table;
  436. $query = '';
  437.  
  438. if (is_string($original_table)) {
  439. // Jika $original_table string, $new_table tidak boleh kosong
  440. if (empty($new_table)) {
  441. throw new Exception('DataBase::cloneTable: Nama table baru tidak boleh kosong');
  442. }
  443.  
  444. $data = [ $original_table => $new_table ];
  445. }
  446.  
  447. foreach ($data as $old => $new) {
  448. if (empty($old) || empty($new)) {
  449. throw new Exception(__METHOD__ . ': Original Table atau New Table tidak boleh kosong');
  450. }
  451.  
  452. if ($config['truncate']) {
  453. $query .= "DROP TABLE IF EXISTS {$new};";
  454. }
  455.  
  456. $query .= $config['use_if'] ?
  457. "CREATE TABLE IF NOT EXISTS {$new} LIKE {$old};" :
  458. "CREATE TABLE {$new} LIKE {$old};";
  459. }
  460.  
  461. $token['tokenize'] = false;
  462. $token['query'] = $query;
  463.  
  464. return $this;
  465. }
  466.  
  467. /**
  468. * Membuat perintah SELECT INTO di sql
  469. *
  470. * @param array|string $column nama kolom yang akan diclone. Jika berupa string akan dirubah kebentuk array
  471. * @param string $original_table nama tabledimana data akan diambil
  472. * @param atring $target_table table dimana data baru akan ditempatkan
  473. * @param array|string $dest kolom tempat data akan dimasukan
  474. * @return self
  475. * @access public
  476. */
  477. function copyTable($original_table, $target_table, $column, $dest = '') {
  478. $this->str_cmd = 'copy';
  479.  
  480. // Reset dalam setiap pemanggilan
  481. $this->arr_token['copy'] = [];
  482. $token =& $this->arr_token['copy'];
  483.  
  484. // Rubah kebentuk array jika bukan array
  485. if (!is_array($column)) {
  486. $column = [ $column ];
  487. }
  488.  
  489. if (!is_array($dest)) {
  490. $dest = [ $dest ];
  491. }
  492.  
  493. $token['original'] = $original_table;
  494. $token['target'] = $target_table;
  495. $token['column'] = $column;
  496. $token['destination'] = $dest;
  497. $token['where'] = [];
  498. $token['tokenize'] = true;
  499.  
  500. return $this;
  501. }
  502.  
  503. /**
  504. * Shortcut untuk mengklon seluruh data dari satu table ke table yang lain
  505. *
  506. * @param string $original_table table dimana data berada
  507. * @param string $target_table table data akab disimpan
  508. * @return self
  509. * @access public
  510. */
  511. function copyAll($original_table, $target_table) {
  512. return $this->copyTable($original_table, $target_table, [ '*' ], [ '' ]);
  513. }
  514.  
  515. /**
  516. * Membuat WHERE klausa di sql
  517. *
  518. * Jika parameter pertama array maka akan diasumsikan itu adalah multiple
  519. * where dimana key berupa nama kolom dan value berupa nilai-nya dengan tanda
  520. * penghubung sama dengan (=) dan setiap where dipisahkan dengan Klausa AND
  521. *
  522. * @param mixed $column nama kolom yang akan ditest
  523. * @param mixed $condition kondisi yang akan dites (=|!=|<>|like|..)
  524. * @param mixed $value nilai yang akan ditest
  525. * @return self
  526. * @access public
  527. */
  528. function where($column, $condition = '', $value = '') {
  529. // Perintah yang dijalankan saat ini. (SELECT|UPDATE|DELETE|..)
  530. $cmd = $this->str_cmd;
  531.  
  532. // Handle penggunaan where yang tidak valid
  533. if ($cmd === '') {
  534. // TODO: Membuat class DataBaseException
  535. throw new Exception('DataBase::where: Penggunaan where yang tidak benar');
  536. }
  537.  
  538. $token =& $this->arr_token[$cmd];
  539.  
  540. // Handle simple where
  541. if (!is_array($column)) {
  542. $token['where'][] = [
  543. 'punctuation' => $this->str_punc,
  544. 'column' => $column,
  545. 'condition' => $condition,
  546. 'value' => $value
  547. ];
  548. $this->str_punc = '';
  549.  
  550. return $this;
  551. }
  552.  
  553. // Ok. jadi ini adalah multiple where jadi
  554. $first = true;
  555. foreach ($column as $column => $value) {
  556. $punc = 'AND';
  557.  
  558. // Handle pertama kali
  559. if ($first) {
  560. $first = false;
  561. $punc = $this->str_punc;
  562. $this->str_punc = '';
  563. }
  564.  
  565. $token['where'][] = [
  566. 'punctuation' => $punc,
  567. 'column' => $column,
  568. 'value' => $value,
  569. 'condition' => '='
  570. ];
  571. }
  572.  
  573. return $this;
  574. }
  575.  
  576. /**
  577. * Membuat klausa ORDER | LIMIT | OFFSET di perintah sql
  578. *
  579. * Jika perintah yang dijalankan bukan DataBase::select maka akan diabaikan secara tersembunyi
  580. *
  581. * @param array $preference konfigurasi yang diharapkan
  582. * @return self
  583. * @access public
  584. */
  585. function filter(array $preference) {
  586. // Kembali, jika bukan select
  587. if ($this->str_cmd !== 'select') {
  588. return $this;
  589. }
  590.  
  591. $filter =& $this->arr_token['select']['filter'];
  592.  
  593. // foreach lebih praktis
  594. if (isset($preference['order'])) {
  595. $order = $preference['order'];
  596. if (!is_array($order)) {
  597. $col = $order;
  598. $dir = 'ASC';
  599. } else {
  600. $col = $order[0];
  601. $dir = (self::DESC & $order[1]) ? 'DESC' : 'ASC';
  602. }
  603.  
  604. $filter['order'] = [
  605. 'column' => $col,
  606. 'direction' => $dir
  607. ];
  608. }
  609.  
  610. if (isset($preference['limit'])) {
  611. $filter['limit'] = $preference['limit'];
  612. }
  613.  
  614. // Harus ada limit jika offset diset. Akan error di mysql jika ada offset tanpa limit
  615. if (isset($preference['offset']) && isset($preference['limit'])) {
  616. $filter['offset'] = $preference['offset'];
  617. }
  618.  
  619. return $this;
  620. }
  621.  
  622. /**
  623. * Menjalankan klausa AND di sql
  624. *
  625. * Ada suffix s karena AND sudah didefine oleh PHP sehingga kita tidak bisa menggunakan fungsi tersebut
  626. *
  627. * @return self
  628. * @access public
  629. */
  630. function ands() {
  631. $this->str_punc = 'AND';
  632.  
  633. return $this;
  634. }
  635.  
  636. /**
  637. * Menjalankan klausa OR di sql
  638. *
  639. * Ada suffix s karena OR sudah didefine oleh PHP sehingga kita tidak bisa menggunakan fungsi tersebut
  640. *
  641. * @return self
  642. * @access public
  643. */
  644. function ors() {
  645. $this->str_punc = 'OR';
  646.  
  647. return $this;
  648. }
  649.  
  650. /**
  651. * Internal fungsi untuk membuat perintah SQL
  652. *
  653. * @return string
  654. * @access private
  655. */
  656. private function internalBuildQuery() {
  657. // Perintah saat ini
  658. $cmd = $this->str_cmd;
  659.  
  660. // Handle jika perintah tidak perlu ditokenize
  661. if (!$this->arr_token[$cmd]['tokenize']) {
  662. return [ $this->arr_token[$cmd]['query'], false ];
  663. }
  664.  
  665. switch ($cmd) {
  666. case 'select':
  667. return $this->internalBuildSelect();
  668.  
  669. case 'insert':
  670. return $this->internalBuildInsert();
  671.  
  672. case 'update':
  673. return $this->internalBuildUpdate();
  674.  
  675. case 'delete':
  676. return $this->internalBuildDelete();
  677.  
  678. case 'create':
  679. return $this->internalBuildCreate();
  680.  
  681. case 'copy':
  682. return $this->internalBuildCopy();
  683.  
  684. default:
  685. throw new Exception('DataBase::internalBuildQuery: Methode tidak dikenali');
  686. }
  687. }
  688.  
  689. /**
  690. * Membuat SQL query dengan perintah SELECT dari token yang ada
  691. *
  692. * @return array
  693. * @access private
  694. */
  695. private function internalBuildSelect() {
  696. $ret = '';
  697. $cmd = $this->str_cmd;
  698. $extra = ['', false];
  699. $token = $this->arr_token[$cmd];
  700.  
  701. $column = implode(',', $token['column']);
  702. $ret .= "SELECT $column FROM {$token['table']}";
  703.  
  704. if (count($token['where'])) {
  705. $extra = $this->internalBuildWhere($token['where']);
  706. $ret .= " $extra[0] ";
  707. }
  708.  
  709. if (count($token['filter'])) {
  710. $filter = $token['filter'];
  711. if (isset($filter['order'])) {
  712. $order = $filter['order'];
  713. $ret .= " ORDER BY {$order['column']} {$order['direction']} ";
  714. }
  715.  
  716. if (isset($filter['limit'])) {
  717. $ret .= " LIMIT {$filter['limit']} ";
  718.  
  719. if (isset($filter['offset'])) {
  720. $ret .= " OFFSET {$filter['offset']} ";
  721. }
  722. }
  723. }
  724.  
  725. return [ $ret, $extra[1] ];
  726. }
  727.  
  728. /**
  729. * Membuat SQL query dengan perintah INSERT dari token yang ada
  730. *
  731. * @return array array yang berisi query string dan data untuk placeholder untuk digunakan di PDO::prepare
  732. * @access private
  733. */
  734. private function internalBuildInsert() {
  735. // Perintah saat ini
  736. $ret = '';
  737. $cmd = $this->str_cmd;
  738. $token = $this->arr_token[$cmd];
  739.  
  740. $column = $token['column'];
  741. $data = $token['data'];
  742.  
  743. $holder = $this->internalCreatePlaceholder(count($data));
  744. $str_column = implode(',', $column);
  745. $str_holder = implode(',', $holder);
  746.  
  747. $ret .= "INSERT INTO {$token['table']} ($str_column) VALUES ($str_holder)";
  748.  
  749. // INSERT tidak perlu WHERE klausa
  750. return [$ret, $data];
  751. }
  752.  
  753. /**
  754. * Membuat SQL query UPDATE dari token yang ada
  755. *
  756. * @return array
  757. * @access private
  758. */
  759. private function internalBuildUpdate() {
  760. $ret = '';
  761. $extra = ['', false];
  762. $cmd = $this->str_cmd;
  763. $token = $this->arr_token[$cmd];
  764.  
  765. $column = $token['column'];
  766. $data = $token['data'];
  767. // $holder = $this->internalCreatePlaceholder(count($data));
  768.  
  769. $str_column = implode(',', $column);
  770.  
  771. if (count($token['where'])) {
  772. $extra = $this->internalBuildWhere($token['where']);
  773. }
  774.  
  775. $ret .= "UPDATE {$token['table']} SET";
  776. foreach ($column as $col) {
  777. $ret .= " $col = ?,";
  778. }
  779. $ret = rtrim($ret, ',');
  780.  
  781. // Mungkin saja ada where klausa
  782. if ($extra[1] !== false) {
  783. $ret .= " $extra[0]";
  784. $data = array_merge($data, $extra[1]);
  785. }
  786.  
  787. return [$ret, $data];
  788. }
  789.  
  790. /**
  791. * Membuat SQL query DELETE dari token yang tersedia
  792. *
  793. * @return array
  794. * @access private
  795. */
  796. private function internalBuildDelete() {
  797. $ret = '';
  798. $cmd = $this->str_cmd;
  799. $token = $this->arr_token[$cmd];
  800.  
  801. // DELETE tanpa WHERE klausa
  802. if (!count($token['where'])) {
  803. throw new Exception('DataBase::internalBuildDelete: Tidak ada WHERE klausa');
  804. }
  805.  
  806. $ret .= "DELETE FROM {$token['table']}";
  807. $extra = $this->internalBuildWhere($token['where']);
  808.  
  809. return [ "$ret {$extra[0]}", $extra[1] ];
  810. }
  811.  
  812. /**
  813. * Membuat SQL query CREATE TABLE menggunakan token yang sudah ada
  814. *
  815. * @return array
  816. * @access private
  817. */
  818. private function internalBuildCreate() {
  819. $ret = '';
  820. $cmd = $this->str_cmd;
  821. $token = $this->arr_token[$cmd];
  822.  
  823. $table = $token['table'];
  824. $data = $token['data'];
  825. $config = $token['config'];
  826.  
  827. //-> Membuat klausa CREATE TABLE
  828. // Jika truncate true, hapus table terlebih dahulu jika ada
  829. if ($config['truncate']) {
  830. $ret .= "DROP TABLE IF EXISTS {$table};";
  831. }
  832.  
  833. // Jika use_if true, gunakan klausa IF NOT EXISTS
  834. $ret .= $config['use_if'] ?
  835. "CREATE TABLE IF NOT EXISTS {$table}" :
  836. "CREATE TABLE {$table}";
  837. $ret .= ' ( ';
  838.  
  839. // Tambahkan kolom dan definisinya
  840. foreach ($data as $column => $definition) {
  841. $ret .= "$column $definition,";
  842. }
  843.  
  844. // Tambahkan Primary Key konstrain jika diset
  845. if ($config['primary_key']) {
  846. $ret .= "PRIMARY KEY({$config['primary_key']}),";
  847. }
  848.  
  849. // Tambahkan Unique konstrain jika diset
  850. if ($config['unique']) {
  851. $ret .= "UNIQUE ({$config['unique']}),";
  852. }
  853.  
  854. $ret = rtrim($ret, ',');
  855. $ret .= ') ';
  856.  
  857. // Set Engine, Charset
  858. $ret .= "ENGINE={$config['engine']} DEFAULT CHARSET={$config['charset']};";
  859.  
  860. return [ $ret, false ];
  861. }
  862.  
  863. /**
  864. * Memparse perintah clone sari token yang sudah ada
  865. *
  866. * @return array
  867. * @access private
  868. */
  869. private function internalBuildCopy() {
  870. $ret = '';
  871. $extra = [ '', false ];
  872. $cmd = $this->str_cmd;
  873. $token = $this->arr_token[$cmd];
  874.  
  875. $original = $token['original'];
  876. $target = $token['target'];
  877. $column = $token['column'];
  878. $dest = $token['destination'];
  879.  
  880. // Handle Ketika tidak ada kolom yang dipilih
  881. if (!count($column) ||
  882. empty($column[0]) ||
  883. ($column[0] !== '*' &&
  884. (!count($dest) ||
  885. empty($dest[0])))
  886. ) {
  887. throw new Exception('DataBase::internalBuildCopy: Memerlukan paling tidak satu kolom untuk dipilih dan tempat data diletakan');
  888. }
  889.  
  890. // Handle SELECT *
  891. // NOTE: Hanya mengecek secara naif
  892. if ($column[0] === '*') {
  893. $ret .= "INSERT INTO ${target} SELECT * FROM ${original}";
  894. } else {
  895. // Langkah pertama pastikan kolom yang dipilih dan kolom tujuan memiliki jumlah yang sama.
  896. // Saya juga inginnya mengechek apakah tipe datanya juga sama tapi biarkan mysql yang menghandlenya.
  897. if (count($column) !== count($dest)) {
  898. throw new Exception('DataBase::internalBuildCopy: Jumlah kolom data berasal tidak sama dengan jumlah kolom tujuan');
  899. }
  900.  
  901. $str_column = implode(',', $column);
  902. $str_dest = implode(',', $dest);
  903.  
  904. $ret .= "INSERT INTO ${target} (${str_dest}) SELECT ${str_columb} FROM ${original}";
  905. }
  906.  
  907. if (count($token['where'])) {
  908. $extra = $this->internalBuildWhere($token['where']);
  909.  
  910. $ret .= " {$extra[0]}";
  911. }
  912.  
  913. return [ $ret, $extra[1] ];
  914. }
  915.  
  916. /**
  917. * Membuat placeholder untuk PDO::prepare
  918. *
  919. * @param int $count jumlah placeholder yang akan dibuat
  920. * @return array
  921. * @access private
  922. */
  923. private function internalCreatePlaceholder($count) {
  924. $ret = [];
  925. foreach (range(1, $count) as $num) {
  926. $ret[] = '?';
  927. }
  928.  
  929. return $ret;
  930. }
  931.  
  932. /**
  933. * Memparse WHERE klausa sesuai token
  934. *
  935. * @param array $token token yang akan di parse
  936. * @return array
  937. * @access private
  938. */
  939. private function internalBuildWhere(array $token) {
  940. $ret = ['WHERE ', []];
  941.  
  942. foreach ($token as $T) {
  943. $tmp = '';
  944. !empty($T['punctuation']) && $tmp .= " {$T['punctuation']} ";
  945. $tmp .= "{$T['column']} {$T['condition']} ?";
  946.  
  947. $ret[0] .= $tmp;
  948. $ret[1][] = $T['value'];
  949. }
  950.  
  951. return $ret;
  952. }
  953.  
  954. /**
  955. * Menentukan tipe data sebuah data sebelum dikirim ke database
  956. *
  957. * @param array $data data yang akan dikirim ke database
  958. * @return array
  959. * @access private
  960. */
  961. private function internalGetType(array $data) {
  962. $translation = [
  963. 'string' => PDO::PARAM_STR,
  964. 'integer' => PDO::PARAM_INT,
  965. 'double' => PDO::PARAM_INT,
  966. 'null' => PDO::PARAM_NULL,
  967. 'bool' => PDO::PARAM_BOOL
  968. ]; $ret = [];
  969.  
  970. foreach ($data as $k => $v) {
  971. $type = gettype($v);
  972. $type = isset($translation[$type]) ? $translation[$type] : PDO::PARAM_STR;
  973. $ret[] = [
  974. 'index' => $k + 1,
  975. 'value' => $v,
  976. 'type' => $type
  977. ];
  978. }
  979.  
  980. return $ret;
  981. }
  982.  
  983. /**
  984. * Internal fungsi untuk mengkoneksi ke database
  985. *
  986. * Jika tidak ada konfigurasi maka secara default akan menggunakan konfigurasi yang
  987. * ada di file /harmoni/config.php
  988. *
  989. * @return void
  990. * @access private
  991. */
  992. private function internalConnect() {
  993. $config = $this->arr_config;
  994.  
  995. $host = isset($config['host']) ? $config['host'] : DB_HOST;
  996. $user = isset($config['user']) ? $config['user'] : DB_USER;
  997. $pass = isset($config['pass']) ? $config['pass'] : DB_PASS;
  998. $name = isset($config['name']) ? $config['name'] : DB_NAME;
  999.  
  1000. $dsn = "mysql: host=$host; dbname=$name";
  1001.  
  1002. try {
  1003. self::$pdo_dbh = new PDO($dsn, $user, $pass);
  1004. // Production : PDO::ERRMODE_SILENT
  1005. // Development: PDO::ERRMODE_EXCEPTION
  1006. self::$pdo_dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  1007. } catch (PDOException $error) {
  1008. // Berhenti mengeksekusi skrip karena koneksi ke database gagal
  1009. exit($error->getMessage());
  1010. }
  1011. }
  1012. }
  1013.  
  1014. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement