00001 <?php
00003
00004
00005
00006
00007
00008
00010
00020
00021 FLEA::loadClass('FLEA_Db_TableLink');
00022
00023
00024
00028 define('HAS_ONE', 1);
00029
00033 define('BELONGS_TO', 2);
00034
00038 define('HAS_MANY', 3);
00039
00043 define('MANY_TO_MANY', 4);
00044
00045
00059 class FLEA_Db_TableDataGateway
00060 {
00066 var $schema = '';
00067
00073 var $tableName = null;
00074
00080 var $fullTableName = null;
00081
00087 var $primaryKey = null;
00088
00094 var $hasOne = null;
00095
00101 var $belongsTo = null;
00102
00108 var $hasMany = null;
00109
00115 var $manyToMany = null;
00116
00125 var $meta = null;
00126
00132 var $fields = null;
00133
00141 var $autoValidating = false;
00142
00148 var $verifier = null;
00149
00155 var $validateRules = null;
00156
00165 var $createdTimeFields = array('CREATED', 'CREATED_ON', 'CREATED_AT');
00166
00175 var $updatedTimeFields = array('UPDATED', 'UPDATED_ON', 'UPDATED_AT');
00176
00184 var $autoLink = true;
00185
00194 var $dbo = null;
00195
00204 var $links = array();
00205
00212 var $qtableName;
00213
00220 var $qpk;
00221
00225 var $pka;
00226
00233 var $qpka;
00234
00242 var $lastValidationResult;
00243
00263 function FLEA_Db_TableDataGateway($params = null)
00264 {
00265 if (!empty($params['schema'])) {
00266 $this->schema = $params['schema'];
00267 }
00268 if (!empty($params['tableName'])) {
00269 $this->tableName = $params['tableName'];
00270 }
00271
00272 if (!empty($params['primaryKey'])) {
00273 $this->primaryKey = $params['primaryKey'];
00274 }
00275
00276
00277 if (isset($params['autoValidating'])) {
00278 $this->autoValidating = $params['autoValidating'];
00279 }
00280 if ($this->autoValidating) {
00281 if (!empty($params['verifierProvider'])) {
00282 $provider = $params['verifierProvider'];
00283 } else {
00284 $provider = FLEA::getAppInf('helper.verifier');
00285 }
00286 if (!empty($provider)) {
00287 $this->verifier =& FLEA::getSingleton($provider);
00288 }
00289 }
00290
00291
00292 if (isset($params['skipConnect']) && $params['skipConnect'] != false) {
00293 return;
00294 }
00295
00296
00297 if (!isset($params['dbo'])) {
00298 if (isset($params['dbDSN'])) {
00299 $dbo =& FLEA::getDBO($params['dbDSN']);
00300 } else {
00301 $dbo =& FLEA::getDBO();
00302 }
00303 } else {
00304 $dbo =& $params['dbo'];
00305 }
00306 $this->setDBO($dbo);
00307
00308
00309 if (!isset($params['skipCreateLinks']) || $params['skipCreateLinks'] == false) {
00310 $this->relink();
00311 }
00312 }
00313
00321 function setDBO(& $dbo)
00322 {
00323 $this->dbo =& $dbo;
00324
00325 if (empty($this->schema) && !empty($dbo->dsn['schema'])) {
00326 $this->schema = $dbo->dsn['schema'];
00327 }
00328 if (empty($this->fullTableName)) {
00329 $this->fullTableName = $dbo->dsn['prefix'] . $this->tableName;
00330 }
00331 $this->qtableName = $dbo->qtable($this->fullTableName, $this->schema);
00332
00333 if (!$this->_prepareMeta()) {
00334 return false;
00335 }
00336 $this->fields = array_keys($this->meta);
00337
00338 if (is_array($this->validateRules)) {
00339 foreach ($this->validateRules as $fieldName => $rules) {
00340 $fieldName = strtoupper($fieldName);
00341 if (!isset($this->meta[$fieldName])) { continue; }
00342 foreach ((array)$rules as $ruleName => $rule) {
00343 $this->meta[$fieldName][$ruleName] = $rule;
00344 }
00345 }
00346 }
00347
00348
00349 if (empty($this->primaryKey)) {
00350 foreach ($this->meta as $field) {
00351 if ($field['primaryKey']) {
00352 $this->primaryKey = $field['name'];
00353 break;
00354 }
00355 }
00356 }
00357
00358 if (is_array($this->primaryKey)) {
00359 $this->qpk = array();
00360 $this->pka = array();
00361 $this->qpka = array();
00362 foreach ($this->primaryKey as $pk) {
00363 $qpk = $dbo->qfield($pk, $this->fullTableName, $this->schema);
00364 $this->qpk[$pk] = $qpk;
00365 $pka = 'flea_pkref_' . $pk;
00366 $this->pka[$pk] = $pka;
00367 $this->qpka[$pk] = $qpk . ' AS ' . $pka;
00368 }
00369 } else {
00370 $this->qpk = $dbo->qfield($this->primaryKey, $this->fullTableName, $this->schema);
00371 $this->pka = 'flea_pkref_' . $this->primaryKey;
00372 $this->qpka = $this->qpk . ' AS ' . $this->pka;
00373 }
00374
00375 return true;
00376 }
00377
00383 function & getDBO()
00384 {
00385 return $this->dbo;
00386 }
00387
00398 function & find($conditions, $sort = null, $fields = '*', $queryLinks = true)
00399 {
00400 $rowset =& $this->findAll($conditions, $sort, 1, $fields, $queryLinks);
00401 if (is_array($rowset)) {
00402 $row = reset($rowset);
00403 } else {
00404 $row = false;
00405 }
00406 unset($rowset);
00407 return $row;
00408 }
00409
00421 function & findAll($conditions = null, $sort = null, $limit = null, $fields = '*', $queryLinks = true)
00422 {
00423 list($whereby, $distinct) = $this->getWhere($conditions);
00424
00425 $sortby = $sort != '' ? " ORDER BY {$sort}" : '';
00426
00427 if (is_array($limit)) {
00428 list($length, $offset) = $limit;
00429 } else {
00430 $length = $limit;
00431 $offset = null;
00432 }
00433
00434
00435 $enableLinks = count($this->links) > 0 && $this->autoLink && $queryLinks;
00436 $fields = $this->dbo->qfields($fields, $this->fullTableName, $this->schema);
00437 if ($enableLinks) {
00438
00439 $sql = "SELECT {$distinct} {$this->qpka}, {$fields} FROM {$this->qtableName} {$whereby} {$sortby}";
00440 } else {
00441 $sql = "SELECT {$distinct} {$fields} FROM {$this->qtableName} {$whereby} {$sortby}";
00442 }
00443
00444
00445 if (null !== $length || null !== $offset) {
00446 $result = $this->dbo->selectLimit($sql, $length, $offset);
00447 } else {
00448 $result = $this->dbo->execute($sql);
00449 }
00450
00451 if ($enableLinks) {
00456 $pkvs = array();
00457 $assocRowset = null;
00458 $rowset = $this->dbo->getAllWithFieldRefs($result, $this->pka, $pkvs, $assocRowset);
00459 $in = 'IN (' . implode(',', array_map(array(& $this->dbo, 'qstr'), $pkvs)) . ')';
00460 } else {
00461 $rowset = $this->dbo->getAll($result);
00462 }
00463 unset($result);
00464
00465
00466 if (!$enableLinks || empty($rowset) || !$this->autoLink) {
00467 return $rowset;
00468 }
00469
00475 $callback = create_function('& $r, $o, $m', '$r[$m] = null;');
00476 foreach ($this->links as $link) {
00477
00478 $mn = $link->mappingName;
00479 if (!$link->enabled || !$link->linkRead) { continue; }
00480 if (!$link->countOnly) {
00481 array_walk($assocRowset, $callback, $mn);
00482 $sql = $link->getFindSQL($in);
00483 $this->dbo->assemble($sql, $assocRowset, $mn, $link->oneToOne, $this->pka, $link->limit);
00484 } else {
00485 $link->calcCount($assocRowset, $mn, $in);
00486 }
00487 }
00488
00489 return $rowset;
00490 }
00491
00499 function assembleRecursionRow($mappingName, & $row, $enabledLinks = null)
00500 {
00501 $assoclink =& $this->getLink($mappingName);
00502 if ($assoclink == false) { return false; }
00503
00504 $assoclink->init();
00505 $tdg =& $assoclink->assocTDG;
00506 $arow =& $row[$mappingName];
00507
00508 if (!is_array($enabledLinks)) {
00509 if ($enabledLinks == null) {
00510 $enabledLinks = array_keys($tdg->links);
00511 } else {
00512 $enabledLinks = explode(',', $enabledLinks);
00513 array_walk($enabledLinks, 'trim');
00514 $enabledLinks = array_filter($enabledLinks, 'strlen');
00515 }
00516 }
00517 $enabledLinks = array_flip($enabledLinks);
00518 $enabledLinks = array_change_key_case($enabledLinks, CASE_LOWER);
00519 $this->enableLinks(array_keys($enabledLinks));
00520
00521 foreach ($tdg->links as $link) {
00522
00523 if (!$link->enabled || !$link->linkRead || !isset($enabledLinks[$link->mappingName])) { continue; }
00524
00525 $in = array();
00526 switch ($assoclink->type) {
00527 case HAS_ONE:
00528 case BELONGS_TO:
00529 $pkv = $arow[$link->mainTDG->primaryKey];
00530 $in[] = $pkv;
00531 $assocRowset = array($pkv => & $arow);
00532 $arow[$link->mappingName] = null;
00533 break;
00534 case HAS_MANY:
00535 case MANY_TO_MANY:
00536 $assocRowset = array();
00537 foreach (array_keys($arow) as $offset) {
00538 $pkv = $arow[$offset][$link->mainTDG->primaryKey];
00539 $in[] = $pkv;
00540 $assocRowset[$pkv] = & $arow[$offset];
00541 $arow[$offset][$link->mappingName] = null;
00542 }
00543 }
00544 $in = 'IN (' . implode(',', array_map(array(& $this->dbo, 'qstr'), $in)) . ')';
00545
00546 $sql = $link->getFindSQL($in);
00547 $this->dbo->assemble($sql, $assocRowset, $link->mappingName, $link->oneToOne, $link->mainTDG->pka, $link->limit);
00548 }
00549
00550 return true;
00551 }
00552
00553
00561 function assembleRecursionRowset($mappingName, & $rowset, $enabledLinks = null)
00562 {
00563 $assoclink =& $this->getLink($mappingName);
00564 if ($assoclink == false) { return false; }
00565
00566 $assoclink->init();
00567 $tdg =& $assoclink->assocTDG;
00568 $arowset = array();
00569 foreach (array_keys($rowset) as $offset) {
00570 $arowset[] =& $rowset[$offset][$mappingName];
00571 }
00572 $keys = array_keys($arowset);
00573
00574 if (!is_array($enabledLinks)) {
00575 if ($enabledLinks == null) {
00576 $enabledLinks = array_keys($tdg->links);
00577 } else {
00578 $enabledLinks = explode(',', $enabledLinks);
00579 array_walk($enabledLinks, 'trim');
00580 $enabledLinks = array_filter($enabledLinks, 'strlen');
00581 }
00582 }
00583 $enabledLinks = array_flip($enabledLinks);
00584 $enabledLinks = array_change_key_case($enabledLinks, CASE_LOWER);
00585 $this->enableLinks(array_keys($enabledLinks));
00586
00587 foreach ($tdg->links as $link) {
00588
00589 if (!$link->enabled || !$link->linkRead || !isset($enabledLinks[$link->mappingName])) { continue; }
00590
00591 $in = array();
00592 $assocRowset = array();
00593 switch ($assoclink->type) {
00594 case HAS_ONE:
00595 case BELONGS_TO:
00596 foreach ($keys as $key) {
00597 $pkv = $arowset[$key][$link->mainTDG->primaryKey];
00598 $in[] = $pkv;
00599 $assocRowset[$pkv] =& $arowset[$key];
00600 $arowset[$key][$link->mappingName] = null;
00601 }
00602 break;
00603 case HAS_MANY:
00604 case MANY_TO_MANY:
00605 foreach ($keys as $key) {
00606 foreach (array_keys($arowset[$key]) as $offset) {
00607 $pkv = $arowset[$key][$offset][$link->mainTDG->primaryKey];
00608 $in[] = $pkv;
00609 $assocRowset[$pkv] = & $arowset[$key][$offset];
00610 $arow[$key][$offset][$link->mappingName] = null;
00611 }
00612 }
00613 }
00614 $in = 'IN (' . implode(',', array_map(array(& $this->dbo, 'qstr'), $in)) . ')';
00615
00616 $sql = $link->getFindSQL($in);
00617 $this->dbo->assemble($sql, $assocRowset, $link->mappingName, $link->oneToOne, $link->mainTDG->pka, $link->limit);
00618 }
00619
00620 return true;
00621 }
00622
00633 function & findByField($field, $value, $sort = null, $fields = '*')
00634 {
00635 return $this->find(array($field => $value), $sort, $fields);
00636 }
00637
00649 function & findAllByField($field, $value, $sort = null, $limit = null, $fields = '*')
00650 {
00651 return $this->findAll(array($field => $value), $sort, $limit, $fields);
00652 }
00653
00666 function & findAllByPkvs($pkvs, $conditions = null, $sort = null, $limit = null, $fields = '*', $queryLinks = true)
00667 {
00668 $in = array('in()' => $pkvs);
00669 if (empty($conditions)) {
00670 $conditions = $in;
00671 } else {
00672 if (!is_array($conditions)) {
00673 $conditions = array($in, $conditions);
00674 } else {
00675 array_push($conditions, $in);
00676 }
00677 }
00678
00679 return $this->findAll($conditions, $sort, $limit, $fields, $queryLinks);
00680 }
00681
00690 function & findBySql($sql, $limit = null)
00691 {
00692
00693 if (is_array($limit)) {
00694 list($length, $offset) = $limit;
00695 } else {
00696 $length = $limit;
00697 $offset = null;
00698 }
00699 if (is_null($length) && is_null($offset)) {
00700 return $this->dbo->getAll($sql);
00701 }
00702
00703 $result = $this->dbo->selectLimit($sql, $length, $offset);
00704 if ($result) {
00705 $rowset = $this->dbo->getAll($result);
00706 } else {
00707 $rowset = false;
00708 }
00709 return $rowset;
00710 }
00711
00720 function findCount($conditions = null, $fields = null)
00721 {
00722 list($whereby, $distinct) = $this->getWhere($conditions);
00723 if (is_null($fields)) {
00724 $fields = $this->qpk;
00725 } else {
00726 $fields = $this->dbo->qfields($fields, $this->fullTableName);
00727 }
00728 $sql = "SELECT {$distinct}COUNT({$fields}) FROM {$this->qtableName}{$whereby}";
00729 return (int)$this->dbo->getOne($sql);
00730 }
00731
00743 function save(& $row, $saveLinks = true, $updateCounter = true)
00744 {
00745 if (empty($row[$this->primaryKey])) {
00746 return $this->create($row, $saveLinks, $updateCounter);
00747 } else {
00748 return $this->update($row, $saveLinks, $updateCounter);
00749 }
00750 }
00751
00760 function saveRowset(& $rowset, $saveLinks = true)
00761 {
00762 $this->dbo->startTrans();
00763 foreach ($rowset as $row) {
00764 if (!$this->save($row, $saveLinks, false)) {
00765 $this->dbo->completeTrans(false);
00766 return false;
00767 }
00768 }
00769 $this->dbo->completeTrans();
00770 return true;
00771 }
00772
00780 function replace(& $row) {
00781 $this->_setCreatedTimeFields($row);
00782 $fields = '';
00783 $values = '';
00784 foreach ($row as $field => $value) {
00785 if (!isset($this->meta[strtoupper($field)])) { continue; }
00786 $fields .= $this->dbo->qfield($field) . ', ';
00787 $values .= $this->dbo->qstr($value) . ', ';
00788 }
00789 $fields = substr($fields, 0, -2);
00790 $values = substr($values, 0, -2);
00791 $sql = "REPLACE INTO {$this->fullTableName} ({$fields}) VALUES ({$values})";
00792 if (!$this->dbo->execute($sql)) { return false; }
00793
00794 if (!empty($row[$this->primaryKey])) {
00795 return $row[$this->primaryKey];
00796 }
00797
00798 $insertid = $this->dbo->insertId();
00799 return $insertid;
00800 }
00801
00809 function replaceRowset(& $rowset)
00810 {
00811 $ids = array();
00812 $this->dbo->startTrans();
00813 foreach ($rowset as $row) {
00814 $id = $this->replace($row, false);
00815 if (!$id) {
00816 $this->dbo->completeTrans(false);
00817 return false;
00818 }
00819 $ids[] = $id;
00820 }
00821 $this->dbo->completeTrans();
00822 return $ids;
00823 }
00824
00835 function update(& $row, $saveLinks = true)
00836 {
00837 if (!$this->_beforeUpdate($row)) {
00838 return false;
00839 }
00840
00841
00842 if (!isset($row[$this->primaryKey])) {
00843 FLEA::loadClass('FLEA_Db_Exception_MissingPrimaryKey');
00844 return __THROW(new FLEA_Db_Exception_MissingPrimaryKey($this->primaryKey));
00845 }
00846
00847
00848 $this->_setUpdatedTimeFields($row);
00849
00850
00851 if ($this->autoValidating && $this->verifier != null) {
00852 if (!$this->checkRowData($row, true)) {
00853
00854 FLEA::loadClass('FLEA_Exception_ValidationFailed');
00855 return __THROW(new FLEA_Exception_ValidationFailed($this->getLastValidation(), $row));
00856 }
00857 }
00858
00859
00860 $this->dbo->startTrans();
00861
00862
00863 if (!$this->_beforeUpdateDb($row)) {
00864 $this->dbo->completeTrans(false);
00865 return false;
00866 }
00867
00868
00869 $pkv = $row[$this->primaryKey];
00870 unset($row[$this->primaryKey]);
00871 list($pairs, $values) = $this->dbo->getPlaceholderPair($row, $this->fields);
00872 $row[$this->primaryKey] = $pkv;
00873
00874 if (!empty($pairs)) {
00875 $pairs = implode(',', $pairs);
00876 $sql = "UPDATE {$this->qtableName} SET {$pairs} WHERE {$this->qpk} = " . $this->dbo->qstr($pkv);
00877
00878
00879 if (!$this->dbo->execute($sql, $values)) {
00880 $this->dbo->completeTrans(false);
00881 return false;
00882 }
00883 }
00884
00885
00886 if ($this->autoLink && $saveLinks) {
00887 foreach (array_keys($this->links) as $linkKey) {
00888 $link =& $this->links[$linkKey];
00889
00890
00891 if (!$link->enabled || !$link->linkUpdate || !isset($row[$link->mappingName]) || !is_array($row[$link->mappingName])) {
00892 continue;
00893 }
00894
00895 if (!$link->saveAssocData($row[$link->mappingName], $pkv)) {
00896 $this->dbo->completeTrans(false);
00897 return false;
00898 }
00899 }
00900 }
00901
00902 $this->_updateCounterCache($row);
00903
00904
00905 $this->dbo->completeTrans();
00906
00907 $this->_afterUpdateDb($row);
00908
00909 return true;
00910 }
00911
00920 function updateRowset(& $rowset, $saveLinks = true)
00921 {
00922 $this->dbo->startTrans();
00923 foreach ($rowset as $row) {
00924 if (!$this->update($row, $saveLinks, false)) {
00925 $this->dbo->completeTrans(false);
00926 return false;
00927 }
00928 }
00929 $this->dbo->completeTrans();
00930 return true;
00931 }
00932
00943 function updateByConditions($conditions, & $row)
00944 {
00945 $whereby = $this->getWhere($conditions, false);
00946 $this->_setUpdatedTimeFields($row);
00947
00948 list($pairs, $values) = $this->dbo->getPlaceholderPair($row, $this->fields);
00949 $pairs = implode(',', $pairs);
00950 $sql = "UPDATE {$this->qtableName} SET {$pairs} {$whereby}";
00951 return $this->dbo->execute($sql, $values);
00952 }
00953
00965 function updateField($conditions, $field, $value)
00966 {
00967 $row = array($field => $value);
00968 return $this->updateByConditions($conditions, $row);
00969 }
00970
00982 function incrField($conditions, $field, $incr = 1)
00983 {
00984 $field = $this->dbo->qfield($field, $this->fullTableName, $this->schema);
00985 $incr = (int)$incr;
00986
00987 $row = array();
00988 $this->_setUpdatedTimeFields($row);
00989 list($pairs, $values) = $this->dbo->getPlaceholderPair($row, $this->fields);
00990 $pairs = implode(',', $pairs);
00991 if ($pairs) {
00992 $pairs = ', ' . $pairs;
00993 }
00994
00995 $whereby = $this->getWhere($conditions, false);
00996 $sql = "UPDATE {$this->qtableName} SET {$field} = {$field} + {$incr}{$pairs} {$whereby}";
00997 return $this->dbo->execute($sql, $values);
00998 }
00999
01011 function decrField($conditions, $field, $decr = 1)
01012 {
01013 $field = $this->dbo->qfield($field, $this->fullTableName, $this->schema);
01014 $decr = (int)$decr;
01015
01016 $row = array();
01017 $this->_setUpdatedTimeFields($row);
01018 list($pairs, $values) = $this->dbo->getPlaceholderPair($row, $this->fields);
01019 $pairs = implode(',', $pairs);
01020 if ($pairs) {
01021 $pairs = ', ' . $pairs;
01022 }
01023
01024 $whereby = $this->getWhere($conditions, false);
01025 $sql = "UPDATE {$this->qtableName} SET {$field} = {$field}- {$decr}{$pairs} {$whereby}";
01026 return $this->dbo->execute($sql, $values);
01027 }
01028
01039 function create(& $row, $saveLinks = true)
01040 {
01041 if (!$this->_beforeCreate($row)) {
01042 return false;
01043 }
01044
01045
01046 $this->_setCreatedTimeFields($row);
01047
01048
01049 $mpk = strtoupper($this->primaryKey);
01050 $insertId = null;
01051 $unsetpk = true;
01052 if (isset($this->meta[$mpk]['autoIncrement']) && $this->meta[$mpk]['autoIncrement'])
01053 {
01054 if (isset($row[$this->primaryKey])) {
01055 if (empty($row[$this->primaryKey])) {
01056
01057
01058 unset($row[$this->primaryKey]);
01059 } else {
01060 $unsetpk = false;
01061 }
01062 }
01063 } else {
01064
01065 if (!isset($row[$this->primaryKey]) || empty($row[$this->primaryKey])) {
01066 $insertId = $this->newInsertId();
01067 $row[$this->primaryKey] = $insertId;
01068 } else {
01069
01070 $insertId = $row[$this->primaryKey];
01071 $unsetpk = false;
01072 }
01073 }
01074
01075
01076 if ($this->autoValidating && $this->verifier != null) {
01077 if (!$this->checkRowData($row)) {
01078 FLEA::loadClass('FLEA_Exception_ValidationFailed');
01079 __THROW(new FLEA_Exception_ValidationFailed($this->getLastValidation(), $row));
01080 return false;
01081 }
01082 }
01083
01084
01085 $this->dbo->startTrans();
01086
01087 if (!$this->_beforeCreateDb($row)) {
01088 if ($unsetpk) { unset($row[$this->primaryKey]); }
01089 $this->dbo->completeTrans(false);
01090 return false;
01091 }
01092
01093
01094 list($holders, $values) = $this->dbo->getPlaceholder($row, $this->fields);
01095 $holders = implode(',', $holders);
01096 $fields = $this->dbo->qfields(array_keys($values));
01097 $sql = "INSERT INTO {$this->qtableName} ({$fields}) VALUES ({$holders})";
01098
01099
01100 if (!$this->dbo->Execute($sql, $values, true)) {
01101 if ($unsetpk) { unset($row[$this->primaryKey]); }
01102 $this->dbo->completeTrans(false);
01103 return false;
01104 }
01105
01106
01107 if (is_null($insertId)) {
01108 $insertId = $this->dbo->insertId();
01109 if (!$insertId) {
01110 if ($unsetpk) { unset($row[$this->primaryKey]); }
01111 $this->dbo->completeTrans(false);
01112 FLEA::loadClass('FLEA_Db_Exception_InvalidInsertID');
01113 return __THROW(new FLEA_Db_Exception_InvalidInsertID());
01114 }
01115 }
01116
01117
01118 if ($this->autoLink && $saveLinks) {
01119 foreach (array_keys($this->links) as $linkKey) {
01120 $link =& $this->links[$linkKey];
01121
01122 if (!$link->enabled || !$link->linkCreate || !isset($row[$link->mappingName]) || !is_array($row[$link->mappingName])) {
01123
01124 continue;
01125 }
01126
01127 if (!$link->saveAssocData($row[$link->mappingName], $insertId)) {
01128 if ($unsetpk) { unset($row[$this->primaryKey]); }
01129 $this->dbo->completeTrans(false);
01130 return false;
01131 }
01132 }
01133 }
01134
01135 $row[$this->primaryKey] = $insertId;
01136 $this->_updateCounterCache($row);
01137
01138
01139 $this->dbo->CompleteTrans();
01140
01141 $this->_afterCreateDb($row);
01142 if ($unsetpk) { unset($row[$this->primaryKey]); }
01143
01144 return $insertId;
01145 }
01146
01155 function createRowset(& $rowset, $saveLinks = true)
01156 {
01157 $insertids = array();
01158 $this->dbo->startTrans();
01159 foreach ($rowset as $row) {
01160 $insertid = $this->create($row, $saveLinks, false);
01161 if (!$insertid) {
01162 $this->dbo->completeTrans(false);
01163 return false;
01164 }
01165 $insertids[] = $insertid;
01166 }
01167 $this->dbo->completeTrans();
01168 return $insertids;
01169 }
01170
01180 function remove(& $row)
01181 {
01182 if (!$this->_beforeRemove($row)) {
01183 return false;
01184 }
01185
01186 if (!isset($row[$this->primaryKey])) {
01187 FLEA::loadClass('FLEA_Db_Exception_MissingPrimaryKey');
01188 __THROW(new FLEA_Db_Exception_MissingPrimaryKey($this->primaryKey));
01189 return false;
01190 }
01191 $ret = $this->removeByPkv($row[$this->primaryKey]);
01192 if ($ret) {
01193 $this->_afterRemoveDb($row);
01194 }
01195 return $ret;
01196 }
01197
01207 function removeByPkv($pkv)
01208 {
01209 $this->dbo->startTrans();
01210
01211 if (!$this->_beforeRemoveDbByPkv($pkv)) {
01212 $this->dbo->completeTrans(false);
01213 return false;
01214 }
01215
01219 $qpkv = $this->dbo->qstr($pkv);
01220
01221
01222 $counterCacheLinks = array();
01223 if ($this->autoLink) {
01224 foreach (array_keys($this->links) as $linkKey) {
01225 $link =& $this->links[$linkKey];
01226
01227 if (!$link->enabled) { continue; }
01228 switch ($link->type) {
01229 case MANY_TO_MANY:
01230
01231 if (!$link->deleteMiddleTableDataByMainForeignKey($qpkv)) {
01232 $this->dbo->completeTrans(false);
01233 return false;
01234 }
01235 break;
01236 case HAS_ONE:
01237 case HAS_MANY:
01244
01245 if ($link->deleteByForeignKey($qpkv) === false) {
01246 $this->dbo->completeTrans(false);
01247 return false;
01248 }
01249 break;
01250 case BELONGS_TO:
01251 if ($link->counterCache) {
01252 $counterCacheLinks[] = $link->foreignKey;
01253 }
01254 }
01255 }
01256 }
01257
01258 if (!empty($counterCacheLinks)) {
01259 $counterCacheLinks[] = $this->primaryKey;
01260 $row = $this->find(array($this->primaryKey => $pkv), null, $counterCacheLinks, false);
01261 }
01262
01263
01264 $sql = "DELETE FROM {$this->qtableName} WHERE {$this->qpk} = {$qpkv}";
01265 if ($this->dbo->execute($sql) == false) {
01266 $this->dbo->completeTrans(false);
01267 return false;
01268 }
01269
01270 if (!empty($counterCacheLinks)) {
01271 $this->_updateCounterCache($row);
01272 }
01273
01274
01275 $this->dbo->completeTrans();
01276
01277 $this->_afterRemoveDbByPkv($pkv);
01278
01279 return true;
01280 }
01281
01289 function removeByConditions($conditions)
01290 {
01291 $rowset = $this->findAll($conditions, null, null, $this->primaryKey, false);
01292 $count = 0;
01293 $this->dbo->startTrans();
01294 foreach ($rowset as $row) {
01295 if (!$this->removeByPkv($row[$this->primaryKey], false)) { break; }
01296 $count++;
01297 }
01298 $this->dbo->completeTrans();
01299 $rows = $this->dbo->affectedRows();
01300 if ($rows > 0) { return $count; }
01301 return 0;
01302 }
01303
01311 function removeByPkvs($pkvs)
01312 {
01313 $ret = true;
01314 $this->dbo->startTrans();
01315 foreach ($pkvs as $id) {
01316 $ret = $this->removeByPkv($id, false);
01317 if ($ret === false) { break; }
01318 }
01319 $this->dbo->completeTrans();
01320 return $ret;
01321 }
01322
01328 function removeAll()
01329 {
01330 $sql = "DELETE FROM {$this->qtableName}";
01331 $ret = $this->execute($sql);
01332 return $ret;
01333 }
01334
01340 function removeAllWithLinks()
01341 {
01342 $this->dbo->startTrans();
01343
01344
01345 if ($this->autoLink) {
01346 foreach (array_keys($this->links) as $linkKey) {
01347 $link =& $this->links[$linkKey];
01348
01349 switch ($link->type) {
01350 case MANY_TO_MANY:
01351
01352 $link->init();
01353 $sql = "DELETE FROM {$link->qjoinTable}";
01354 break;
01355 case HAS_ONE:
01356 case HAS_MANY:
01357 $link->init();
01358 $sql = "DELETE FROM {$link->assocTDG->qtableName}";
01359 break;
01360 default:
01361 continue;
01362 }
01363 if ($this->dbo->execute($sql) == false) {
01364 $this->dbo->completeTrans(false);
01365 return false;
01366 }
01367 }
01368 }
01369
01370 $sql = "DELETE FROM {$this->qtableName}";
01371 if ($this->dbo->execute($sql) == false) {
01372 $this->dbo->completeTrans(false);
01373 return false;
01374 }
01375
01376
01377 $this->dbo->completeTrans();
01378
01379 return true;
01380 }
01381
01387 function enableLinks($links = null)
01388 {
01389 $this->autoLink = true;
01390 if (is_null($links)) {
01391 $links = array_keys($this->links);
01392 } elseif (!is_array($links)) {
01393 $links = explode(',', $links);
01394 $links = array_filter(array_map('trim', $links), 'strlen');
01395 }
01396
01397 foreach ($links as $name) {
01398 $name = strtoupper($name);
01399 if (isset($this->links[$name])) {
01400 $this->links[$name]->enabled = true;
01401 }
01402 }
01403 }
01404
01413 function enableLink($linkName)
01414 {
01415 $link =& $this->getLink($linkName);
01416 if ($link) { $link->enabled = true; }
01417 $this->autoLink = true;
01418 return $link;
01419 }
01420
01426 function disableLinks($links = null)
01427 {
01428 if (is_null($links)) {
01429 $links = array_keys($this->links);
01430 $this->autoLink = false;
01431 } elseif (!is_array($links)) {
01432 $links = explode(',', $links);
01433 $links = array_filter(array_map('trim', $links), 'strlen');
01434 }
01435
01436 foreach ($links as $name) {
01437 $name = strtoupper($name);
01438 if (isset($this->links[$name])) {
01439 $this->links[$name]->enabled = false;
01440 }
01441 }
01442 }
01443
01451 function disableLink($linkName)
01452 {
01453 $link =& $this->getLink($linkName);
01454 if ($link) { $link->enabled = false; }
01455 return $link;
01456 }
01457
01461 function clearLinks()
01462 {
01463 $this->links = array();
01464 }
01465
01469 function relink()
01470 {
01471 $this->clearLinks();
01472 $this->createLink($this->hasOne, HAS_ONE);
01473 $this->createLink($this->belongsTo, BELONGS_TO);
01474 $this->createLink($this->hasMany, HAS_MANY);
01475 $this->createLink($this->manyToMany, MANY_TO_MANY);
01476 }
01477
01485 function & getLink($linkName)
01486 {
01487 $linkName = strtoupper($linkName);
01488 if (isset($this->links[$linkName])) {
01489 return $this->links[$linkName];
01490 }
01491
01492 FLEA::loadClass('FLEA_Db_Exception_MissingLink');
01493 __THROW(new FLEA_Db_Exception_MissingLink($linkName));
01494 $ret = false;
01495 return $ret;
01496 }
01497
01505 function & getLinkTable($linkName)
01506 {
01507 $link =& $this->getLink($linkName);
01508 $link->init();
01509 return $link->assocTDG;
01510 }
01511
01519 function & existsLink($name)
01520 {
01521 $name = strtoupper($name);
01522 return isset($this->links[$name]);
01523 }
01524
01533 function createLink($defines, $type)
01534 {
01535 if (!is_array($defines)) { return; }
01536 if (!is_array(reset($defines))) {
01537 $defines = array($defines);
01538 }
01539
01540
01541 foreach ($defines as $define) {
01542 if (!is_array($define)) { continue; }
01543
01544 $link =& FLEA_Db_TableLink::createLink($define, $type, $this);
01545 $this->links[strtoupper($link->name)] =& $link;
01546 }
01547 }
01548
01554 function removeLink($linkName)
01555 {
01556 $linkName = strtoupper($linkName);
01557 if (isset($this->links[$linkName])) {
01558 unset($this->links[$linkName]);
01559 }
01560 }
01561
01572 function checkRowData(& $row, $skip = 0) {
01573 if (is_null($this->verifier)) { return false; }
01574 $this->lastValidationResult = $this->verifier->checkAll($row, $this->meta, $skip);
01575 return empty($this->lastValidationResult);
01576 }
01577
01585 function getLastValidation($info = null) {
01586 if (is_null($info)) { return $this->lastValidationResult; }
01587
01588 $arr = array();
01589 foreach ($this->lastValidationResult as $field => $check) {
01590 if (empty($check['rule'][$info])) {
01591 $arr[] = $field;
01592 } else {
01593 $arr[] = $check['rule'][$info];
01594 }
01595 }
01596 return $arr;
01597 }
01598
01604 function newInsertId() {
01605 return $this->dbo->nextId($this->fullTableName . '_seq');
01606 }
01607
01616 function execute($sql, $inputarr = false)
01617 {
01618 return $this->dbo->execute($sql, $inputarr);
01619 }
01620
01629 function qinto($sql, $params = null)
01630 {
01631 if (!is_array($params)) {
01632 FLEA::loadClass('FLEA_Exception_TypeMismatch');
01633 return __THROW(new FLEA_Exception_TypeMismatch('$params', 'array', gettype($params)));
01634 }
01635 $arr = explode('?', $sql);
01636 $sql = array_shift($arr);
01637 foreach ($params as $value) {
01638 $sql .= $this->dbo->qstr($value) . array_shift($arr);
01639 }
01640 return $sql;
01641 }
01642
01662 function parseWhere($where, $args = null)
01663 {
01664 if (!is_array($args)) {
01665 $args = array();
01666 }
01667 if (is_array($where)) {
01668 return $this->_parseWhereArray($where);
01669 } else {
01670 return $this->_parseWhereString($where, $args);
01671 }
01672 }
01673
01681 function _parseWhereArray($where)
01682 {
01691 $parts = array();
01692 $callback = array($this->dbo, 'qstr');
01693 $next_op = '';
01694
01695 foreach ($where as $key => $value) {
01696 if (is_int($key)) {
01697 $parts[] = $value;
01698 if ($value == ')') {
01699 $next_op = 'AND';
01700 } else {
01701 $next_op = '';
01702 }
01703 } else {
01704 if ($next_op != '') {
01705 $parts[] = $next_op;
01706 }
01707 $field = $this->_parseWhereQfield(array('', $key));
01708 if (is_array($value)) {
01709 $value = array_map($callback, $value);
01710 $parts[] = $field . ' IN (' . implode(',', $value) . ')';
01711 } else {
01712 $value = $this->dbo->qstr($value);
01713 $parts[] = $field . ' = ' . $value;
01714 }
01715 $next_op = 'AND';
01716 }
01717 }
01718
01719 return implode(' ', $parts);
01720 }
01721
01730 function _parseWhereString($where, $args = null)
01731 {
01741
01742 if (strpos($where, '[') !== false) {
01743
01744 $where = preg_replace_callback('/\[([a-z0-9_\-\.]+)\]/i', array($this, '_parseWhereQfield'), $where);
01745 }
01746
01747 return $this->qinto($where, $args);
01748 }
01749
01757 function _parseWhereQfield($matches)
01758 {
01759 $p = explode('.', $matches[1]);
01760 switch (count($p)) {
01761 case 3:
01762 list($schema, $table, $field) = $p;
01763 if ($table == $this->tableName) {
01764 $table = $this->fullTableName;
01765 }
01766 return $this->dbo->qfield($field, $table, $schema);
01767 case 2:
01768 list($table, $field) = $p;
01769 if ($table == $this->tableName) {
01770 $table = $this->fullTableName;
01771 }
01772 return $this->dbo->qfield($field, $table);
01773 default:
01774 return $this->dbo->qfield($p[0]);
01775 }
01776 }
01777
01785 function qstr($value)
01786 {
01787 return $this->dbo->qstr($value);
01788 }
01789
01798 function qfield($fieldName, $tableName = null)
01799 {
01800 if (is_null($tableName)) {
01801 $tableName = $this->fullTableName;
01802 }
01803 return $this->dbo->qfield($fieldName, $tableName, $this->schema);
01804 }
01805
01815 function qfields($fieldsName, $tableName = null, $returnArray = false)
01816 {
01817 if (is_null($tableName)) {
01818 $tableName = $this->fullTableName;
01819 }
01820 return $this->dbo->qfields($fieldsName, $tableName, $this->schema, $returnArray);
01821 }
01822
01831 function getWhere($conditions, $queryLinks = true) {
01832
01833 $where = FLEA_Db_SqlHelper::parseConditions($conditions, $this);
01834 $sqljoin = '';
01835 $distinct = '';
01836
01837 do {
01838 if (!is_array($where)) {
01839 $whereby = $where != '' ? " WHERE {$where}" : '';
01840 break;
01841 }
01842
01843 $arr = $where;
01844