1: <?php
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: class WsModel extends WsDatabase
48: {
49: 50: 51: 52:
53: public $className = '';
54: 55: 56: 57:
58: public $tableName = '';
59: 60: 61: 62: 63:
64: public $metaName = '';
65: 66: 67: 68: 69: 70: 71:
72: public $columns = array();
73: 74: 75: 76:
77: public $primary_key = 'id';
78: 79: 80: 81:
82: public $columnCanBeNull = array();
83: 84: 85: 86: 87: 88:
89: public $columnType = array();
90: 91: 92: 93: 94: 95:
96: public $columnHeaders = array();
97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115:
116: public $foreignKeys = array();
117: 118: 119: 120: 121: 122:
123: public $hiddenColumns = array();
124:
125:
126: public function __construct()
127: {
128: parent::__construct();
129:
130: 131: 132: 133:
134: $this->className = get_class($this);
135: $name = strtolower(substr($this->className, 0,
136: strpos($this->className, 'Model')));
137:
138:
139: $this->setTableName($name);
140:
141:
142: $this->metaName = $name;
143: }
144:
145:
146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157:
158: public function setTableName($name)
159: {
160: $this->tableName = $name;
161:
162:
163: if (WsConfig::get('db_driver') === 'pgsql') {
164: $query = '
165: SELECT
166: att2.attname AS "child_column",
167: cl.relname AS "parent_table",
168: att.attname AS "parent_column"
169: FROM
170: (SELECT
171: UNNEST(con1.conkey) AS "parent",
172: UNNEST(con1.confkey) AS "child",
173: con1.confrelid,
174: con1.conrelid
175: FROM
176: pg_class cl
177: JOIN pg_namespace ns ON cl.relnamespace = ns.oid
178: JOIN pg_constraint con1 ON con1.conrelid = cl.oid
179: WHERE
180: cl.relname = :table_name
181: AND con1.contype = \'f\'
182: ) con
183: JOIN pg_attribute att on
184: att.attrelid = con.confrelid AND att.attnum = con.child
185: JOIN pg_class cl ON cl.oid = con.confrelid
186: JOIN pg_attribute att2 ON
187: att2.attrelid = con.conrelid AND att2.attnum = con.parent;
188: ';
189:
190: } else if (WsConfig::get('db_driver') === 'mysql') {
191: $query = '
192: SELECT
193: column_name AS "child_column",
194: referenced_table_name AS "parent_table",
195: referenced_column_name AS "parent_column"
196: FROM information_schema.key_column_usage
197: WHERE table_name = :table_name
198: AND referenced_table_name IS NOT NULL;
199: ';
200: } else if (WsConfig::get('db_driver') === 'sqlite') {
201: $query = 'PRAGMA foreign_key_list(:table_name)';
202: }
203:
204:
205: $this->foreignKeys = array();
206:
207: $results = $this->query($query, array(
208: 'table_name' => $this->tableName
209: ));
210:
211:
212: if (WsConfig::get('db_driver') !== 'sqlite') {
213: foreach ($results as $result) {
214: $this->foreignKeys[$result['child_column']] = array(
215: 'table' => $result['parent_table'],
216: 'column' => $result['parent_column'],
217: 'display' => $result['parent_column']
218: );
219: }
220: }
221:
222:
223: if (WsConfig::get('db_driver') === 'sqlite') {
224: $query = 'PRAGMA table_info(:table_name)';
225: } else {
226: $query = '
227: SELECT column_name, is_nullable, data_type
228: FROM information_schema.columns
229: WHERE table_name= :table_name';
230: }
231:
232: $results2 = $this->query($query, array(
233: 'table_name' => $this->tableName
234: ));
235:
236:
237: $this->columns = array();
238: $this->columnHeaders = array();
239: $this->columnIsNull = array();
240: $this->columnType = array();
241:
242: foreach ($results2 as $result) {
243: array_push($this->columns, $result['column_name']);
244:
245: $this->columnCanBeNull[$result['column_name']] =
246: (($result['is_nullable'] =='YES') ? true: false);
247:
248: $this->columnHeaders[$result['column_name']] =
249: $this->tableName.'-'.$result['column_name'];
250:
251:
252: if (stripos($result['data_type'], 'int') !== false) {
253:
254: $this->columnType[$result['column_name']] = 'int_type';
255: } else if (stripos($result['data_type'], 'float') !== false
256: or stripos($result['data_type'], 'real') !== false
257: or stripos($result['data_type'], 'double') !== false
258: or stripos($result['data_type'], 'dec') !== false
259: or stripos($result['data_type'], 'fixed') !== false
260: or stripos($result['data_type'], 'numeric') !== false
261: ) {
262:
263: $this->columnType[$result['column_name']] = 'numeric_type';
264: } else if (stripos($result['data_type'], 'datetime') !== false
265: or stripos($result['data_type'], 'timestamp') !== false
266: ) {
267:
268: $this->columnType[$result['column_name']] = 'timestamp_type';
269: } else if (stripos($result['data_type'], 'date') !== false) {
270:
271: $this->columnType[$result['column_name']] = 'date_type';
272: } else if (stripos($result['data_type'], 'time') !== false) {
273:
274: $this->columnType[$result['column_name']] = 'time_type';
275: } else if (stripos($result['data_type'], 'text') !== false) {
276:
277: $this->columnType[$result['column_name']] = 'textarea_type';
278: } else if (stripos($result['data_type'], 'bool') !== false) {
279:
280: $this->columnType[$result['column_name']] = 'bool_type';
281: } else {
282:
283: if (stripos($result['column_name'], 'pass') !== false) {
284:
285: $this->columnType[$result['column_name']] = 'password_type';
286: } else if (stripos($result['column_name'], 'url') !== false) {
287:
288: $this->columnType[$result['column_name']] = 'url_type';
289: } else if (stripos($result['column_name'], 'mail') !== false) {
290:
291: $this->columnType[$result['column_name']] = 'mail_type';
292: } else if (stripos($result['column_name'], 'phone') !== false) {
293:
294: $this->columnType[$result['column_name']] = 'phone_type';
295: } else {
296:
297: $this->columnType[$result['column_name']] = 'misc_type';
298: }
299: }
300: }
301:
302: unset($query, $results, $results2);
303: }
304:
305:
306: 307: 308: 309: 310: 311: 312: 313:
314: public function idExists($id)
315: {
316: 317: 318:
319: if (func_num_args() == 1) {
320: $id = func_get_arg(0);
321: } else {
322: header('HTTP/1.1 500 Internal Server Error');
323: trigger_error($this->className
324: .': invalid number of parameters in idExists()',
325: E_USER_ERROR);
326: return false;
327: }
328:
329:
330: $query = 'SELECT '.$this->primary_key;
331: $from = $this->tableName;
332: $where = $this->tableName.'.'.$this->primary_key.' = :id_parameter';
333:
334:
335: $query .= ' FROM '.$from.' WHERE '.$where.' LIMIT 1';
336:
337: $result = $this->query($query, array(
338: 'id_parameter' => intval($id)
339: ));
340:
341:
342: if ($this->nRows == 1) {
343: $result = true;
344: } else {
345: $result = false;
346: }
347:
348: unset($query);
349:
350: return $result;
351: }
352:
353:
354: 355: 356: 357: 358: 359:
360: public function beforeDelete()
361: {
362: return true;
363: }
364:
365:
366: 367: 368: 369: 370: 371:
372: public function delete()
373: {
374: 375: 376:
377: if (func_num_args() == 1) {
378: $id = func_get_arg(0);
379: } else if(property_exists($this, 'id')) {
380: if (isset($this->id)) {
381: $id = $this->id;
382: } else {
383: $id = '-1';
384: }
385: } else {
386: $id = '-1';
387: }
388:
389: if ($id != '-1') {
390: $this->getOne($id);
391: }
392:
393: if (!$this->beforeDelete()) {
394: return false;
395: }
396:
397: if ($id != '-1') {
398:
399: $query = 'DELETE FROM '.$this->tableName.' WHERE '
400: .$this->primary_key.'=:id';
401: if($this->execute($query, array('id' => $id))) {
402: unset($query, $id);
403: return true;
404: } else {
405: header('HTTP/1.1 500 Internal Server Error');
406: trigger_error($this->className
407: .': error occurred while deleting record from model',
408: E_USER_ERROR);
409: unset($query, $id);
410: return false;
411: }
412: }
413: }
414:
415:
416: 417: 418: 419: 420: 421:
422: public function beforeSave()
423: {
424: return true;
425: }
426:
427:
428: 429: 430: 431: 432: 433: 434: 435:
436: public function save()
437: {
438: $query = '';
439: $values = array();
440: $fields = '';
441: $field_val = '';
442:
443: 444: 445:
446: if(property_exists($this, 'id')) {
447: if (isset($this->id)) {
448: $id = $this->id;
449: } else {
450: $id = '-1';
451: }
452: } else {
453: $id = '-1';
454: }
455:
456: if(!$this->beforeSave()) {
457: return false;
458: }
459:
460: if ($this->idExists($id)) {
461:
462: $updates = '';
463: foreach ($this->columns as $column) {
464: if (property_exists($this, $column)) {
465: if(trim($this->$column) !== '') {
466: $updates .= $column.' = :'.$column.', ';
467: $values[$column] = $this->$column;
468: }
469: }
470: }
471:
472:
473: $updates = substr($updates, 0, -2);
474:
475:
476: $query = 'UPDATE '.$this->tableName.' SET '
477: .$updates.' WHERE '.$this->primary_key.'=:id';
478:
479: unset($updates);
480: } else {
481:
482: foreach ($this->columns as $column) {
483: if (property_exists($this, $column)) {
484: if(trim($this->$column) !== '') {
485: $fields .= $column.', ';
486: $field_val .= ':'.$column.', ';
487: $values[$column] = $this->$column;
488: }
489: }
490: }
491:
492:
493: $fields = substr($fields, 0, -2);
494: $field_val = substr($field_val, 0, -2);
495:
496:
497: $query = 'INSERT INTO '.$this->tableName.' ('.$fields
498: .') VALUES ('.$field_val.')';
499:
500: unset($fields, $field_val);
501: }
502:
503: if($this->execute($query, $values)) {
504: unset($query, $values);
505: return true;
506: } else {
507: header('HTTP/1.1 500 Internal Server Error');
508: trigger_error($this->className
509: .': error occurred while saving record to model',
510: E_USER_ERROR);
511: unset($query, $values);
512: return false;
513: }
514: }
515:
516:
517: 518: 519: 520: 521: 522: 523:
524: public function getOne()
525: {
526: 527: 528:
529: if(property_exists($this, 'id')) {
530: if (isset($this->id)) {
531: $id = $this->id;
532: } else {
533: $this->nRows = 0;
534: return false;
535: }
536: } else if (func_num_args() == 1) {
537: $id = func_get_arg(0);
538: } else {
539: $this->nRows = 0;
540: return false;
541: }
542:
543:
544: $query = 'SELECT ';
545: $from = $this->tableName.', ';
546: $where = $this->tableName.'.'.$this->primary_key.'=:id_parameter AND ';
547: foreach ($this->columns as $column) {
548:
549: if (isset($this->foreignKeys[$column])) {
550: $foreign_table = strtolower(
551: $this->foreignKeys[$column]['table']);
552: 553: 554:
555: if ($foreign_table == $this->tableName) {
556: $foreign_id = isset($this->foreignKeys[$column]['column']) ?
557: $this->foreignKeys[$column]['column'] : 'id';
558: $display = isset($this->foreignKeys[$column]['display']) ?
559: $this->foreignKeys[$column]['display'] : $column;
560: $query .= $foreign_table.'_parent.'
561: .$display.' AS '.$column.', ';
562: $from .= $foreign_table.' '.$foreign_table.'_parent, ';
563: $where .= $this->tableName.'.'.$column.'='
564: .$foreign_table.'_parent.'.$foreign_id.' AND ';
565: } else {
566: $foreign_id = isset($this->foreignKeys[$column]['column']) ?
567: $this->foreignKeys[$column]['column'] : 'id';
568: $display = isset($this->foreignKeys[$column]['display']) ?
569: $this->foreignKeys[$column]['display'] : $foreign_id;
570: $query .= $foreign_table.'.'.$display.' AS '.$column.', ';
571: $from .= $foreign_table.', ';
572: $where .= $this->tableName.'.'.$column.'='
573: .$foreign_table.'.'.$foreign_id.' AND ';
574: }
575: } else {
576:
577: $query .= $this->tableName.'.'.$column.' AS '.$column.', ';
578: }
579: }
580:
581: $query2 = substr($query, 0, -2);
582:
583: $from = substr($from, 0, -2);
584:
585: $where = substr($where, 0, -5);
586:
587:
588: $query2 .= ' FROM '.$from.' WHERE '.$where.' LIMIT 1';
589: $result = $this->query($query2, array('id_parameter' => $id));
590:
591:
592: if ($this->nRows == 1) {
593:
594: foreach ($result[0] as $key => $value) {
595: $this->$key = $value;
596: }
597: } else {
598: $this->nRows = 0;
599: $result = false;
600: }
601:
602: unset($query, $query2);
603:
604: return $result[0];
605: }
606:
607:
608: 609: 610: 611: 612: 613: 614: 615: 616:
617: public function getAll($order='', $limit=0, $offset=0)
618: {
619:
620: $query = 'SELECT ';
621: $from = $this->tableName.', ';
622: $where = '';
623: foreach ($this->columns as $column) {
624:
625: if (isset($this->foreignKeys[$column])) {
626: $foreign_table = strtolower(
627: $this->foreignKeys[$column]['table']);
628: 629: 630:
631: if ($foreign_table == $this->tableName) {
632: $foreign_id = isset($this->foreignKeys[$column]['column']) ?
633: $this->foreignKeys[$column]['column'] : 'id';
634: $display = isset($this->foreignKeys[$column]['display']) ?
635: $this->foreignKeys[$column]['display'] : $column;
636: $query .= $foreign_table.'_parent.'
637: .$display.' AS '.$column.', ';
638: $from .= $foreign_table.' '.$foreign_table.'_parent, ';
639: $where .= $this->tableName.'.'.$column.'='
640: .$foreign_table.'_parent.'.$foreign_id.' AND ';
641: } else {
642: $foreign_id = isset($this->foreignKeys[$column]['column']) ?
643: $this->foreignKeys[$column]['column'] : 'id';
644: $display = isset($this->foreignKeys[$column]['display']) ?
645: $this->foreignKeys[$column]['display'] : $foreign_id;
646: $query .= $foreign_table.'.'.$display.' AS '.$column.', ';
647: $from .= $foreign_table.', ';
648: $where .= $this->tableName.'.'.$column.'='
649: .$foreign_table.'.'.$foreign_id.' AND ';
650: }
651: } else {
652:
653: $query .= $this->tableName.'.'.$column.' AS '.$column.', ';
654: }
655: }
656:
657: $query2 = substr($query, 0, -2);
658:
659: $from = substr($from, 0, -2);
660:
661:
662: $query2 .= ' FROM '.$from;
663:
664: if ($where != '') {
665:
666: $where = substr($where, 0, -5);
667: $query2 .= ' WHERE '.$where;
668: }
669:
670:
671: if ($order != '') {
672: $query2 .= ' ORDER BY '.$order;
673: }
674:
675:
676: if ($limit > 0) {
677: $query2 .= ' LIMIT '.$limit;
678: }
679:
680:
681: if ($offset > 0) {
682: $query2 .= ' OFFSET '.$offset;
683: }
684:
685: $result = $this->query($query2);
686:
687: unset($query, $query2);
688:
689:
690: if ($this->nRows >= 1) {
691: return $result;
692: } else {
693: return false;
694: }
695: }
696:
697:
698: 699: 700: 701: 702: 703: 704: 705: 706: 707:
708: public function search($condition='', $order='', $limit=0, $offset=0)
709: {
710: $query = 'SELECT ';
711: $from = $this->tableName.', ';
712: $where = '';
713: foreach ($this->columns as $column) {
714:
715: if (isset($this->foreignKeys[$column])) {
716: $foreign_table = strtolower(
717: $this->foreignKeys[$column]['table']);
718: 719: 720:
721: if ($foreign_table == $this->tableName) {
722: $foreign_id = isset($this->foreignKeys[$column]['column']) ?
723: $this->foreignKeys[$column]['column'] : 'id';
724: $display = isset($this->foreignKeys[$column]['display']) ?
725: $this->foreignKeys[$column]['display'] : $column;
726: $query .= $foreign_table.'_parent.'
727: .$display.' AS '.$column.', ';
728: $from .= $foreign_table.' '.$foreign_table.'_parent, ';
729: $where .= $this->tableName.'.'.$column.'='
730: .$foreign_table.'_parent.'.$foreign_id.' AND ';
731: } else {
732: $foreign_id = isset($this->foreignKeys[$column]['column']) ?
733: $this->foreignKeys[$column]['column'] : 'id';
734: $display = isset($this->foreignKeys[$column]['display']) ?
735: $this->foreignKeys[$column]['display'] : $foreign_id;
736: $query .= $foreign_table.'.'.$display.' AS '.$column.', ';
737: $from .= $foreign_table.', ';
738: $where .= $this->tableName.'.'.$column.'='
739: .$foreign_table.'.'.$foreign_id.' AND ';
740: }
741: } else {
742:
743: $query .= $this->tableName.'.'.$column.' AS '.$column.', ';
744: }
745: }
746:
747: $query2 = substr($query, 0, -2);
748:
749: $from = substr($from, 0, -2);
750:
751:
752: $query2 .= ' FROM '.$from;
753:
754:
755: if ($where != '') {
756:
757: $where = substr($where, 0, -5);
758: $query2 .= ' WHERE '.$where;
759: if ($condition != '') {
760: $query2 .= ' AND '.$condition;
761: }
762: } else {
763: if ($condition != '') {
764: $query2 .= ' WHERE '.$condition;
765: }
766: }
767:
768:
769: if ($order != '') {
770: $query2 .= ' ORDER BY '.$order;
771: }
772:
773:
774: if ($limit > 0) {
775: $query2 .= ' LIMIT '.$limit;
776: }
777:
778:
779: if ($offset > 0) {
780: $query2 .= ' OFFSET '.$offset;
781: }
782:
783: $result = $this->query($query2);
784:
785: unset($query, $query2);
786:
787:
788: if ($this->nRows >= 1) {
789:
790:
791: foreach ($result[0] as $key => $value) {
792: $this->$key = $value;
793: }
794: return $result;
795: } else {
796: return false;
797: }
798: }
799:
800:
801: 802: 803: 804: 805: 806:
807: public function getNextId()
808: {
809:
810: $query = 'SELECT COALESCE(MAX('.$this->primary_key
811: .'), 0) + 1 AS next_id FROM '.$this->tableName;
812: $result = $this->query($query);
813:
814: $next_id = intval($result[0]['next_id']);
815:
816: unset ($query, $result);
817:
818: return $next_id;
819: }
820: }
821: