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: App::import('Core', array('ClassRegistry', 'Validation', 'Set', 'String'));
27: App::import('Model', 'ModelBehavior', false);
28: App::import('Model', 'ConnectionManager', false);
29:
30: if (!class_exists('Overloadable')) {
31: require LIBS . 'overloadable.php';
32: }
33:
34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45:
46: class Model extends Overloadable {
47:
48: 49: 50: 51: 52: 53: 54:
55: var $useDbConfig = 'default';
56:
57: 58: 59: 60: 61: 62: 63:
64: var $useTable = null;
65:
66: 67: 68: 69: 70: 71: 72:
73: var $displayField = null;
74:
75: 76: 77: 78: 79: 80: 81:
82: var $id = false;
83:
84: 85: 86: 87: 88: 89: 90:
91: var $data = array();
92:
93: 94: 95: 96: 97: 98:
99: var $table = false;
100:
101: 102: 103: 104: 105: 106: 107:
108: var $primaryKey = null;
109:
110: 111: 112: 113: 114: 115: 116:
117: var $_schema = null;
118:
119: 120: 121: 122: 123: 124: 125: 126: 127:
128: var $validate = array();
129:
130: 131: 132: 133: 134: 135: 136:
137: var $validationErrors = array();
138:
139: 140: 141: 142: 143: 144: 145:
146: var $tablePrefix = null;
147:
148: 149: 150: 151: 152: 153: 154:
155: var $name = null;
156:
157: 158: 159: 160: 161: 162:
163: var $alias = null;
164:
165: 166: 167: 168: 169: 170:
171: var $tableToModel = array();
172:
173: 174: 175: 176: 177: 178:
179: var $logTransactions = false;
180:
181: 182: 183: 184: 185: 186: 187: 188:
189: var $cacheQueries = false;
190:
191: 192: 193: 194: 195: 196: 197:
198: var $belongsTo = array();
199:
200: 201: 202: 203: 204: 205: 206:
207: var $hasOne = array();
208:
209: 210: 211: 212: 213: 214: 215:
216: var $hasMany = array();
217:
218: 219: 220: 221: 222: 223: 224:
225: var $hasAndBelongsToMany = array();
226:
227: 228: 229: 230: 231: 232: 233: 234: 235: 236:
237: var $actsAs = null;
238:
239: 240: 241: 242: 243: 244:
245: var $Behaviors = null;
246:
247: 248: 249: 250: 251: 252:
253: var $whitelist = array();
254:
255: 256: 257: 258: 259: 260:
261: var $cacheSources = true;
262:
263: 264: 265: 266: 267: 268:
269: var $findQueryType = null;
270:
271: 272: 273: 274: 275: 276: 277: 278:
279: var $recursive = 1;
280:
281: 282: 283: 284: 285: 286: 287: 288: 289: 290:
291: var $order = null;
292:
293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304:
305: var $virtualFields = array();
306:
307: 308: 309: 310: 311: 312:
313: var $__associationKeys = array(
314: 'belongsTo' => array('className', 'foreignKey', 'conditions', 'fields', 'order', 'counterCache'),
315: 'hasOne' => array('className', 'foreignKey','conditions', 'fields','order', 'dependent'),
316: 'hasMany' => array('className', 'foreignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'dependent', 'exclusive', 'finderQuery', 'counterQuery'),
317: 'hasAndBelongsToMany' => array('className', 'joinTable', 'with', 'foreignKey', 'associationForeignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'unique', 'finderQuery', 'deleteQuery', 'insertQuery')
318: );
319:
320: 321: 322: 323: 324: 325:
326: var $__associations = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
327:
328: 329: 330: 331: 332: 333:
334: var $__backAssociation = array();
335:
336: 337: 338: 339: 340: 341:
342: var $__insertID = null;
343:
344: 345: 346: 347: 348: 349:
350: var $__numRows = null;
351:
352: 353: 354: 355: 356: 357:
358: var $__affectedRows = null;
359:
360: 361: 362: 363: 364: 365: 366:
367: var $__safeUpdateMode = false;
368:
369: 370: 371: 372: 373: 374:
375: var $_findMethods = array(
376: 'all' => true, 'first' => true, 'count' => true,
377: 'neighbors' => true, 'list' => true, 'threaded' => true
378: );
379:
380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411:
412: function __construct($id = false, $table = null, $ds = null) {
413: parent::__construct();
414:
415: if (is_array($id)) {
416: extract(array_merge(
417: array(
418: 'id' => $this->id, 'table' => $this->useTable, 'ds' => $this->useDbConfig,
419: 'name' => $this->name, 'alias' => $this->alias
420: ),
421: $id
422: ));
423: }
424:
425: if ($this->name === null) {
426: $this->name = (isset($name) ? $name : get_class($this));
427: }
428:
429: if ($this->alias === null) {
430: $this->alias = (isset($alias) ? $alias : $this->name);
431: }
432:
433: if ($this->primaryKey === null) {
434: $this->primaryKey = 'id';
435: }
436:
437: ClassRegistry::addObject($this->alias, $this);
438:
439: $this->id = $id;
440: unset($id);
441:
442: if ($table === false) {
443: $this->useTable = false;
444: } elseif ($table) {
445: $this->useTable = $table;
446: }
447:
448: if ($ds !== null) {
449: $this->useDbConfig = $ds;
450: }
451:
452: if (is_subclass_of($this, 'AppModel')) {
453: $appVars = get_class_vars('AppModel');
454: $merge = array('_findMethods');
455:
456: if ($this->actsAs !== null || $this->actsAs !== false) {
457: $merge[] = 'actsAs';
458: }
459: $parentClass = get_parent_class($this);
460: if (strtolower($parentClass) !== 'appmodel') {
461: $parentVars = get_class_vars($parentClass);
462: foreach ($merge as $var) {
463: if (isset($parentVars[$var]) && !empty($parentVars[$var])) {
464: $appVars[$var] = Set::merge($appVars[$var], $parentVars[$var]);
465: }
466: }
467: }
468:
469: foreach ($merge as $var) {
470: if (isset($appVars[$var]) && !empty($appVars[$var]) && is_array($this->{$var})) {
471: $this->{$var} = Set::merge($appVars[$var], $this->{$var});
472: }
473: }
474: }
475: $this->Behaviors = new BehaviorCollection();
476:
477: if ($this->useTable !== false) {
478: $this->setDataSource($ds);
479:
480: if ($this->useTable === null) {
481: $this->useTable = Inflector::tableize($this->name);
482: }
483: $this->setSource($this->useTable);
484:
485: if ($this->displayField == null) {
486: $this->displayField = $this->hasField(array('title', 'name', $this->primaryKey));
487: }
488: } elseif ($this->table === false) {
489: $this->table = Inflector::tableize($this->name);
490: }
491: $this->__createLinks();
492: $this->Behaviors->init($this->alias, $this->actsAs);
493: }
494:
495: 496: 497: 498: 499: 500: 501: 502: 503:
504: function call__($method, $params) {
505: $result = $this->Behaviors->dispatchMethod($this, $method, $params);
506:
507: if ($result !== array('unhandled')) {
508: return $result;
509: }
510: $db =& ConnectionManager::getDataSource($this->useDbConfig);
511: $return = $db->query($method, $params, $this);
512:
513: if (!PHP5) {
514: $this->resetAssociations();
515: }
516: return $return;
517: }
518:
519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538:
539: function bindModel($params, $reset = true) {
540: foreach ($params as $assoc => $model) {
541: if ($reset === true && !isset($this->__backAssociation[$assoc])) {
542: $this->__backAssociation[$assoc] = $this->{$assoc};
543: }
544: foreach ($model as $key => $value) {
545: $assocName = $key;
546:
547: if (is_numeric($key)) {
548: $assocName = $value;
549: $value = array();
550: }
551: $modelName = $assocName;
552: $this->{$assoc}[$assocName] = $value;
553:
554: if ($reset === false && isset($this->__backAssociation[$assoc])) {
555: $this->__backAssociation[$assoc][$assocName] = $value;
556: }
557: }
558: }
559: $this->__createLinks();
560: return true;
561: }
562:
563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581:
582: function unbindModel($params, $reset = true) {
583: foreach ($params as $assoc => $models) {
584: if ($reset === true && !isset($this->__backAssociation[$assoc])) {
585: $this->__backAssociation[$assoc] = $this->{$assoc};
586: }
587: foreach ($models as $model) {
588: if ($reset === false && isset($this->__backAssociation[$assoc][$model])) {
589: unset($this->__backAssociation[$assoc][$model]);
590: }
591: unset($this->{$assoc}[$model]);
592: }
593: }
594: return true;
595: }
596:
597: 598: 599: 600: 601: 602:
603: function __createLinks() {
604: foreach ($this->__associations as $type) {
605: if (!is_array($this->{$type})) {
606: $this->{$type} = explode(',', $this->{$type});
607:
608: foreach ($this->{$type} as $i => $className) {
609: $className = trim($className);
610: unset ($this->{$type}[$i]);
611: $this->{$type}[$className] = array();
612: }
613: }
614:
615: if (!empty($this->{$type})) {
616: foreach ($this->{$type} as $assoc => $value) {
617: $plugin = null;
618:
619: if (is_numeric($assoc)) {
620: unset ($this->{$type}[$assoc]);
621: $assoc = $value;
622: $value = array();
623: $this->{$type}[$assoc] = $value;
624:
625: if (strpos($assoc, '.') !== false) {
626: $value = $this->{$type}[$assoc];
627: unset($this->{$type}[$assoc]);
628: list($plugin, $assoc) = pluginSplit($assoc, true);
629: $this->{$type}[$assoc] = $value;
630: }
631: }
632: $className = $assoc;
633:
634: if (!empty($value['className'])) {
635: list($plugin, $className) = pluginSplit($value['className'], true);
636: $this->{$type}[$assoc]['className'] = $className;
637: }
638: $this->__constructLinkedModel($assoc, $plugin . $className);
639: }
640: $this->__generateAssociation($type);
641: }
642: }
643: }
644:
645: 646: 647: 648: 649: 650: 651: 652: 653: 654: 655: 656: 657: 658:
659: function __constructLinkedModel($assoc, $className = null) {
660: if (empty($className)) {
661: $className = $assoc;
662: }
663:
664: if (!isset($this->{$assoc}) || $this->{$assoc}->name !== $className) {
665: $model = array('class' => $className, 'alias' => $assoc);
666: if (PHP5) {
667: $this->{$assoc} = ClassRegistry::init($model);
668: } else {
669: $this->{$assoc} =& ClassRegistry::init($model);
670: }
671: if (strpos($className, '.') !== false) {
672: ClassRegistry::addObject($className, $this->{$assoc});
673: }
674: if ($assoc) {
675: $this->tableToModel[$this->{$assoc}->table] = $assoc;
676: }
677: }
678: }
679:
680: 681: 682: 683: 684: 685: 686:
687: function __generateAssociation($type) {
688: foreach ($this->{$type} as $assocKey => $assocData) {
689: $class = $assocKey;
690: $dynamicWith = false;
691:
692: foreach ($this->__associationKeys[$type] as $key) {
693:
694: if (!isset($this->{$type}[$assocKey][$key]) || $this->{$type}[$assocKey][$key] === null) {
695: $data = '';
696:
697: switch ($key) {
698: case 'fields':
699: $data = '';
700: break;
701:
702: case 'foreignKey':
703: $data = (($type == 'belongsTo') ? Inflector::underscore($assocKey) : Inflector::singularize($this->table)) . '_id';
704: break;
705:
706: case 'associationForeignKey':
707: $data = Inflector::singularize($this->{$class}->table) . '_id';
708: break;
709:
710: case 'with':
711: $data = Inflector::camelize(Inflector::singularize($this->{$type}[$assocKey]['joinTable']));
712: $dynamicWith = true;
713: break;
714:
715: case 'joinTable':
716: $tables = array($this->table, $this->{$class}->table);
717: sort ($tables);
718: $data = $tables[0] . '_' . $tables[1];
719: break;
720:
721: case 'className':
722: $data = $class;
723: break;
724:
725: case 'unique':
726: $data = true;
727: break;
728: }
729: $this->{$type}[$assocKey][$key] = $data;
730: }
731: }
732:
733: if (!empty($this->{$type}[$assocKey]['with'])) {
734: $joinClass = $this->{$type}[$assocKey]['with'];
735: if (is_array($joinClass)) {
736: $joinClass = key($joinClass);
737: }
738:
739: $plugin = null;
740: if (strpos($joinClass, '.') !== false) {
741: list($plugin, $joinClass) = explode('.', $joinClass);
742: $plugin .= '.';
743: $this->{$type}[$assocKey]['with'] = $joinClass;
744: }
745:
746: if (!ClassRegistry::isKeySet($joinClass) && $dynamicWith === true) {
747: $this->{$joinClass} = new AppModel(array(
748: 'name' => $joinClass,
749: 'table' => $this->{$type}[$assocKey]['joinTable'],
750: 'ds' => $this->useDbConfig
751: ));
752: } else {
753: $this->__constructLinkedModel($joinClass, $plugin . $joinClass);
754: $this->{$type}[$assocKey]['joinTable'] = $this->{$joinClass}->table;
755: }
756:
757: if (count($this->{$joinClass}->schema()) <= 2 && $this->{$joinClass}->primaryKey !== false) {
758: $this->{$joinClass}->primaryKey = $this->{$type}[$assocKey]['foreignKey'];
759: }
760: }
761: }
762: }
763:
764: 765: 766: 767: 768: 769: 770:
771: function setSource($tableName) {
772: $this->setDataSource($this->useDbConfig);
773: $db =& ConnectionManager::getDataSource($this->useDbConfig);
774: $db->cacheSources = ($this->cacheSources && $db->cacheSources);
775:
776: if ($db->isInterfaceSupported('listSources')) {
777: $sources = $db->listSources();
778: if (is_array($sources) && !in_array(strtolower($this->tablePrefix . $tableName), array_map('strtolower', $sources))) {
779: return $this->cakeError('missingTable', array(array(
780: 'className' => $this->alias,
781: 'table' => $this->tablePrefix . $tableName,
782: 'code' => 500
783: )));
784: }
785: $this->_schema = null;
786: }
787: $this->table = $this->useTable = $tableName;
788: $this->tableToModel[$this->table] = $this->alias;
789: $this->schema();
790: }
791:
792: 793: 794: 795: 796: 797: 798: 799: 800: 801: 802: 803: 804: 805: 806: 807:
808: function set($one, $two = null) {
809: if (!$one) {
810: return;
811: }
812: if (is_object($one)) {
813: $one = Set::reverse($one);
814: }
815:
816: if (is_array($one)) {
817: $data = $one;
818: if (empty($one[$this->alias])) {
819: if ($this->getAssociated(key($one)) === null) {
820: $data = array($this->alias => $one);
821: }
822: }
823: } else {
824: $data = array($this->alias => array($one => $two));
825: }
826:
827: foreach ($data as $modelName => $fieldSet) {
828: if (is_array($fieldSet)) {
829:
830: foreach ($fieldSet as $fieldName => $fieldValue) {
831: if (isset($this->validationErrors[$fieldName])) {
832: unset ($this->validationErrors[$fieldName]);
833: }
834:
835: if ($modelName === $this->alias) {
836: if ($fieldName === $this->primaryKey) {
837: $this->id = $fieldValue;
838: }
839: }
840: if (is_array($fieldValue) || is_object($fieldValue)) {
841: $fieldValue = $this->deconstruct($fieldName, $fieldValue);
842: }
843: $this->data[$modelName][$fieldName] = $fieldValue;
844: }
845: }
846: }
847: return $data;
848: }
849:
850: 851: 852: 853: 854: 855: 856: 857:
858: function deconstruct($field, $data) {
859: if (!is_array($data)) {
860: return $data;
861: }
862:
863: $copy = $data;
864: $type = $this->getColumnType($field);
865:
866: if (in_array($type, array('datetime', 'timestamp', 'date', 'time'))) {
867: $useNewDate = (isset($data['year']) || isset($data['month']) ||
868: isset($data['day']) || isset($data['hour']) || isset($data['minute']));
869:
870: $dateFields = array('Y' => 'year', 'm' => 'month', 'd' => 'day', 'H' => 'hour', 'i' => 'min', 's' => 'sec');
871: $timeFields = array('H' => 'hour', 'i' => 'min', 's' => 'sec');
872:
873: $db =& ConnectionManager::getDataSource($this->useDbConfig);
874: $format = $db->columns[$type]['format'];
875: $date = array();
876:
877: if (isset($data['hour']) && isset($data['meridian']) && $data['hour'] != 12 && 'pm' == $data['meridian']) {
878: $data['hour'] = $data['hour'] + 12;
879: }
880: if (isset($data['hour']) && isset($data['meridian']) && $data['hour'] == 12 && 'am' == $data['meridian']) {
881: $data['hour'] = '00';
882: }
883: if ($type == 'time') {
884: foreach ($timeFields as $key => $val) {
885: if (!isset($data[$val]) || $data[$val] === '0' || $data[$val] === '00') {
886: $data[$val] = '00';
887: } elseif ($data[$val] === '') {
888: $data[$val] = '';
889: } else {
890: $data[$val] = sprintf('%02d', $data[$val]);
891: }
892: if (!empty($data[$val])) {
893: $date[$key] = $data[$val];
894: } else {
895: return null;
896: }
897: }
898: }
899:
900: if ($type == 'datetime' || $type == 'timestamp' || $type == 'date') {
901: foreach ($dateFields as $key => $val) {
902: if ($val == 'hour' || $val == 'min' || $val == 'sec') {
903: if (!isset($data[$val]) || $data[$val] === '0' || $data[$val] === '00') {
904: $data[$val] = '00';
905: } else {
906: $data[$val] = sprintf('%02d', $data[$val]);
907: }
908: }
909: if (!isset($data[$val]) || isset($data[$val]) && (empty($data[$val]) || $data[$val][0] === '-')) {
910: return null;
911: }
912: if (isset($data[$val]) && !empty($data[$val])) {
913: $date[$key] = $data[$val];
914: }
915: }
916: }
917: $date = str_replace(array_keys($date), array_values($date), $format);
918: if ($useNewDate && !empty($date)) {
919: return $date;
920: }
921: }
922: return $data;
923: }
924:
925: 926: 927: 928: 929: 930: 931: 932:
933: function schema($field = false) {
934: if (!is_array($this->_schema) || $field === true) {
935: $db =& ConnectionManager::getDataSource($this->useDbConfig);
936: $db->cacheSources = ($this->cacheSources && $db->cacheSources);
937: if ($db->isInterfaceSupported('describe') && $this->useTable !== false) {
938: $this->_schema = $db->describe($this, $field);
939: } elseif ($this->useTable === false) {
940: $this->_schema = array();
941: }
942: }
943: if (is_string($field)) {
944: if (isset($this->_schema[$field])) {
945: return $this->_schema[$field];
946: } else {
947: return null;
948: }
949: }
950: return $this->_schema;
951: }
952:
953: 954: 955: 956: 957: 958:
959: function getColumnTypes() {
960: $columns = $this->schema();
961: if (empty($columns)) {
962: trigger_error(__('(Model::getColumnTypes) Unable to build model field data. If you are using a model without a database table, try implementing schema()', true), E_USER_WARNING);
963: }
964: $cols = array();
965: foreach ($columns as $field => $values) {
966: $cols[$field] = $values['type'];
967: }
968: return $cols;
969: }
970:
971: 972: 973: 974: 975: 976: 977:
978: function getColumnType($column) {
979: $db =& ConnectionManager::getDataSource($this->useDbConfig);
980: $cols = $this->schema();
981: $model = null;
982:
983: $column = str_replace(array($db->startQuote, $db->endQuote), '', $column);
984:
985: if (strpos($column, '.')) {
986: list($model, $column) = explode('.', $column);
987: }
988: if ($model != $this->alias && isset($this->{$model})) {
989: return $this->{$model}->getColumnType($column);
990: }
991: if (isset($cols[$column]) && isset($cols[$column]['type'])) {
992: return $cols[$column]['type'];
993: }
994: return null;
995: }
996:
997: 998: 999: 1000: 1001: 1002: 1003: 1004: 1005: 1006:
1007: function hasField($name, $checkVirtual = false) {
1008: if (is_array($name)) {
1009: foreach ($name as $n) {
1010: if ($this->hasField($n, $checkVirtual)) {
1011: return $n;
1012: }
1013: }
1014: return false;
1015: }
1016:
1017: if ($checkVirtual && !empty($this->virtualFields)) {
1018: if ($this->isVirtualField($name)) {
1019: return true;
1020: }
1021: }
1022:
1023: if (empty($this->_schema)) {
1024: $this->schema();
1025: }
1026:
1027: if ($this->_schema != null) {
1028: return isset($this->_schema[$name]);
1029: }
1030: return false;
1031: }
1032:
1033: 1034: 1035: 1036: 1037: 1038: 1039:
1040: function isVirtualField($field) {
1041: if (empty($this->virtualFields) || !is_string($field)) {
1042: return false;
1043: }
1044: if (isset($this->virtualFields[$field])) {
1045: return true;
1046: }
1047: if (strpos($field, '.') !== false) {
1048: list($model, $field) = explode('.', $field);
1049: if ($model == $this->alias && isset($this->virtualFields[$field])) {
1050: return true;
1051: }
1052: }
1053: return false;
1054: }
1055:
1056: 1057: 1058: 1059: 1060: 1061: 1062: 1063: 1064:
1065: function getVirtualField($field = null) {
1066: if ($field == null) {
1067: return empty($this->virtualFields) ? false : $this->virtualFields;
1068: }
1069: if ($this->isVirtualField($field)) {
1070: if (strpos($field, '.') !== false) {
1071: list($model, $field) = explode('.', $field);
1072: }
1073: return $this->virtualFields[$field];
1074: }
1075: return false;
1076: }
1077:
1078: 1079: 1080: 1081: 1082: 1083: 1084: 1085: 1086: 1087: 1088: 1089:
1090: function create($data = array(), $filterKey = false) {
1091: $defaults = array();
1092: $this->id = false;
1093: $this->data = array();
1094: $this->validationErrors = array();
1095:
1096: if ($data !== null && $data !== false) {
1097: foreach ($this->schema() as $field => $properties) {
1098: if ($this->primaryKey !== $field && isset($properties['default']) && $properties['default'] !== '') {
1099: $defaults[$field] = $properties['default'];
1100: }
1101: }
1102: $this->set($defaults);
1103: $this->set($data);
1104: }
1105: if ($filterKey) {
1106: $this->set($this->primaryKey, false);
1107: }
1108: return $this->data;
1109: }
1110:
1111: 1112: 1113: 1114: 1115: 1116: 1117: 1118: 1119: 1120:
1121: function read($fields = null, $id = null) {
1122: $this->validationErrors = array();
1123:
1124: if ($id != null) {
1125: $this->id = $id;
1126: }
1127:
1128: $id = $this->id;
1129:
1130: if (is_array($this->id)) {
1131: $id = $this->id[0];
1132: }
1133:
1134: if ($id !== null && $id !== false) {
1135: $this->data = $this->find('first', array(
1136: 'conditions' => array($this->alias . '.' . $this->primaryKey => $id),
1137: 'fields' => $fields
1138: ));
1139: return $this->data;
1140: } else {
1141: return false;
1142: }
1143: }
1144:
1145: 1146: 1147: 1148: 1149: 1150: 1151: 1152: 1153: 1154: 1155:
1156: function field($name, $conditions = null, $order = null) {
1157: if ($conditions === null && $this->id !== false) {
1158: $conditions = array($this->alias . '.' . $this->primaryKey => $this->id);
1159: }
1160: if ($this->recursive >= 1) {
1161: $recursive = -1;
1162: } else {
1163: $recursive = $this->recursive;
1164: }
1165: $fields = $name;
1166: if ($data = $this->find('first', compact('conditions', 'fields', 'order', 'recursive'))) {
1167: if (strpos($name, '.') === false) {
1168: if (isset($data[$this->alias][$name])) {
1169: return $data[$this->alias][$name];
1170: }
1171: } else {
1172: $name = explode('.', $name);
1173: if (isset($data[$name[0]][$name[1]])) {
1174: return $data[$name[0]][$name[1]];
1175: }
1176: }
1177: if (isset($data[0]) && count($data[0]) > 0) {
1178: return array_shift($data[0]);
1179: }
1180: } else {
1181: return false;
1182: }
1183: }
1184:
1185: 1186: 1187: 1188: 1189: 1190: 1191: 1192: 1193: 1194: 1195: 1196:
1197: function saveField($name, $value, $validate = false) {
1198: $id = $this->id;
1199: $this->create(false);
1200:
1201: if (is_array($validate)) {
1202: $options = array_merge(array('validate' => false, 'fieldList' => array($name)), $validate);
1203: } else {
1204: $options = array('validate' => $validate, 'fieldList' => array($name));
1205: }
1206: return $this->save(array($this->alias => array($this->primaryKey => $id, $name => $value)), $options);
1207: }
1208:
1209: 1210: 1211: 1212: 1213: 1214: 1215: 1216: 1217: 1218: 1219: 1220: 1221:
1222: function save($data = null, $validate = true, $fieldList = array()) {
1223: $defaults = array('validate' => true, 'fieldList' => array(), 'callbacks' => true);
1224: $_whitelist = $this->whitelist;
1225: $fields = array();
1226:
1227: if (!is_array($validate)) {
1228: $options = array_merge($defaults, compact('validate', 'fieldList', 'callbacks'));
1229: } else {
1230: $options = array_merge($defaults, $validate);
1231: }
1232:
1233: if (!empty($options['fieldList'])) {
1234: $this->whitelist = $options['fieldList'];
1235: } elseif ($options['fieldList'] === null) {
1236: $this->whitelist = array();
1237: }
1238: $this->set($data);
1239:
1240: if (empty($this->data) && !$this->hasField(array('created', 'updated', 'modified'))) {
1241: return false;
1242: }
1243:
1244: foreach (array('created', 'updated', 'modified') as $field) {
1245: $keyPresentAndEmpty = (
1246: isset($this->data[$this->alias]) &&
1247: array_key_exists($field, $this->data[$this->alias]) &&
1248: $this->data[$this->alias][$field] === null
1249: );
1250: if ($keyPresentAndEmpty) {
1251: unset($this->data[$this->alias][$field]);
1252: }
1253: }
1254:
1255: $exists = $this->exists();
1256: $dateFields = array('modified', 'updated');
1257:
1258: if (!$exists) {
1259: $dateFields[] = 'created';
1260: }
1261: if (isset($this->data[$this->alias])) {
1262: $fields = array_keys($this->data[$this->alias]);
1263: }
1264: if ($options['validate'] && !$this->validates($options)) {
1265: $this->whitelist = $_whitelist;
1266: return false;
1267: }
1268:
1269: $db =& ConnectionManager::getDataSource($this->useDbConfig);
1270:
1271: foreach ($dateFields as $updateCol) {
1272: if ($this->hasField($updateCol) && !in_array($updateCol, $fields)) {
1273: $default = array('formatter' => 'date');
1274: $colType = array_merge($default, $db->columns[$this->getColumnType($updateCol)]);
1275: if (!array_key_exists('format', $colType)) {
1276: $time = strtotime('now');
1277: } else {
1278: $time = $colType['formatter']($colType['format']);
1279: }
1280: if (!empty($this->whitelist)) {
1281: $this->whitelist[] = $updateCol;
1282: }
1283: $this->set($updateCol, $time);
1284: }
1285: }
1286:
1287: if ($options['callbacks'] === true || $options['callbacks'] === 'before') {
1288: $result = $this->Behaviors->trigger($this, 'beforeSave', array($options), array(
1289: 'break' => true, 'breakOn' => false
1290: ));
1291: if (!$result || !$this->beforeSave($options)) {
1292: $this->whitelist = $_whitelist;
1293: return false;
1294: }
1295: }
1296:
1297: if (empty($this->data[$this->alias][$this->primaryKey])) {
1298: unset($this->data[$this->alias][$this->primaryKey]);
1299: }
1300: $fields = $values = array();
1301:
1302: foreach ($this->data as $n => $v) {
1303: if (isset($this->hasAndBelongsToMany[$n])) {
1304: if (isset($v[$n])) {
1305: $v = $v[$n];
1306: }
1307: $joined[$n] = $v;
1308: } else {
1309: if ($n === $this->alias) {
1310: foreach (array('created', 'updated', 'modified') as $field) {
1311: if (array_key_exists($field, $v) && empty($v[$field])) {
1312: unset($v[$field]);
1313: }
1314: }
1315:
1316: foreach ($v as $x => $y) {
1317: if ($this->hasField($x) && (empty($this->whitelist) || in_array($x, $this->whitelist))) {
1318: list($fields[], $values[]) = array($x, $y);
1319: }
1320: }
1321: }
1322: }
1323: }
1324: $count = count($fields);
1325:
1326: if (!$exists && $count > 0) {
1327: $this->id = false;
1328: }
1329: $success = true;
1330: $created = false;
1331:
1332: if ($count > 0) {
1333: $cache = $this->_prepareUpdateFields(array_combine($fields, $values));
1334:
1335: if (!empty($this->id)) {
1336: $this->__safeUpdateMode = true;
1337: $success = (bool)$db->update($this, $fields, $values);
1338: $this->__safeUpdateMode = false;
1339: } else {
1340: $fInfo = $this->_schema[$this->primaryKey];
1341: $isUUID = ($fInfo['length'] == 36 &&
1342: ($fInfo['type'] === 'string' || $fInfo['type'] === 'binary')
1343: );
1344: if (empty($this->data[$this->alias][$this->primaryKey]) && $isUUID) {
1345: if (array_key_exists($this->primaryKey, $this->data[$this->alias])) {
1346: $j = array_search($this->primaryKey, $fields);
1347: $values[$j] = String::uuid();
1348: } else {
1349: list($fields[], $values[]) = array($this->primaryKey, String::uuid());
1350: }
1351: }
1352:
1353: if (!$db->create($this, $fields, $values)) {
1354: $success = $created = false;
1355: } else {
1356: $created = true;
1357: }
1358: }
1359:
1360: if ($success && !empty($this->belongsTo)) {
1361: $this->updateCounterCache($cache, $created);
1362: }
1363: }
1364:
1365: if (!empty($joined) && $success === true) {
1366: $this->__saveMulti($joined, $this->id, $db);
1367: }
1368:
1369: if ($success && $count > 0) {
1370: if (!empty($this->data)) {
1371: $success = $this->data;
1372: }
1373: if ($options['callbacks'] === true || $options['callbacks'] === 'after') {
1374: $this->Behaviors->trigger($this, 'afterSave', array($created, $options));
1375: $this->afterSave($created);
1376: }
1377: if (!empty($this->data)) {
1378: $success = Set::merge($success, $this->data);
1379: }
1380: $this->data = false;
1381: $this->_clearCache();
1382: $this->validationErrors = array();
1383: }
1384: $this->whitelist = $_whitelist;
1385: return $success;
1386: }
1387:
1388: 1389: 1390: 1391: 1392: 1393: 1394:
1395: function __saveMulti($joined, $id, &$db) {
1396: foreach ($joined as $assoc => $data) {
1397:
1398: if (isset($this->hasAndBelongsToMany[$assoc])) {
1399: list($join) = $this->joinModel($this->hasAndBelongsToMany[$assoc]['with']);
1400:
1401: $isUUID = !empty($this->{$join}->primaryKey) && (
1402: $this->{$join}->_schema[$this->{$join}->primaryKey]['length'] == 36 && (
1403: $this->{$join}->_schema[$this->{$join}->primaryKey]['type'] === 'string' ||
1404: $this->{$join}->_schema[$this->{$join}->primaryKey]['type'] === 'binary'
1405: )
1406: );
1407:
1408: $newData = $newValues = array();
1409: $primaryAdded = false;
1410:
1411: $fields = array(
1412: $db->name($this->hasAndBelongsToMany[$assoc]['foreignKey']),
1413: $db->name($this->hasAndBelongsToMany[$assoc]['associationForeignKey'])
1414: );
1415:
1416: $idField = $db->name($this->{$join}->primaryKey);
1417: if ($isUUID && !in_array($idField, $fields)) {
1418: $fields[] = $idField;
1419: $primaryAdded = true;
1420: }
1421:
1422: foreach ((array)$data as $row) {
1423: if ((is_string($row) && (strlen($row) == 36 || strlen($row) == 16)) || is_numeric($row)) {
1424: $values = array(
1425: $db->value($id, $this->getColumnType($this->primaryKey)),
1426: $db->value($row)
1427: );
1428: if ($isUUID && $primaryAdded) {
1429: $values[] = $db->value(String::uuid());
1430: }
1431: $values = implode(',', $values);
1432: $newValues[] = "({$values})";
1433: unset($values);
1434: } elseif (isset($row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
1435: $newData[] = $row;
1436: } elseif (isset($row[$join]) && isset($row[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
1437: $newData[] = $row[$join];
1438: }
1439: }
1440:
1441: if ($this->hasAndBelongsToMany[$assoc]['unique']) {
1442: $conditions = array(
1443: $join . '.' . $this->hasAndBelongsToMany[$assoc]['foreignKey'] => $id
1444: );
1445: if (!empty($this->hasAndBelongsToMany[$assoc]['conditions'])) {
1446: $conditions = array_merge($conditions, (array)$this->hasAndBelongsToMany[$assoc]['conditions']);
1447: }
1448: $links = $this->{$join}->find('all', array(
1449: 'conditions' => $conditions,
1450: 'recursive' => empty($this->hasAndBelongsToMany[$assoc]['conditions']) ? -1 : 0,
1451: 'fields' => $this->hasAndBelongsToMany[$assoc]['associationForeignKey']
1452: ));
1453:
1454: $associationForeignKey = "{$join}." . $this->hasAndBelongsToMany[$assoc]['associationForeignKey'];
1455: $oldLinks = Set::extract($links, "{n}.{$associationForeignKey}");
1456: if (!empty($oldLinks)) {
1457: $conditions[$associationForeignKey] = $oldLinks;
1458: $db->delete($this->{$join}, $conditions);
1459: }
1460: }
1461:
1462: if (!empty($newData)) {
1463: foreach ($newData as $data) {
1464: $data[$this->hasAndBelongsToMany[$assoc]['foreignKey']] = $id;
1465: $this->{$join}->create($data);
1466: $this->{$join}->save();
1467: }
1468: }
1469:
1470: if (!empty($newValues)) {
1471: $fields = implode(',', $fields);
1472: $db->insertMulti($this->{$join}, $fields, $newValues);
1473: }
1474: }
1475: }
1476: }
1477:
1478: 1479: 1480: 1481: 1482: 1483: 1484: 1485: 1486:
1487: function updateCounterCache($keys = array(), $created = false) {
1488: $keys = empty($keys) ? $this->data[$this->alias] : $keys;
1489: $keys['old'] = isset($keys['old']) ? $keys['old'] : array();
1490:
1491: foreach ($this->belongsTo as $parent => $assoc) {
1492: $foreignKey = $assoc['foreignKey'];
1493: $fkQuoted = $this->escapeField($assoc['foreignKey']);
1494:
1495: if (!empty($assoc['counterCache'])) {
1496: if ($assoc['counterCache'] === true) {
1497: $assoc['counterCache'] = Inflector::underscore($this->alias) . '_count';
1498: }
1499: if (!$this->{$parent}->hasField($assoc['counterCache'])) {
1500: continue;
1501: }
1502:
1503: if (!array_key_exists($foreignKey, $keys)) {
1504: $keys[$foreignKey] = $this->field($foreignKey);
1505: }
1506: $recursive = (isset($assoc['counterScope']) ? 1 : -1);
1507: $conditions = ($recursive == 1) ? (array)$assoc['counterScope'] : array();
1508:
1509: if (isset($keys['old'][$foreignKey])) {
1510: if ($keys['old'][$foreignKey] != $keys[$foreignKey]) {
1511: $conditions[$fkQuoted] = $keys['old'][$foreignKey];
1512: $count = intval($this->find('count', compact('conditions', 'recursive')));
1513:
1514: $this->{$parent}->updateAll(
1515: array($assoc['counterCache'] => $count),
1516: array($this->{$parent}->escapeField() => $keys['old'][$foreignKey])
1517: );
1518: }
1519: }
1520: $conditions[$fkQuoted] = $keys[$foreignKey];
1521:
1522: if ($recursive == 1) {
1523: $conditions = array_merge($conditions, (array)$assoc['counterScope']);
1524: }
1525: $count = intval($this->find('count', compact('conditions', 'recursive')));
1526:
1527: $this->{$parent}->updateAll(
1528: array($assoc['counterCache'] => $count),
1529: array($this->{$parent}->escapeField() => $keys[$foreignKey])
1530: );
1531: }
1532: }
1533: }
1534:
1535: 1536: 1537: 1538: 1539: 1540: 1541: 1542:
1543: function _prepareUpdateFields($data) {
1544: $foreignKeys = array();
1545: foreach ($this->belongsTo as $assoc => $info) {
1546: if ($info['counterCache']) {
1547: $foreignKeys[$assoc] = $info['foreignKey'];
1548: }
1549: }
1550: $included = array_intersect($foreignKeys, array_keys($data));
1551:
1552: if (empty($included) || empty($this->id)) {
1553: return array();
1554: }
1555: $old = $this->find('first', array(
1556: 'conditions' => array($this->primaryKey => $this->id),
1557: 'fields' => array_values($included),
1558: 'recursive' => -1
1559: ));
1560: return array_merge($data, array('old' => $old[$this->alias]));
1561: }
1562:
1563: 1564: 1565: 1566: 1567: 1568: 1569: 1570: 1571: 1572: 1573: 1574: 1575: 1576: 1577: 1578: 1579: 1580: 1581: 1582: 1583: 1584: 1585:
1586: function saveAll($data = null, $options = array()) {
1587: if (empty($data)) {
1588: $data = $this->data;
1589: }
1590: $db =& ConnectionManager::getDataSource($this->useDbConfig);
1591:
1592: $options = array_merge(array('validate' => 'first', 'atomic' => true), $options);
1593: $this->validationErrors = $validationErrors = array();
1594: $validates = true;
1595: $return = array();
1596:
1597: if (empty($data) && $options['validate'] !== false) {
1598: $result = $this->save($data, $options);
1599: return !empty($result);
1600: }
1601:
1602: if ($options['atomic'] && $options['validate'] !== 'only') {
1603: $transactionBegun = $db->begin($this);
1604: }
1605:
1606: if (Set::numeric(array_keys($data))) {
1607: while ($validates) {
1608: $return = array();
1609: foreach ($data as $key => $record) {
1610: if (!$currentValidates = $this->__save($record, $options)) {
1611: $validationErrors[$key] = $this->validationErrors;
1612: }
1613:
1614: if ($options['validate'] === 'only' || $options['validate'] === 'first') {
1615: $validating = true;
1616: if ($options['atomic']) {
1617: $validates = $validates && $currentValidates;
1618: } else {
1619: $validates = $currentValidates;
1620: }
1621: } else {
1622: $validating = false;
1623: $validates = $currentValidates;
1624: }
1625:
1626: if (!$options['atomic']) {
1627: $return[] = $validates;
1628: } elseif (!$validates && !$validating) {
1629: break;
1630: }
1631: }
1632: $this->validationErrors = $validationErrors;
1633:
1634: switch (true) {
1635: case ($options['validate'] === 'only'):
1636: return ($options['atomic'] ? $validates : $return);
1637: break;
1638: case ($options['validate'] === 'first'):
1639: $options['validate'] = true;
1640: break;
1641: default:
1642: if ($options['atomic']) {
1643: if ($validates) {
1644: if ($transactionBegun) {
1645: return $db->commit($this) !== false;
1646: } else {
1647: return true;
1648: }
1649: }
1650: $db->rollback($this);
1651: return false;
1652: }
1653: return $return;
1654: break;
1655: }
1656: }
1657: if ($options['atomic'] && !$validates) {
1658: $db->rollback($this);
1659: return false;
1660: }
1661: return $return;
1662: }
1663: $associations = $this->getAssociated();
1664:
1665: while ($validates) {
1666: foreach ($data as $association => $values) {
1667: if (isset($associations[$association])) {
1668: switch ($associations[$association]) {
1669: case 'belongsTo':
1670: if ($this->{$association}->__save($values, $options)) {
1671: $data[$this->alias][$this->belongsTo[$association]['foreignKey']] = $this->{$association}->id;
1672: } else {
1673: $validationErrors[$association] = $this->{$association}->validationErrors;
1674: $validates = false;
1675: }
1676: if (!$options['atomic']) {
1677: $return[$association][] = $validates;
1678: }
1679: break;
1680: }
1681: }
1682: }
1683:
1684: if (!$this->__save($data, $options)) {
1685: $validationErrors[$this->alias] = $this->validationErrors;
1686: $validates = false;
1687: }
1688: if (!$options['atomic']) {
1689: $return[$this->alias] = $validates;
1690: }
1691: $validating = ($options['validate'] === 'only' || $options['validate'] === 'first');
1692:
1693: foreach ($data as $association => $values) {
1694: if (!$validates && !$validating) {
1695: break;
1696: }
1697: if (isset($associations[$association])) {
1698: $type = $associations[$association];
1699: switch ($type) {
1700: case 'hasOne':
1701: if (!$validating) {
1702: $values[$this->{$type}[$association]['foreignKey']] = $this->id;
1703: }
1704:
1705: if (!$this->{$association}->__save($values, $options)) {
1706: $validationErrors[$association] = $this->{$association}->validationErrors;
1707: $validates = false;
1708: }
1709: if (!$options['atomic']) {
1710: $return[$association][] = $validates;
1711: }
1712: break;
1713: case 'hasMany':
1714: if (!$validating) {
1715: foreach ($values as $i => $value) {
1716: $values[$i][$this->{$type}[$association]['foreignKey']] = $this->id;
1717: }
1718: }
1719:
1720: $_options = array_merge($options, array('atomic' => false));
1721:
1722: if ($_options['validate'] === 'first') {
1723: $_options['validate'] = 'only';
1724: }
1725: $_return = $this->{$association}->saveAll($values, $_options);
1726:
1727: if ($_return === false || (is_array($_return) && in_array(false, $_return, true))) {
1728: $validationErrors[$association] = $this->{$association}->validationErrors;
1729: $validates = false;
1730: }
1731: if (is_array($_return)) {
1732: foreach ($_return as $val) {
1733: if (!isset($return[$association])) {
1734: $return[$association] = array();
1735: } elseif (!is_array($return[$association])) {
1736: $return[$association] = array($return[$association]);
1737: }
1738: $return[$association][] = $val;
1739: }
1740: } else {
1741: $return[$association] = $_return;
1742: }
1743: break;
1744: }
1745: }
1746: }
1747: $this->validationErrors = $validationErrors;
1748:
1749: if (isset($validationErrors[$this->alias])) {
1750: $this->validationErrors = $validationErrors[$this->alias];
1751: }
1752:
1753: switch (true) {
1754: case ($options['validate'] === 'only'):
1755: return ($options['atomic'] ? $validates : $return);
1756: break;
1757: case ($options['validate'] === 'first'):
1758: $options['validate'] = true;
1759: $return = array();
1760: break;
1761: default:
1762: if ($options['atomic']) {
1763: if ($validates) {
1764: if ($transactionBegun) {
1765: return $db->commit($this) !== false;
1766: } else {
1767: return true;
1768: }
1769: } else {
1770: $db->rollback($this);
1771: }
1772: }
1773: return $return;
1774: break;
1775: }
1776: if ($options['atomic'] && !$validates) {
1777: $db->rollback($this);
1778: return false;
1779: }
1780: }
1781: }
1782:
1783: 1784: 1785: 1786: 1787: 1788: 1789:
1790: function __save($data, $options) {
1791: if ($options['validate'] === 'first' || $options['validate'] === 'only') {
1792: if (!($this->create($data) && $this->validates($options))) {
1793: return false;
1794: }
1795: } elseif (!($this->create(null) !== null && $this->save($data, $options))) {
1796: return false;
1797: }
1798: return true;
1799: }
1800:
1801: 1802: 1803: 1804: 1805: 1806: 1807: 1808: 1809: 1810:
1811: function updateAll($fields, $conditions = true) {
1812: $db =& ConnectionManager::getDataSource($this->useDbConfig);
1813: return $db->update($this, $fields, null, $conditions);
1814: }
1815:
1816: 1817: 1818: 1819: 1820: 1821: 1822: 1823: 1824:
1825: function delete($id = null, $cascade = true) {
1826: if (!empty($id)) {
1827: $this->id = $id;
1828: }
1829: $id = $this->id;
1830:
1831: if ($this->beforeDelete($cascade)) {
1832: $filters = $this->Behaviors->trigger($this, 'beforeDelete', array($cascade), array(
1833: 'break' => true, 'breakOn' => false
1834: ));
1835: if (!$filters || !$this->exists()) {
1836: return false;
1837: }
1838: $db =& ConnectionManager::getDataSource($this->useDbConfig);
1839:
1840: $this->_deleteDependent($id, $cascade);
1841: $this->_deleteLinks($id);
1842: $this->id = $id;
1843:
1844: if (!empty($this->belongsTo)) {
1845: $keys = $this->find('first', array(
1846: 'fields' => $this->__collectForeignKeys(),
1847: 'conditions' => array($this->alias . '.' . $this->primaryKey => $id)
1848: ));
1849: }
1850:
1851: if ($db->delete($this, array($this->alias . '.' . $this->primaryKey => $id))) {
1852: if (!empty($this->belongsTo)) {
1853: $this->updateCounterCache($keys[$this->alias]);
1854: }
1855: $this->Behaviors->trigger($this, 'afterDelete');
1856: $this->afterDelete();
1857: $this->_clearCache();
1858: $this->id = false;
1859: return true;
1860: }
1861: }
1862: return false;
1863: }
1864:
1865: 1866: 1867: 1868: 1869: 1870: 1871: 1872:
1873: function _deleteDependent($id, $cascade) {
1874: if (!empty($this->__backAssociation)) {
1875: $savedAssociatons = $this->__backAssociation;
1876: $this->__backAssociation = array();
1877: }
1878: if ($cascade === true) {
1879: foreach (array_merge($this->hasMany, $this->hasOne) as $assoc => $data) {
1880: if ($data['dependent'] === true) {
1881:
1882: $model =& $this->{$assoc};
1883: if ($data['foreignKey'] === false && $data['conditions'] && in_array($this->name, $model->getAssociated('belongsTo'))) {
1884: $model->recursive = 0;
1885: $conditions = array($this->escapeField(null, $this->name) => $id);
1886: } else {
1887: $model->recursive = -1;
1888: $conditions = array($model->escapeField($data['foreignKey']) => $id);
1889: if ($data['conditions']) {
1890: $conditions = array_merge((array)$data['conditions'], $conditions);
1891: }
1892: }
1893:
1894: if (isset($data['exclusive']) && $data['exclusive']) {
1895: $model->deleteAll($conditions);
1896: } else {
1897: $records = $model->find('all', array(
1898: 'conditions' => $conditions, 'fields' => $model->primaryKey
1899: ));
1900:
1901: if (!empty($records)) {
1902: foreach ($records as $record) {
1903: $model->delete($record[$model->alias][$model->primaryKey]);
1904: }
1905: }
1906: }
1907: }
1908: }
1909: }
1910: if (isset($savedAssociatons)) {
1911: $this->__backAssociation = $savedAssociatons;
1912: }
1913: }
1914:
1915: 1916: 1917: 1918: 1919: 1920: 1921:
1922: function _deleteLinks($id) {
1923: foreach ($this->hasAndBelongsToMany as $assoc => $data) {
1924: $joinModel = $data['with'];
1925: $records = $this->{$joinModel}->find('all', array(
1926: 'conditions' => array_merge(array($this->{$joinModel}->escapeField($data['foreignKey']) => $id)),
1927: 'fields' => $this->{$joinModel}->primaryKey,
1928: 'recursive' => -1
1929: ));
1930: if (!empty($records)) {
1931: foreach ($records as $record) {
1932: $this->{$joinModel}->delete($record[$this->{$joinModel}->alias][$this->{$joinModel}->primaryKey]);
1933: }
1934: }
1935: }
1936: }
1937:
1938: 1939: 1940: 1941: 1942: 1943: 1944: 1945: 1946: 1947:
1948: function deleteAll($conditions, $cascade = true, $callbacks = false) {
1949: if (empty($conditions)) {
1950: return false;
1951: }
1952: $db =& ConnectionManager::getDataSource($this->useDbConfig);
1953:
1954: if (!$cascade && !$callbacks) {
1955: return $db->delete($this, $conditions);
1956: } else {
1957: $ids = $this->find('all', array_merge(array(
1958: 'fields' => "{$this->alias}.{$this->primaryKey}",
1959: 'recursive' => 0), compact('conditions'))
1960: );
1961: if ($ids === false) {
1962: return false;
1963: }
1964:
1965: $ids = Set::extract($ids, "{n}.{$this->alias}.{$this->primaryKey}");
1966: if (empty($ids)) {
1967: return true;
1968: }
1969:
1970: if ($callbacks) {
1971: $_id = $this->id;
1972: $result = true;
1973: foreach ($ids as $id) {
1974: $result = ($result && $this->delete($id, $cascade));
1975: }
1976: $this->id = $_id;
1977: return $result;
1978: } else {
1979: foreach ($ids as $id) {
1980: $this->_deleteLinks($id);
1981: if ($cascade) {
1982: $this->_deleteDependent($id, $cascade);
1983: }
1984: }
1985: return $db->delete($this, array($this->alias . '.' . $this->primaryKey => $ids));
1986: }
1987: }
1988: }
1989:
1990: 1991: 1992: 1993: 1994: 1995:
1996: function __collectForeignKeys($type = 'belongsTo') {
1997: $result = array();
1998:
1999: foreach ($this->{$type} as $assoc => $data) {
2000: if (isset($data['foreignKey']) && is_string($data['foreignKey'])) {
2001: $result[$assoc] = $data['foreignKey'];
2002: }
2003: }
2004: return $result;
2005: }
2006:
2007: 2008: 2009: 2010: 2011: 2012: 2013: 2014: 2015: 2016:
2017: function exists() {
2018: if ($this->getID() === false) {
2019: return false;
2020: }
2021: $conditions = array($this->alias . '.' . $this->primaryKey => $this->getID());
2022: $query = array('conditions' => $conditions, 'recursive' => -1, 'callbacks' => false);
2023: return ($this->find('count', $query) > 0);
2024: }
2025:
2026: 2027: 2028: 2029: 2030: 2031: 2032:
2033: function hasAny($conditions = null) {
2034: return ($this->find('count', array('conditions' => $conditions, 'recursive' => -1)) != false);
2035: }
2036:
2037: 2038: 2039: 2040: 2041: 2042: 2043: 2044: 2045: 2046: 2047: 2048: 2049: 2050: 2051: 2052: 2053: 2054: 2055: 2056: 2057: 2058: 2059: 2060: 2061: 2062: 2063: 2064: 2065: 2066: 2067: 2068: 2069: 2070: 2071: 2072: 2073: 2074: 2075: 2076: 2077: 2078: 2079: 2080: 2081: 2082: 2083: 2084: 2085: 2086: 2087: 2088: 2089: 2090: 2091: 2092: 2093: 2094: 2095:
2096: function find($conditions = null, $fields = array(), $order = null, $recursive = null) {
2097: if (!is_string($conditions) || (is_string($conditions) && !array_key_exists($conditions, $this->_findMethods))) {
2098: $type = 'first';
2099: $query = array_merge(compact('conditions', 'fields', 'order', 'recursive'), array('limit' => 1));
2100: } else {
2101: list($type, $query) = array($conditions, $fields);
2102: }
2103:
2104: $this->findQueryType = $type;
2105: $this->id = $this->getID();
2106:
2107: $query = array_merge(
2108: array(
2109: 'conditions' => null, 'fields' => null, 'joins' => array(), 'limit' => null,
2110: 'offset' => null, 'order' => null, 'page' => null, 'group' => null, 'callbacks' => true
2111: ),
2112: (array)$query
2113: );
2114:
2115: if ($type != 'all') {
2116: if ($this->_findMethods[$type] === true) {
2117: $query = $this->{'_find' . ucfirst($type)}('before', $query);
2118: }
2119: }
2120:
2121: if (!is_numeric($query['page']) || intval($query['page']) < 1) {
2122: $query['page'] = 1;
2123: }
2124: if ($query['page'] > 1 && !empty($query['limit'])) {
2125: $query['offset'] = ($query['page'] - 1) * $query['limit'];
2126: }
2127: if ($query['order'] === null && $this->order !== null) {
2128: $query['order'] = $this->order;
2129: }
2130: $query['order'] = array($query['order']);
2131:
2132: if ($query['callbacks'] === true || $query['callbacks'] === 'before') {
2133: $return = $this->Behaviors->trigger($this, 'beforeFind', array($query), array(
2134: 'break' => true, 'breakOn' => false, 'modParams' => true
2135: ));
2136: $query = (is_array($return)) ? $return : $query;
2137:
2138: if ($return === false) {
2139: return null;
2140: }
2141:
2142: $return = $this->beforeFind($query);
2143: $query = (is_array($return)) ? $return : $query;
2144:
2145: if ($return === false) {
2146: return null;
2147: }
2148: }
2149:
2150: if (!$db =& ConnectionManager::getDataSource($this->useDbConfig)) {
2151: return false;
2152: }
2153: $results = $db->read($this, $query);
2154: $this->resetAssociations();
2155:
2156: if ($query['callbacks'] === true || $query['callbacks'] === 'after') {
2157: $results = $this->__filterResults($results);
2158: }
2159:
2160: $this->findQueryType = null;
2161:
2162: if ($type === 'all') {
2163: return $results;
2164: } else {
2165: if ($this->_findMethods[$type] === true) {
2166: return $this->{'_find' . ucfirst($type)}('after', $query, $results);
2167: }
2168: }
2169: }
2170:
2171: 2172: 2173: 2174: 2175: 2176: 2177: 2178: 2179: 2180:
2181: function _findFirst($state, $query, $results = array()) {
2182: if ($state == 'before') {
2183: $query['limit'] = 1;
2184: return $query;
2185: } elseif ($state == 'after') {
2186: if (empty($results[0])) {
2187: return false;
2188: }
2189: return $results[0];
2190: }
2191: }
2192:
2193: 2194: 2195: 2196: 2197: 2198: 2199: 2200: 2201: 2202:
2203: function _findCount($state, $query, $results = array()) {
2204: if ($state == 'before') {
2205: $db =& ConnectionManager::getDataSource($this->useDbConfig);
2206: if (empty($query['fields'])) {
2207: $query['fields'] = $db->calculate($this, 'count');
2208: } elseif (is_string($query['fields']) && !preg_match('/count/i', $query['fields'])) {
2209: $query['fields'] = $db->calculate($this, 'count', array(
2210: $db->expression($query['fields']), 'count'
2211: ));
2212: }
2213: $query['order'] = false;
2214: return $query;
2215: } elseif ($state == 'after') {
2216: if (isset($results[0][0]['count'])) {
2217: return intval($results[0][0]['count']);
2218: } elseif (isset($results[0][$this->alias]['count'])) {
2219: return intval($results[0][$this->alias]['count']);
2220: }
2221: return false;
2222: }
2223: }
2224:
2225: 2226: 2227: 2228: 2229: 2230: 2231: 2232: 2233: 2234:
2235: function _findList($state, $query, $results = array()) {
2236: if ($state == 'before') {
2237: if (empty($query['fields'])) {
2238: $query['fields'] = array("{$this->alias}.{$this->primaryKey}", "{$this->alias}.{$this->displayField}");
2239: $list = array("{n}.{$this->alias}.{$this->primaryKey}", "{n}.{$this->alias}.{$this->displayField}", null);
2240: } else {
2241: if (!is_array($query['fields'])) {
2242: $query['fields'] = String::tokenize($query['fields']);
2243: }
2244:
2245: if (count($query['fields']) == 1) {
2246: if (strpos($query['fields'][0], '.') === false) {
2247: $query['fields'][0] = $this->alias . '.' . $query['fields'][0];
2248: }
2249:
2250: $list = array("{n}.{$this->alias}.{$this->primaryKey}", '{n}.' . $query['fields'][0], null);
2251: $query['fields'] = array("{$this->alias}.{$this->primaryKey}", $query['fields'][0]);
2252: } elseif (count($query['fields']) == 3) {
2253: for ($i = 0; $i < 3; $i++) {
2254: if (strpos($query['fields'][$i], '.') === false) {
2255: $query['fields'][$i] = $this->alias . '.' . $query['fields'][$i];
2256: }
2257: }
2258:
2259: $list = array('{n}.' . $query['fields'][0], '{n}.' . $query['fields'][1], '{n}.' . $query['fields'][2]);
2260: } else {
2261: for ($i = 0; $i < 2; $i++) {
2262: if (strpos($query['fields'][$i], '.') === false) {
2263: $query['fields'][$i] = $this->alias . '.' . $query['fields'][$i];
2264: }
2265: }
2266:
2267: $list = array('{n}.' . $query['fields'][0], '{n}.' . $query['fields'][1], null);
2268: }
2269: }
2270: if (!isset($query['recursive']) || $query['recursive'] === null) {
2271: $query['recursive'] = -1;
2272: }
2273: list($query['list']['keyPath'], $query['list']['valuePath'], $query['list']['groupPath']) = $list;
2274: return $query;
2275: } elseif ($state == 'after') {
2276: if (empty($results)) {
2277: return array();
2278: }
2279: $lst = $query['list'];
2280: return Set::combine($results, $lst['keyPath'], $lst['valuePath'], $lst['groupPath']);
2281: }
2282: }
2283:
2284: 2285: 2286: 2287: 2288: 2289: 2290: 2291: 2292: 2293:
2294: function _findNeighbors($state, $query, $results = array()) {
2295: if ($state == 'before') {
2296: $query = array_merge(array('recursive' => 0), $query);
2297: extract($query);
2298: $conditions = (array)$conditions;
2299: if (isset($field) && isset($value)) {
2300: if (strpos($field, '.') === false) {
2301: $field = $this->alias . '.' . $field;
2302: }
2303: } else {
2304: $field = $this->alias . '.' . $this->primaryKey;
2305: $value = $this->id;
2306: }
2307: $query['conditions'] = array_merge($conditions, array($field . ' <' => $value));
2308: $query['order'] = $field . ' DESC';
2309: $query['limit'] = 1;
2310: $query['field'] = $field;
2311: $query['value'] = $value;
2312: return $query;
2313: } elseif ($state == 'after') {
2314: extract($query);
2315: unset($query['conditions'][$field . ' <']);
2316: $return = array();
2317: if (isset($results[0])) {
2318: $prevVal = Set::extract('/' . str_replace('.', '/', $field), $results[0]);
2319: $query['conditions'][$field . ' >='] = $prevVal[0];
2320: $query['conditions'][$field . ' !='] = $value;
2321: $query['limit'] = 2;
2322: } else {
2323: $return['prev'] = null;
2324: $query['conditions'][$field . ' >'] = $value;
2325: $query['limit'] = 1;
2326: }
2327: $query['order'] = $field . ' ASC';
2328: $return2 = $this->find('all', $query);
2329: if (!array_key_exists('prev', $return)) {
2330: $return['prev'] = $return2[0];
2331: }
2332: if (count($return2) == 2) {
2333: $return['next'] = $return2[1];
2334: } elseif (count($return2) == 1 && !$return['prev']) {
2335: $return['next'] = $return2[0];
2336: } else {
2337: $return['next'] = null;
2338: }
2339: return $return;
2340: }
2341: }
2342:
2343: 2344: 2345: 2346: 2347: 2348: 2349: 2350: 2351: 2352:
2353: function _findThreaded($state, $query, $results = array()) {
2354: if ($state == 'before') {
2355: return $query;
2356: } elseif ($state == 'after') {
2357: $return = $idMap = array();
2358: $ids = Set::extract($results, '{n}.' . $this->alias . '.' . $this->primaryKey);
2359:
2360: foreach ($results as $result) {
2361: $result['children'] = array();
2362: $id = $result[$this->alias][$this->primaryKey];
2363: $parentId = $result[$this->alias]['parent_id'];
2364: if (isset($idMap[$id]['children'])) {
2365: $idMap[$id] = array_merge($result, (array)$idMap[$id]);
2366: } else {
2367: $idMap[$id] = array_merge($result, array('children' => array()));
2368: }
2369: if (!$parentId || !in_array($parentId, $ids)) {
2370: $return[] =& $idMap[$id];
2371: } else {
2372: $idMap[$parentId]['children'][] =& $idMap[$id];
2373: }
2374: }
2375: if (count($return) > 1) {
2376: $ids = array_unique(Set::extract('/' . $this->alias . '/parent_id', $return));
2377: if (count($ids) > 1) {
2378: $root = $return[0][$this->alias]['parent_id'];
2379: foreach ($return as $key => $value) {
2380: if ($value[$this->alias]['parent_id'] != $root) {
2381: unset($return[$key]);
2382: }
2383: }
2384: }
2385: }
2386: return $return;
2387: }
2388: }
2389:
2390: 2391: 2392: 2393: 2394: 2395: 2396: 2397:
2398: function __filterResults($results, $primary = true) {
2399: $return = $this->Behaviors->trigger($this, 'afterFind', array($results, $primary), array('modParams' => true));
2400: if ($return !== true) {
2401: $results = $return;
2402: }
2403: return $this->afterFind($results, $primary);
2404: }
2405:
2406: 2407: 2408: 2409: 2410: 2411: 2412: 2413:
2414: function resetAssociations() {
2415: if (!empty($this->__backAssociation)) {
2416: foreach ($this->__associations as $type) {
2417: if (isset($this->__backAssociation[$type])) {
2418: $this->{$type} = $this->__backAssociation[$type];
2419: }
2420: }
2421: $this->__backAssociation = array();
2422: }
2423:
2424: foreach ($this->__associations as $type) {
2425: foreach ($this->{$type} as $key => $name) {
2426: if (!empty($this->{$key}->__backAssociation)) {
2427: $this->{$key}->resetAssociations();
2428: }
2429: }
2430: }
2431: $this->__backAssociation = array();
2432: return true;
2433: }
2434:
2435: 2436: 2437: 2438: 2439: 2440: 2441: 2442:
2443: function isUnique($fields, $or = true) {
2444: if (!is_array($fields)) {
2445: $fields = func_get_args();
2446: if (is_bool($fields[count($fields) - 1])) {
2447: $or = $fields[count($fields) - 1];
2448: unset($fields[count($fields) - 1]);
2449: }
2450: }
2451:
2452: foreach ($fields as $field => $value) {
2453: if (is_numeric($field)) {
2454: unset($fields[$field]);
2455:
2456: $field = $value;
2457: if (isset($this->data[$this->alias][$field])) {
2458: $value = $this->data[$this->alias][$field];
2459: } else {
2460: $value = null;
2461: }
2462: }
2463:
2464: if (strpos($field, '.') === false) {
2465: unset($fields[$field]);
2466: $fields[$this->alias . '.' . $field] = $value;
2467: }
2468: }
2469: if ($or) {
2470: $fields = array('or' => $fields);
2471: }
2472: if (!empty($this->id)) {
2473: $fields[$this->alias . '.' . $this->primaryKey . ' !='] = $this->id;
2474: }
2475: return ($this->find('count', array('conditions' => $fields, 'recursive' => -1)) == 0);
2476: }
2477:
2478: 2479: 2480: 2481: 2482: 2483: 2484: 2485:
2486: function query() {
2487: $params = func_get_args();
2488: $db =& ConnectionManager::getDataSource($this->useDbConfig);
2489: return call_user_func_array(array(&$db, 'query'), $params);
2490: }
2491:
2492: 2493: 2494: 2495: 2496: 2497: 2498: 2499: 2500: 2501: 2502:
2503: function validates($options = array()) {
2504: $errors = $this->invalidFields($options);
2505: if (empty($errors) && $errors !== false) {
2506: $errors = $this->__validateWithModels($options);
2507: }
2508: if (is_array($errors)) {
2509: return count($errors) === 0;
2510: }
2511: return $errors;
2512: }
2513:
2514: 2515: 2516: 2517: 2518: 2519: 2520: 2521: 2522:
2523: function invalidFields($options = array()) {
2524: if (
2525: !$this->Behaviors->trigger(
2526: $this,
2527: 'beforeValidate',
2528: array($options),
2529: array('break' => true, 'breakOn' => false)
2530: ) ||
2531: $this->beforeValidate($options) === false
2532: ) {
2533: return false;
2534: }
2535:
2536: if (!isset($this->validate) || empty($this->validate)) {
2537: return $this->validationErrors;
2538: }
2539:
2540: $data = $this->data;
2541: $methods = array_map('strtolower', get_class_methods($this));
2542: $behaviorMethods = array_keys($this->Behaviors->methods());
2543:
2544: if (isset($data[$this->alias])) {
2545: $data = $data[$this->alias];
2546: } elseif (!is_array($data)) {
2547: $data = array();
2548: }
2549:
2550: $Validation =& Validation::getInstance();
2551: $exists = null;
2552:
2553: $_validate = $this->validate;
2554: $whitelist = $this->whitelist;
2555:
2556: if (!empty($options['fieldList'])) {
2557: $whitelist = $options['fieldList'];
2558: }
2559:
2560: if (!empty($whitelist)) {
2561: $validate = array();
2562: foreach ((array)$whitelist as $f) {
2563: if (!empty($this->validate[$f])) {
2564: $validate[$f] = $this->validate[$f];
2565: }
2566: }
2567: $this->validate = $validate;
2568: }
2569:
2570: foreach ($this->validate as $fieldName => $ruleSet) {
2571: if (!is_array($ruleSet) || (is_array($ruleSet) && isset($ruleSet['rule']))) {
2572: $ruleSet = array($ruleSet);
2573: }
2574: $default = array(
2575: 'allowEmpty' => null,
2576: 'required' => null,
2577: 'rule' => 'blank',
2578: 'last' => false,
2579: 'on' => null
2580: );
2581:
2582: foreach ($ruleSet as $index => $validator) {
2583: if (!is_array($validator)) {
2584: $validator = array('rule' => $validator);
2585: }
2586: $validator = array_merge($default, $validator);
2587:
2588: if (isset($validator['message'])) {
2589: $message = $validator['message'];
2590: } else {
2591: $message = __('This field cannot be left blank', true);
2592: }
2593:
2594: if (!empty($validator['on'])) {
2595: if ($exists === null) {
2596: $exists = $this->exists();
2597: }
2598: if (($validator['on'] == 'create' && $exists) || ($validator['on'] == 'update' && !$exists)) {
2599: continue;
2600: }
2601: }
2602:
2603: $required = (
2604: (!isset($data[$fieldName]) && $validator['required'] === true) ||
2605: (
2606: isset($data[$fieldName]) && (empty($data[$fieldName]) &&
2607: !is_numeric($data[$fieldName])) && $validator['allowEmpty'] === false
2608: )
2609: );
2610:
2611: if ($required) {
2612: $this->invalidate($fieldName, $message);
2613: if ($validator['last']) {
2614: break;
2615: }
2616: } elseif (array_key_exists($fieldName, $data)) {
2617: if (empty($data[$fieldName]) && $data[$fieldName] != '0' && $validator['allowEmpty'] === true) {
2618: break;
2619: }
2620: if (is_array($validator['rule'])) {
2621: $rule = $validator['rule'][0];
2622: unset($validator['rule'][0]);
2623: $ruleParams = array_merge(array($data[$fieldName]), array_values($validator['rule']));
2624: } else {
2625: $rule = $validator['rule'];
2626: $ruleParams = array($data[$fieldName]);
2627: }
2628:
2629: $valid = true;
2630:
2631: if (in_array(strtolower($rule), $methods)) {
2632: $ruleParams[] = $validator;
2633: $ruleParams[0] = array($fieldName => $ruleParams[0]);
2634: $valid = $this->dispatchMethod($rule, $ruleParams);
2635: } elseif (in_array($rule, $behaviorMethods) || in_array(strtolower($rule), $behaviorMethods)) {
2636: $ruleParams[] = $validator;
2637: $ruleParams[0] = array($fieldName => $ruleParams[0]);
2638: $valid = $this->Behaviors->dispatchMethod($this, $rule, $ruleParams);
2639: } elseif (method_exists($Validation, $rule)) {
2640: $valid = $Validation->dispatchMethod($rule, $ruleParams);
2641: } elseif (!is_array($validator['rule'])) {
2642: $valid = preg_match($rule, $data[$fieldName]);
2643: } elseif (Configure::read('debug') > 0) {
2644: trigger_error(sprintf(__('Could not find validation handler %s for %s', true), $rule, $fieldName), E_USER_WARNING);
2645: }
2646:
2647: if (!$valid || (is_string($valid) && strlen($valid) > 0)) {
2648: if (is_string($valid) && strlen($valid) > 0) {
2649: $validator['message'] = $valid;
2650: } elseif (!isset($validator['message'])) {
2651: if (is_string($index)) {
2652: $validator['message'] = $index;
2653: } elseif (is_numeric($index) && count($ruleSet) > 1) {
2654: $validator['message'] = $index + 1;
2655: } else {
2656: $validator['message'] = $message;
2657: }
2658: }
2659: $this->invalidate($fieldName, $validator['message']);
2660:
2661: if ($validator['last']) {
2662: break;
2663: }
2664: }
2665: }
2666: }
2667: }
2668: $this->validate = $_validate;
2669: return $this->validationErrors;
2670: }
2671:
2672: 2673: 2674: 2675: 2676: 2677: 2678: 2679: 2680:
2681: function __validateWithModels($options) {
2682: $valid = true;
2683: foreach ($this->hasAndBelongsToMany as $assoc => $association) {
2684: if (empty($association['with']) || !isset($this->data[$assoc])) {
2685: continue;
2686: }
2687: list($join) = $this->joinModel($this->hasAndBelongsToMany[$assoc]['with']);
2688: $data = $this->data[$assoc];
2689:
2690: $newData = array();
2691: foreach ((array)$data as $row) {
2692: if (isset($row[$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
2693: $newData[] = $row;
2694: } elseif (isset($row[$join]) && isset($row[$join][$this->hasAndBelongsToMany[$assoc]['associationForeignKey']])) {
2695: $newData[] = $row[$join];
2696: }
2697: }
2698: if (empty($newData)) {
2699: continue;
2700: }
2701: foreach ($newData as $data) {
2702: $data[$this->hasAndBelongsToMany[$assoc]['foreignKey']] = $this->id;
2703: $this->{$join}->create($data);
2704: $valid = ($valid && $this->{$join}->validates($options));
2705: }
2706: }
2707: return $valid;
2708: }
2709: 2710: 2711: 2712: 2713: 2714: 2715: 2716: 2717:
2718: function invalidate($field, $value = true) {
2719: if (!is_array($this->validationErrors)) {
2720: $this->validationErrors = array();
2721: }
2722: $this->validationErrors[$field] = $value;
2723: }
2724:
2725: 2726: 2727: 2728: 2729: 2730: 2731:
2732: function isForeignKey($field) {
2733: $foreignKeys = array();
2734: if (!empty($this->belongsTo)) {
2735: foreach ($this->belongsTo as $assoc => $data) {
2736: $foreignKeys[] = $data['foreignKey'];
2737: }
2738: }
2739: return in_array($field, $foreignKeys);
2740: }
2741:
2742: 2743: 2744: 2745: 2746: 2747: 2748: 2749: 2750:
2751: function escapeField($field = null, $alias = null) {
2752: if (empty($alias)) {
2753: $alias = $this->alias;
2754: }
2755: if (empty($field)) {
2756: $field = $this->primaryKey;
2757: }
2758: $db =& ConnectionManager::getDataSource($this->useDbConfig);
2759: if (strpos($field, $db->name($alias) . '.') === 0) {
2760: return $field;
2761: }
2762: return $db->name($alias . '.' . $field);
2763: }
2764:
2765: 2766: 2767: 2768: 2769: 2770: 2771:
2772: function getID($list = 0) {
2773: if (empty($this->id) || (is_array($this->id) && isset($this->id[0]) && empty($this->id[0]))) {
2774: return false;
2775: }
2776:
2777: if (!is_array($this->id)) {
2778: return $this->id;
2779: }
2780:
2781: if (empty($this->id)) {
2782: return false;
2783: }
2784:
2785: if (isset($this->id[$list]) && !empty($this->id[$list])) {
2786: return $this->id[$list];
2787: } elseif (isset($this->id[$list])) {
2788: return false;
2789: }
2790:
2791: foreach ($this->id as $id) {
2792: return $id;
2793: }
2794:
2795: return false;
2796: }
2797:
2798: 2799: 2800: 2801: 2802: 2803:
2804: function getLastInsertID() {
2805: return $this->getInsertID();
2806: }
2807:
2808: 2809: 2810: 2811: 2812: 2813:
2814: function getInsertID() {
2815: return $this->__insertID;
2816: }
2817:
2818: 2819: 2820: 2821: 2822: 2823:
2824: function setInsertID($id) {
2825: $this->__insertID = $id;
2826: }
2827:
2828: 2829: 2830: 2831: 2832: 2833:
2834: function getNumRows() {
2835: $db =& ConnectionManager::getDataSource($this->useDbConfig);
2836: return $db->lastNumRows();
2837: }
2838:
2839: 2840: 2841: 2842: 2843: 2844:
2845: function getAffectedRows() {
2846: $db =& ConnectionManager::getDataSource($this->useDbConfig);
2847: return $db->lastAffected();
2848: }
2849:
2850: 2851: 2852: 2853: 2854: 2855: 2856:
2857: function setDataSource($dataSource = null) {
2858: $oldConfig = $this->useDbConfig;
2859:
2860: if ($dataSource != null) {
2861: $this->useDbConfig = $dataSource;
2862: }
2863: $db =& ConnectionManager::getDataSource($this->useDbConfig);
2864: if (!empty($oldConfig) && isset($db->config['prefix'])) {
2865: $oldDb =& ConnectionManager::getDataSource($oldConfig);
2866:
2867: if (!isset($this->tablePrefix) || (!isset($oldDb->config['prefix']) || $this->tablePrefix == $oldDb->config['prefix'])) {
2868: $this->tablePrefix = $db->config['prefix'];
2869: }
2870: } elseif (isset($db->config['prefix'])) {
2871: $this->tablePrefix = $db->config['prefix'];
2872: }
2873:
2874: if (empty($db) || !is_object($db)) {
2875: return $this->cakeError('missingConnection', array(array('code' => 500, 'className' => $this->alias)));
2876: }
2877: }
2878:
2879: 2880: 2881: 2882: 2883: 2884: 2885:
2886: function &getDataSource() {
2887: $db =& ConnectionManager::getDataSource($this->useDbConfig);
2888: return $db;
2889: }
2890:
2891: 2892: 2893: 2894: 2895: 2896: 2897:
2898: function getAssociated($type = null) {
2899: if ($type == null) {
2900: $associated = array();
2901: foreach ($this->__associations as $assoc) {
2902: if (!empty($this->{$assoc})) {
2903: $models = array_keys($this->{$assoc});
2904: foreach ($models as $m) {
2905: $associated[$m] = $assoc;
2906: }
2907: }
2908: }
2909: return $associated;
2910: } elseif (in_array($type, $this->__associations)) {
2911: if (empty($this->{$type})) {
2912: return array();
2913: }
2914: return array_keys($this->{$type});
2915: } else {
2916: $assoc = array_merge(
2917: $this->hasOne,
2918: $this->hasMany,
2919: $this->belongsTo,
2920: $this->hasAndBelongsToMany
2921: );
2922: if (array_key_exists($type, $assoc)) {
2923: foreach ($this->__associations as $a) {
2924: if (isset($this->{$a}[$type])) {
2925: $assoc[$type]['association'] = $a;
2926: break;
2927: }
2928: }
2929: return $assoc[$type];
2930: }
2931: return null;
2932: }
2933: }
2934:
2935: 2936: 2937: 2938: 2939: 2940: 2941: 2942: 2943: 2944:
2945: function joinModel($assoc, $keys = array()) {
2946: if (is_string($assoc)) {
2947: return array($assoc, array_keys($this->{$assoc}->schema()));
2948: } elseif (is_array($assoc)) {
2949: $with = key($assoc);
2950: return array($with, array_unique(array_merge($assoc[$with], $keys)));
2951: }
2952: trigger_error(
2953: sprintf(__('Invalid join model settings in %s', true), $model->alias),
2954: E_USER_WARNING
2955: );
2956: }
2957:
2958: 2959: 2960: 2961: 2962: 2963: 2964: 2965: 2966: 2967:
2968: function beforeFind($queryData) {
2969: return true;
2970: }
2971:
2972: 2973: 2974: 2975: 2976: 2977: 2978: 2979: 2980: 2981:
2982: function afterFind($results, $primary = false) {
2983: return $results;
2984: }
2985:
2986: 2987: 2988: 2989: 2990: 2991: 2992: 2993:
2994: function beforeSave($options = array()) {
2995: return true;
2996: }
2997:
2998: 2999: 3000: 3001: 3002: 3003: 3004:
3005: function afterSave($created) {
3006: }
3007:
3008: 3009: 3010: 3011: 3012: 3013: 3014: 3015:
3016: function beforeDelete($cascade = true) {
3017: return true;
3018: }
3019:
3020: 3021: 3022: 3023: 3024: 3025:
3026: function afterDelete() {
3027: }
3028:
3029: 3030: 3031: 3032: 3033: 3034: 3035: 3036: 3037:
3038: function beforeValidate($options = array()) {
3039: return true;
3040: }
3041:
3042: 3043: 3044: 3045: 3046: 3047:
3048: function onError() {
3049: }
3050:
3051: 3052: 3053: 3054: 3055: 3056: 3057: 3058: 3059:
3060: function _clearCache($type = null) {
3061: if ($type === null) {
3062: if (Configure::read('Cache.check') === true) {
3063: $assoc[] = strtolower(Inflector::pluralize($this->alias));
3064: $assoc[] = strtolower(Inflector::underscore(Inflector::pluralize($this->alias)));
3065: foreach ($this->__associations as $key => $association) {
3066: foreach ($this->$association as $key => $className) {
3067: $check = strtolower(Inflector::pluralize($className['className']));
3068: if (!in_array($check, $assoc)) {
3069: $assoc[] = strtolower(Inflector::pluralize($className['className']));
3070: $assoc[] = strtolower(Inflector::underscore(Inflector::pluralize($className['className'])));
3071: }
3072: }
3073: }
3074: clearCache($assoc);
3075: return true;
3076: }
3077: } else {
3078:
3079: }
3080: }
3081:
3082: 3083: 3084: 3085: 3086: 3087:
3088: function __sleep() {
3089: $return = array_keys(get_object_vars($this));
3090: return $return;
3091: }
3092:
3093: 3094: 3095: 3096: 3097: 3098:
3099: function __wakeup() {
3100: }
3101: }
3102: if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) {
3103: Overloadable::overload('Model');
3104: }
3105: