· 7 years ago · Oct 05, 2018, 07:06 PM
1<?php
2
3/**
4 * Abstract class that serves as the Model in the MVC framework.
5 *
6 * A Model is a representation of the information in the application. A Model's
7 * data is saved in the database and the class is used to handle all the
8 * business logics. This class handles the standard create, read, update
9 * and delete operations. It must be extended to create the concrete
10 * implementation of a Model, and handle any other business logics specific to
11 * that Model.
12 *
13 * The name of the extended class must correlate directly to the name of the
14 * database table it is saving it's data into. The name of the class will be
15 * [table_name]_model. So, for example to represent a user in the application,
16 * there needs to be a class called "user_model" and a database table called
17 * "user". If a different table name is needed, it can be specified in
18 * self::$table_name.
19 *
20 * The Model's data is represented in the class as an element in the
21 * self::$properties array. The index of the array is the Model's property name
22 * and must translate directly to a column with the same name in the database
23 * table. There can only be one Primary Key in the table, and is in the format
24 * [table_name]_id. If a different Primary Key name is needed, it can be
25 * specified in self::$primary_key_name.
26 *
27 * @package Framework
28 */
29abstract class model
30{
31 protected $table_name = '';
32 protected $primary_key_name = '';
33 protected $properties = array();
34 protected $indexes = array();
35 protected $parent_objects = array();
36 protected $conditions = array();
37
38
39
40 protected function __construct()
41 {
42 $this->table_name = $this->get_table_name();
43 $this->primary_key_name = $this->get_primary_key_name();
44
45 $this->add_property($this->primary_key_name, 'INT', '11', 'Primary Key', 1, '', '', '', 1);
46
47 $system = system::get_instance();
48 $schema_file = $system->schemas_path . '/' . get_class($this) . '.schema.php';
49 $default_schema_file = $system->default_schemas_path . '/' . get_class($this) . '.schema.php';
50
51 if (file_exists($schema_file))
52 {
53 include $schema_file;
54 }
55 elseif (file_exists($default_schema_file))
56 {
57 include $default_schema_file;
58 }
59 else
60 {
61 throw new Exception('Schema file for ' . get_class($this) . ' does not exist');
62 }
63
64 $this->add_property('created_date_time', 'DATETIME', '', 'Date/Time the record was created');
65 $this->add_property('created_by', 'INT', '11', 'user_id of user who created the record');
66 $this->add_property('updated_date_time', 'DATETIME', '', 'Date/Time the record was last updated');
67 $this->add_property('updated_by', 'INT', '11', 'user_id of user who last updated the record');
68
69 foreach ($this->properties as $name => $properties)
70 {
71 if (strlen($properties['foreign_key_parent']) > 0)
72 {
73 $fk_parts = $this->parse_foreign_key_parent($properties['foreign_key_parent']);
74 $this->parent_objects[$fk_parts['class_name']] = new $fk_parts['class_name'];
75 }
76 }
77 }
78
79
80
81 /**
82 * Overrides the default __get() and returns the value of the Model's
83 * property, or the related object of a parent class, in that precedence
84 * order. A special property name "primary_key" will return the value of
85 * the object's Primary Key.
86 *
87 * @param string $property_or_class_name
88 * @return mixed
89 */
90 protected final function __get($property_or_class_name)
91 {
92 if ($property_or_class_name == 'primary_key')
93 {
94 return $this->properties[$this->primary_key_name]['value'];
95 }
96 elseif (array_key_exists($property_or_class_name, $this->properties))
97 {
98 return $this->properties[$property_or_class_name]['value'];
99 }
100 elseif (array_key_exists($property_or_class_name, $this->parent_objects))
101 {
102 return $this->parent_objects[$property_or_class_name];
103 }
104 else
105 {
106 throw new Exception(get_class($this) . ' property/parent_object ' . $property_or_class_name . ' does not exist');
107 return '';
108 }
109 }
110
111
112
113 /**
114 * Overrides the default __set() and sets the value of the Model's property,
115 * if it exists.
116 *
117 * @param string $property_name
118 * @param string $property_value
119 * @return boolean
120 */
121 protected final function __set($property_name, $property_value)
122 {
123 if (array_key_exists($property_name, $this->properties))
124 {
125 if ($this->properties[$property_name]['is_protected'])
126 {
127 throw new Exception('Cannot set value of protected property');
128 return false;
129 }
130 else
131 {
132 $this->properties[$property_name]['value'] = $property_value;
133 }
134 }
135 else
136 {
137 throw new Exception(get_class($this) . ' property ' . $property_name . ' does not exist');
138 return false;
139 }
140
141 return true;
142 }
143
144
145
146 /**
147 * Returns the table name associated to this Model. If self::$table_name is
148 * empty, it will deduce the table name from the class name.
149 *
150 * @return string
151 */
152 public final function get_table_name()
153 {
154 $result = '';
155
156 if ($this->table_name == '')
157 {
158 $result = str_replace('_model', '', get_class($this));
159 }
160 else
161 {
162 $result = $this->table_name;
163 }
164
165 return $result;
166 }
167
168
169
170 /**
171 * Returns the primary key name associated to this Model. If
172 * self::$primary_key_name is empty, it will deduce the primary key name
173 * from the table name.
174 *
175 * @return string
176 */
177 protected final function get_primary_key_name()
178 {
179 $result = '';
180
181 if ($this->primary_key_name == '')
182 {
183 $result = $this->get_table_name() . '_id';
184 }
185 else
186 {
187 $result = $this->primary_key_name;
188 }
189
190 return $result;
191 }
192
193
194
195 /**
196 * Adds a model property by adding an element to the self::$properties array.
197 *
198 * @todo Add code to verify the parameters e.g. property_name, data_type/length.
199 * @param string $property_name
200 * @param string $data_type
201 * @param string $data_length
202 * @param string $description
203 * @param boolean $is_protected
204 * @param string $foreign_key_parent Either '' to indicate non-foreign_key, or e.g. 'user.user_id' to indicate foreign key and it's parent property.
205 * @param string $delete_action Will be used if property is a foreign_key; possible values are 'restrict', 'cascade', 'none'.
206 * @param string $update_action Will be used if property is a foreign_key; possible values are 'restrict', 'cascade', 'none'.
207 * @param boolean $is_primary_key
208 * @return boolean
209 */
210 protected final function add_property($property_name, $data_type, $data_length = '', $description = '', $is_protected = 0, $foreign_key_parent = '', $delete_action = 'restrict', $update_action = 'none', $is_primary_key = 0)
211 {
212 $this->properties[$property_name] = array(
213
214 'value' => '',
215 'data_type' => $data_type,
216 'data_length' => $data_length,
217 'description' => $description,
218 'is_protected' => $is_protected,
219 'foreign_key_parent' => $foreign_key_parent,
220 'delete_action' => $delete_action,
221 'update_action' => $update_action,
222 'is_primary_key' => $is_primary_key,
223
224 );
225
226 return true;
227 }
228
229
230
231 /**
232 * Adds an index to the model by adding an element to the self::$indexes
233 * array.
234 *
235 * @todo Add code to verify the parameters e.g. index_name/fields.
236 * @param string $index_name
237 * @param mixed $index_fields If string, it's a one column index; If array, it's a multiple column index.
238 * @param boolean $is_unique_index
239 * @return boolean
240 */
241 protected final function add_index($index_name, $index_fields, $is_unique_index = 0)
242 {
243 $this->indexes[$index_name] = array(
244
245 'fields' => $index_fields,
246 'is_unique' => $is_unique_index,
247
248 );
249
250 return true;
251 }
252
253
254
255 /**
256 * Returns an array of the parent class name and the corresponding property
257 * from the foreign_key_parent name.
258 *
259 * @param string $foreign_key_parent_name
260 * @return array
261 */
262 protected function parse_foreign_key_parent($foreign_key_parent_name)
263 {
264 $result = array();
265
266 $fk_parts = explode('.', $foreign_key_parent_name);
267 if (count($fk_parts) != 2) throw new Exception('Invalid foreign_key_parent value ' . $foreign_key_parent_name);
268
269 $result['class_name'] = $fk_parts[0];
270 $result['property_name'] = $fk_parts[1];
271
272 return $result;
273 }
274
275
276
277 /**
278 * Returns an array of the class's properties' names.
279 *
280 * @return array
281 */
282 public function get_property_names()
283 {
284 $result = array_keys($this->properties);
285 return $result;
286 }
287
288
289
290 /**
291 * Adds a condition that makes up the WHERE clause(s) when doing a load().
292 *
293 * @param string $left
294 * @param string $right
295 * @param string $operator
296 * @param boolean $is_value
297 * @return boolean
298 */
299 public function add_condition($left, $right, $operator, $is_value = true)
300 {
301 $database = database::get_instance();
302 $this->conditions[] = $left . " " . $operator . " " . ($is_value ? "'" : "") . $database->escape_string($right) . ($is_value ? "'" : "");
303 return true;
304 }
305
306
307
308 /**
309 * Automatically called before self::load(), so can be overriden to add any
310 * operations to be done before loading data.
311 *
312 * @return boolean
313 */
314 protected function preload()
315 {
316 return true;
317 }
318
319
320
321 /**
322 * Loads data from database and populates self::$properties based on
323 * self::$conditions which builds the WHERE clause. If a $results array is
324 * passed in by reference, then it will be populated with an object (of this
325 * class) for each matching record found. Elements are added at the end of
326 * the $results array, so existing elements are not affected.
327 *
328 * @param array $results
329 * @param string $group_by
330 * @param string $order_by
331 * @param integer $start_row
332 * @param integer $limit
333 * @return boolean
334 */
335 protected function load(&$results = array(), $group_by = '', $order_by = '', $start_row = 0, $limit = 1)
336 {
337 if (!is_array($results))
338 {
339 throw new Exception('$results must be an array');
340 return false;
341 }
342
343 if (!$this->preload())
344 {
345 throw new Exception('preload() on ' . get_class($this) . ' failed');
346 return false;
347 }
348
349 $database = database::get_instance();
350 $primary_key_name = $this->primary_key_name;
351
352 $sql = "SELECT ";
353
354 foreach ($this->properties as $name => $detail)
355 {
356 $sql .= "`" . $this->table_name . "`.`" . $name . "` AS `" . $this->table_name . "_" . $name . "`, ";
357 }
358
359 foreach ($this->parent_objects as $parent_object)
360 {
361 foreach ($parent_object->get_property_names() as $property_name)
362 {
363 $sql .= "`" . $parent_object->get_table_name() . "`.`" . $property_name . "` AS `" . $parent_object->get_table_name() . "_" . $property_name . "`, ";
364 }
365 }
366
367 $sql = substr($sql, 0, -2) . " ";
368 $sql .= "FROM `" . $this->table_name . "`, ";
369
370 foreach ($this->parent_objects as $parent_object)
371 {
372 $sql .= "`" . $parent_object->get_table_name() . "`, ";
373 }
374
375 $sql = substr($sql, 0, -2) . " ";
376 $sql .= "WHERE 1 ";
377
378 foreach ($this->properties as $name => $properties)
379 {
380 if (strlen($properties['foreign_key_parent']) > 0)
381 {
382 $fk_parts = $this->parse_foreign_key_parent($properties['foreign_key_parent']);
383 $tmp_object = new $fk_parts['class_name'];
384 $sql .= "AND `" . $this->table_name . "`.`" . $name . "` = `" . $tmp_object->get_table_name() . "`.`" . $fk_parts['property_name'] . "` ";
385 unset($tmp_object);
386 }
387 }
388
389 foreach ($this->conditions as $condition)
390 {
391 $sql .= "AND " . $condition . " ";
392 }
393
394 if (strlen($group_by) > 0)
395 {
396 $sql .= "GROUP BY " . $group_by . " ";
397 }
398
399 if (strlen($order_by) > 0)
400 {
401 $sql .= "ORDER BY " . $order_by . " ";
402 }
403
404 if ($limit > 0)
405 {
406 $sql .= "LIMIT " . $start_row . ", " . $limit;
407 }
408
409 $sql .= ";";
410
411 try
412 {
413 $result_id = $database->query($sql);
414 }
415 catch (Exception $e)
416 {
417 $this->synchronise_database();
418 $result_id = $database->query($sql);
419 }
420
421 while ($row = $database->fetch_object($result_id))
422 {
423 foreach ($this->properties as $property_name => $property_value)
424 {
425 $column_name = $this->table_name . '_' . $property_name;
426 $this->properties[$property_name]['value'] = $row->$column_name;
427 }
428
429 foreach ($this->parent_objects as $class_name => $parent_object)
430 {
431 $property_names = $parent_object->get_property_names();
432
433 foreach ($property_names as $property_name)
434 {
435 $column_name = $parent_object->get_table_name() . '_' . $property_name;
436
437 try
438 {
439 $this->parent_objects[$class_name]->$property_name = $row->$column_name;
440 }
441 catch (Exception $e)
442 {
443 // Cannot set a "protected" property of parent object, so just ignore it
444 }
445 }
446 }
447
448 if (is_array($results))
449 {
450 $results[] = clone $this;
451 }
452 else
453 {
454 break;
455 }
456 }
457
458 if (!$this->postload())
459 {
460 throw new Exception('postload() on ' . get_class($this) . ' failed');
461 return false;
462 }
463
464 return true;
465 }
466
467
468
469 /**
470 * Automatically called after self::load(), so can be overriden to add any
471 * operations to be done after loading data.
472 *
473 * @return boolean
474 */
475 protected function postload()
476 {
477 return true;
478 }
479
480
481
482 /**
483 * Automatically called before self::save(), so can be overriden to add any
484 * operations to be done before saving data.
485 *
486 * @return boolean
487 */
488 protected function presave()
489 {
490 return true;
491 }
492
493
494
495 /**
496 * Saves data from self::$properties values into database. If Primary Key
497 * value is not already set, a unique Primary Key is generated and a new
498 * record in the database is created.
499 *
500 * @return boolean
501 */
502 public function save()
503 {
504 if (!$this->presave())
505 {
506 throw new Exception('presave() on ' . get_class($this) . ' failed');
507 return false;
508 }
509
510 $session = session::get_instance();
511 $database = database::get_instance();
512
513 $primary_key_name = $this->primary_key_name;
514 $date_time_now = date('Y-m-d H:i:s');
515 $this->updated_date_time = $date_time_now;
516 $this->updated_by = $session->user_id;
517
518 foreach ($this->properties as $name => $detail)
519 {
520 $value = $detail['value'];
521 if ($detail['data_type'] == 'INT' && $value == '') $this->properties[$name]['value'] = '0';
522 }
523
524 if (!$this->$primary_key_name)
525 {
526 $this->properties[$primary_key_name]['value'] = $this->get_next_id();
527 $this->created_date_time = $date_time_now;
528 $this->created_by = $session->user_id == '' ? '0' : $session->user_id;
529
530 $sql = "INSERT INTO `" . $this->table_name . "` (
531 `" . implode('`, `', array_keys($this->properties)) . "`
532 ) VALUES (
533 ";
534
535 foreach ($this->properties as $name => $detail)
536 {
537 $sql .= "'" . $database->escape_string($detail['value']) . "', ";
538 }
539
540 $sql = substr($sql, 0, -2);
541 $sql .= "
542 );";
543 }
544 else
545 {
546 $sql = "UPDATE `" . $this->table_name . "`
547 SET ";
548
549 foreach ($this->properties as $name => $detail)
550 {
551 $sql .= "`" . $name . "` = '" . $database->escape_string($detail['value']) . "', ";
552 }
553
554 $sql = substr($sql, 0, -2);
555 $sql .= "
556 WHERE `" . $primary_key_name . "` = '" . $this->$primary_key_name . "';";
557 }
558
559 try
560 {
561 $database->query($sql);
562 }
563 catch (Exception $e)
564 {
565 $this->synchronise_database();
566 $database->query($sql);
567 }
568
569 if (!$this->postsave())
570 {
571 throw new Exception('postsave() on ' . get_class($this) . ' failed');
572 return false;
573 }
574
575 return true;
576 }
577
578
579
580 /**
581 * Automatically called after self::save(), so can be overriden to add any
582 * operations to be done after saving data.
583 *
584 * @return boolean
585 */
586 protected function postsave()
587 {
588 return true;
589 }
590
591
592
593 /**
594 * Automatically called before self::delete(), so can be overriden to add any
595 * operations to be done before deleting data.
596 *
597 * @return boolean
598 */
599 protected function predelete()
600 {
601 return true;
602 }
603
604
605
606 /**
607 * Deletes record in database and empties self::$properties values.
608 *
609 * @return boolean
610 */
611 public function delete()
612 {
613 if (!$this->predelete())
614 {
615 throw new Exception('predelete() on ' . get_class($this) . ' failed');
616 return false;
617 }
618
619 $primary_key_name = $this->primary_key_name;
620 $database = database::get_instance();
621
622 $sql = "DELETE FROM `" . $this->table_name . "`
623 WHERE `" . $primary_key_name . "` = '" . $database->escape_string($this->$primary_key_name) . "'";
624
625 try
626 {
627 $database->query($sql);
628 }
629 catch (Exception $e)
630 {
631 $this->synchronise_database();
632 $database->query($sql);
633 }
634
635 if (!$this->postdelete())
636 {
637 throw new Exception('postdelete() on ' . get_class($this) . ' failed');
638 return false;
639 }
640
641 return true;
642 }
643
644
645
646 /**
647 * Automatically called after self::delete(), so can be overriden to add any
648 * operations to be done after deleting data.
649 *
650 * @return boolean
651 */
652 protected function postdelete()
653 {
654 return true;
655 }
656
657
658
659 /**
660 * Generates and returns the next available primary key value.
661 *
662 * @return integer
663 */
664 protected function get_next_id()
665 {
666 $result = 0;
667
668 $database = database::get_instance();
669
670 $sql = "UPDATE `counter`
671 SET `counter` = LAST_INSERT_ID(`counter` + 1)
672 WHERE `counter_name` = '" . $this->primary_key_name . "';";
673
674 try
675 {
676 $result_id = $database->query($sql);
677
678 if ($database->affected_rows($result_id) == 0)
679 {
680 $this->synchronise_database();
681 $sql = "SELECT MAX(`" . $this->primary_key_name . "`) + 1 FROM `" . $this->table_name . "`;";
682 $current_id_value = $database->get_value($sql);
683
684 $sql = "INSERT INTO `counter` (
685 `counter_name`,
686 `counter`
687 ) VALUES (
688 '" . $database->escape_string($this->primary_key_name) . "',
689 '" . $database->escape_string($current_id_value) . "');";
690
691 $database->query($sql);
692 $result = $current_id_value;
693 }
694 else
695 {
696 $sql = "SELECT LAST_INSERT_ID();";
697 $result = $database->get_value($sql);
698 }
699 }
700 catch (Exception $e)
701 {
702 $sql = "SHOW TABLES LIKE 'counter';";
703
704 if ($database->get_value($sql) != 'counter')
705 {
706 $sql = "CREATE TABLE `counter` (
707 `counter_name` varchar(64) NOT NULL default '',
708 `counter` int(11) NOT NULL default '0',
709 PRIMARY KEY (`counter_name`)
710 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;";
711
712 $database->query($sql);
713 }
714
715 $this->synchronise_database();
716 $sql = "SELECT MAX(`" . $this->primary_key_name . "`) + 1 FROM `" . $this->table_name . "`;";
717 $current_id_value = $database->get_value($sql);
718
719 $sql = "INSERT INTO `counter` (
720 `counter_name`,
721 `counter`
722 ) VALUES (
723 '" . $database->escape_string($this->primary_key_name) . "',
724 '" . $database->escape_string($current_id_value) . "');";
725
726 $database->query($sql);
727 $result = $current_id_value;
728 }
729
730 return $result;
731 }
732
733
734
735 /**
736 * Checks that there is a database table with all the relevant columns
737 * correlating to this class. If something is out of synch, a table CREATE
738 * or ALTER is carried out.
739 *
740 * @return boolean
741 */
742 public function synchronise_database()
743 {
744 foreach ($this->parent_objects as $parent_object)
745 {
746 $parent_object->synchronise_database();
747 }
748
749 $database = database::get_instance();
750
751 //$sql = "SET FOREIGN_KEY_CHECKS = '0';";
752 //$database->query($sql);
753
754 $sql = "SHOW TABLES LIKE '" . $database->escape_string($this->table_name) . "';";
755 $table_name = $database->get_value($sql);
756
757 if ($table_name != $this->table_name)
758 {
759 $sql = "CREATE TABLE `" . $this->table_name . "` (\n";
760
761 foreach ($this->properties as $name => $detail)
762 {
763 $sql .= " `" . $name . "` " . $detail['data_type'] . ($detail['data_length'] != '' ? "(" . $detail['data_length'] . ")" : "") . " NOT NULL,\n";
764 }
765
766 $sql .= " PRIMARY KEY (`" . $this->primary_key_name . "`)\n";
767 $sql .= ") ENGINE=InnoDB DEFAULT CHARSET=latin1;";
768
769 $database->query($sql);
770 }
771 else
772 {
773 $sql = "SHOW CREATE TABLE `" . $this->table_name . "`;";
774 $result_id = $database->query($sql);
775 $row = $database->fetch_object($result_id);
776 $create_table_column = 'Create Table';
777 $create_table_sql = $row->$create_table_column;
778 $string_to_find = 'CONSTRAINT `';
779 $position_of_fk_name = 0;
780
781 while (($position_of_fk_name = strpos($create_table_sql, $string_to_find, $position_of_fk_name)) !== false)
782 {
783 $position_of_fk_name += strlen($string_to_find);
784 $position_of_backtick = strpos($create_table_sql, '`', $position_of_fk_name);
785 $fk_name = substr($create_table_sql, $position_of_fk_name, $position_of_backtick - $position_of_fk_name);
786
787 $sql = "ALTER TABLE `" . $this->table_name . "` DROP FOREIGN KEY `" . $fk_name . "`;";
788 $database->query($sql);
789 }
790
791 $sql = "SHOW INDEX FROM `" . $this->table_name . "`;";
792 $result_id = $database->query($sql);
793
794 while ($row = $database->fetch_object($result_id))
795 {
796 if ($row->Key_name != 'PRIMARY' && $row->Seq_in_index == '1')
797 {
798 $sql = "DROP INDEX `" . $row->Key_name . "` ON `" . $this->table_name . "`;";
799 $database->query($sql);
800 }
801 }
802
803 $sql = "SHOW COLUMNS FROM `" . $this->table_name . "`;";
804 $result_id = $database->query($sql);
805 $database_columns = array();
806
807 while ($row = $database->fetch_object($result_id))
808 {
809 $type = $row->Type;
810 $type_parts = explode('(', $type);
811 $data_type = $type_parts[0];
812 $data_length = count($type_parts) == 2 ? str_replace(')', '', $type_parts[1]) : '';
813
814 $database_columns[$row->Field] = array(
815
816 'data_type' => strtoupper($data_type),
817 'data_length' => $data_length,
818 'is_primary_key' => ($row->Key == 'PRI' ? 1 : 0),
819
820 );
821 }
822
823 $sql = "ALTER TABLE `" . $this->table_name . "`\n";
824
825 foreach ($this->properties as $name => $detail)
826 {
827 if (!array_key_exists($name, $database_columns))
828 {
829 $sql .= "ADD COLUMN `" . $name . "` " . $detail['data_type'] . ($detail['data_length'] != '' ? "(" . $detail['data_length'] . ")" : "") . " NOT NULL,\n";
830 }
831 elseif (strtoupper($detail['data_type']) != $database_columns[$name]['data_type'] || $detail['data_length'] != $database_columns[$name]['data_length'])
832 {
833 $sql .= "MODIFY COLUMN `" . $name . "` " . $detail['data_type'] . ($detail['data_length'] != '' ? "(" . $detail['data_length'] . ")" : "") . " NOT NULL,\n";
834 }
835 }
836
837 foreach ($database_columns as $name => $detail)
838 {
839 if (!array_key_exists($name, $this->properties))
840 {
841 $sql .= "DROP COLUMN `" . $name . "`,\n";
842 }
843 }
844
845 $sql = (substr($sql, -2) == "`\n" ? substr($sql, 0, -1) . ";" : substr($sql, 0, -2) . ";");
846 $database->query($sql);
847 }
848
849 foreach ($this->indexes as $name => $properties)
850 {
851 $sql = "CREATE " . ($properties['is_unique'] ? "UNIQUE " : "") . "INDEX `" . $name . "`
852 ON `" . $this->table_name . "`
853 (`" . (is_array($properties['fields']) ? implode('`, `', $properties['fields']) : $properties['fields']) . "`);";
854 $database->query($sql);
855 }
856
857 foreach ($this->properties as $name => $detail)
858 {
859 if ($detail['foreign_key_parent'] != '')
860 {
861 $fk_parts = $this->parse_foreign_key_parent($detail['foreign_key_parent']);
862
863 $sql = "ALTER TABLE `" . $this->table_name . "`
864 ADD CONSTRAINT `" . $fk_parts['class_name'] . "_fk`
865 FOREIGN KEY `" . $fk_parts['class_name'] . "_fk_index` (`" . $fk_parts['property_name'] . "`)
866 REFERENCES `" . $fk_parts['class_name'] . "` (`" . $fk_parts['property_name'] . "`)
867 ON DELETE ";
868
869 if ($detail['delete_action'] == 'none') $sql .= "NO_ACTION ";
870 elseif ($detail['delete_action'] == 'cascade') $sql .= "CASCADE ";
871 else $sql .= "RESTRICT ";
872
873 $sql .= "ON UPDATE ";
874
875 if ($detail['update_action'] == 'restrict') $sql .= "RESTRICT;";
876 elseif ($detail['update_action'] == 'cascade') $sql .= "CASCADE;";
877 else $sql .= "NO ACTION;";
878
879 $database->query($sql);
880 }
881 }
882
883 //$sql = "SET FOREIGN_KEY_CHECKS = '1';";
884 //$database->query($sql);
885
886 return true;
887 }
888
889
890
891 /**
892 * Loads object by a given primary key value.
893 *
894 * @param integer $primary_key_value
895 * @return boolean
896 */
897 public function load_by_primary_key($primary_key_value)
898 {
899 $this->conditions = array();
900 $this->add_condition('`' . $this->table_name . '`.`' . $this->primary_key_name . '`', $primary_key_value, '=');
901 $this->load();
902 return true;
903 }
904
905
906
907 /**
908 * Returns an array of this class's objects; one object per matching record.
909 *
910 * @param string $group_by
911 * @param string $order_by
912 * @param integer $start_row
913 * @param string $limit If <1, then will return all results
914 * @return array Array of objects
915 */
916 public function get_many($group_by = '', $order_by = '', $start_row = 0, $limit = 0)
917 {
918 $result = array();
919 $this->load($result, $group_by, $order_by, $start_row, $limit);
920
921 return $result;
922 }
923}