/** * Persist new or changed objects to the database container. * * Inserts or updates the database record representing this object and any * new or changed related object records. Both aggregate and composite * related objects will be saved as appropriate, before or following the * save operation on the controlling instance. * * @param boolean|integer $cacheFlag Indicates if the saved object(s) should * be cached and optionally, by specifying an integer value, for how many * seconds before expiring. Overrides the cacheFlag for the object(s). * @return boolean Returns true on success, false on failure. */ public function save($cacheFlag = null) { if ($this->isLazy()) { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Attempt to save lazy object: ' . print_r($this->toArray('', true), 1)); return false; } $result = true; $sql = ''; $pk = $this->getPrimaryKey(); $pkn = $this->getPK(); $pkGenerated = false; if ($this->isNew()) { $this->setDirty(); } if ($this->getOption(xPDO::OPT_VALIDATE_ON_SAVE)) { if (!$this->validate()) { return false; } } if (!$this->xpdo->getConnection(array(xPDO::OPT_CONN_MUTABLE => true))) { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not get connection for writing data", '', __METHOD__, __FILE__, __LINE__); return false; } $this->_saveRelatedObjects(); if (!empty($this->_dirty)) { $cols = array(); $bindings = array(); $updateSql = array(); foreach (array_keys($this->_dirty) as $_k) { if (!array_key_exists($_k, $this->_fieldMeta)) { continue; } if (isset($this->_fieldMeta[$_k]['generated'])) { if (!$this->_new || !isset($this->_fields[$_k]) || empty($this->_fields[$_k])) { $pkGenerated = true; continue; } } if ($this->_fieldMeta[$_k]['phptype'] === 'password') { $this->_fields[$_k] = $this->encode($this->_fields[$_k], 'password'); } $fieldType = PDO::PARAM_STR; $fieldValue = $this->_fields[$_k]; if (in_array($this->_fieldMeta[$_k]['phptype'], array('datetime', 'timestamp')) && !empty($this->_fieldMeta[$_k]['attributes']) && $this->_fieldMeta[$_k]['attributes'] == 'ON UPDATE CURRENT_TIMESTAMP') { $this->_fields[$_k] = strftime('%Y-%m-%d %H:%M:%S'); continue; } elseif ($fieldValue === null || $fieldValue === 'NULL') { if ($this->_new) { continue; } $fieldType = PDO::PARAM_NULL; $fieldValue = null; } elseif (in_array($this->_fieldMeta[$_k]['phptype'], array('timestamp', 'datetime')) && in_array($fieldValue, $this->xpdo->driver->_currentTimestamps, true)) { $this->_fields[$_k] = strftime('%Y-%m-%d %H:%M:%S'); continue; } elseif (in_array($this->_fieldMeta[$_k]['phptype'], array('date')) && in_array($fieldValue, $this->xpdo->driver->_currentDates, true)) { $this->_fields[$_k] = strftime('%Y-%m-%d'); continue; } elseif ($this->_fieldMeta[$_k]['phptype'] == 'timestamp' && preg_match('/int/i', $this->_fieldMeta[$_k]['dbtype'])) { $fieldType = PDO::PARAM_INT; } elseif (!in_array($this->_fieldMeta[$_k]['phptype'], array('string', 'password', 'datetime', 'timestamp', 'date', 'time', 'array', 'json', 'float'))) { $fieldType = PDO::PARAM_INT; } if ($this->_new) { $cols[$_k] = $this->xpdo->escape($_k); $bindings[":{$_k}"]['value'] = $fieldValue; $bindings[":{$_k}"]['type'] = $fieldType; } else { $bindings[":{$_k}"]['value'] = $fieldValue; $bindings[":{$_k}"]['type'] = $fieldType; $updateSql[] = $this->xpdo->escape($_k) . " = :{$_k}"; } } if ($this->_new) { $sql = "INSERT INTO {$this->_table} (" . implode(', ', array_values($cols)) . ") VALUES (" . implode(', ', array_keys($bindings)) . ")"; } else { if ($pk && $pkn) { if (is_array($pkn)) { $iteration = 0; $where = ''; foreach ($pkn as $k => $v) { $vt = PDO::PARAM_INT; if (in_array($this->_fieldMeta[$k]['phptype'], array('string', 'float'))) { $vt = PDO::PARAM_STR; } if ($iteration) { $where .= " AND "; } $where .= $this->xpdo->escape($k) . " = :{$k}"; $bindings[":{$k}"]['value'] = $this->_fields[$k]; $bindings[":{$k}"]['type'] = $vt; $iteration++; } } else { $pkn = $this->getPK(); $pkt = PDO::PARAM_INT; if (in_array($this->_fieldMeta[$pkn]['phptype'], array('string', 'float'))) { $pkt = PDO::PARAM_STR; } $bindings[":{$pkn}"]['value'] = $pk; $bindings[":{$pkn}"]['type'] = $pkt; $where = $this->xpdo->escape($pkn) . ' = :' . $pkn; } if (!empty($updateSql)) { $sql = "UPDATE {$this->_table} SET " . implode(',', $updateSql) . " WHERE {$where}"; } } } if (!empty($sql) && ($criteria = new xPDOCriteria($this->xpdo, $sql))) { if ($criteria->prepare()) { if (!empty($bindings)) { $criteria->bind($bindings, true, false); } if ($this->xpdo->getDebug() === true) { $this->xpdo->log(xPDO::LOG_LEVEL_DEBUG, "Executing SQL:\n{$sql}\nwith bindings:\n" . print_r($bindings, true)); } $tstart = microtime(true); if (!($result = $criteria->stmt->execute())) { $this->xpdo->queryTime += microtime(true) - $tstart; $this->xpdo->executedQueries++; $errorInfo = $criteria->stmt->errorInfo(); $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error " . $criteria->stmt->errorCode() . " executing statement:\n" . $criteria->toSQL() . "\n" . print_r($errorInfo, true)); if (($errorInfo[1] == '1146' || $errorInfo[1] == '1') && $this->getOption(xPDO::OPT_AUTO_CREATE_TABLES)) { if ($this->xpdo->getManager() && $this->xpdo->manager->createObjectContainer($this->_class) === true) { $tstart = microtime(true); if (!($result = $criteria->stmt->execute())) { $this->xpdo->queryTime += microtime(true) - $tstart; $this->xpdo->executedQueries++; $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error " . $criteria->stmt->errorCode() . " executing statement:\n{$sql}\n"); } else { $this->xpdo->queryTime += microtime(true) - $tstart; $this->xpdo->executedQueries++; } } else { $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error " . $this->xpdo->errorCode() . " attempting to create object container for class {$this->_class}:\n" . print_r($this->xpdo->errorInfo(), true)); } } } else { $this->xpdo->queryTime += microtime(true) - $tstart; $this->xpdo->executedQueries++; } } else { $result = false; } if ($result) { if ($pkn && !$pk) { if ($pkGenerated) { $this->_fields[$this->getPK()] = $this->xpdo->lastInsertId(); } $pk = $this->getPrimaryKey(); } if ($pk || !$this->getPK()) { $this->_dirty = array(); $this->_validated = array(); $this->_new = false; } $callback = $this->getOption(xPDO::OPT_CALLBACK_ON_SAVE); if ($callback && is_callable($callback)) { call_user_func($callback, array('className' => $this->_class, 'criteria' => $criteria, 'object' => $this)); } if ($this->xpdo->_cacheEnabled && $pk && ($cacheFlag || $cacheFlag === null && $this->_cacheFlag)) { $cacheKey = $this->xpdo->newQuery($this->_class, $pk, $cacheFlag); if (is_bool($cacheFlag)) { $expires = 0; } else { $expires = intval($cacheFlag); } $this->xpdo->toCache($cacheKey, $this, $expires, array('modified' => true)); } } } } $this->_saveRelatedObjects(); if ($result) { $this->_dirty = array(); $this->_validated = array(); } return $result; }
$disThread = $modx->getTableName('disThread'); $bindings = array(); $sql = "INSERT INTO {$disRead} ({$modx->getSelectColumns('disThreadRead', '', '', array('user', 'board', 'thread'))}) "; $cSub = $modx->newQuery('disThread'); $cSub->select(array(1 => "({$userId})", $modx->getSelectColumns('disThread', 'disThread', '', array('board', 'id')))); if (!empty($scriptProperties['lastLogin'])) { $cSub->where(array('post_last_on:>=' => strtotime($scriptProperties['lastLogin']))); if ($scriptProperties['ts'] !== false) { $cSub->where(array('post_last_on:<' => $scriptProperties['ts'])); } } else { if (!empty($scriptProperties['replies'])) { $cSub->innerJoin('disThreadParticipant', 'Participants', array("{$modx->escape('Participants')}.{$modx->escape('user')} = {$userId}", "{$modx->escape('Participants')}.{$modx->escape('thread')} = {$modx->escape('disThread')}.{$modx->escape('id')}")); $cSub->where(array('author_last:!=' => $userId)); } } $cSub->where(array("{$modx->escape('disThread')}.{$modx->escape('id')} NOT IN ({$disReadSub->toSQL()})", 'private' => 0)); $cSub->prepare(); $sql .= $cSub->toSQL(); $criteria = new xPDOCriteria($modx, $sql); if ($criteria->prepare()) { if (!empty($bindings)) { $criteria->bind($bindings, true, false); } if (!$criteria->stmt->execute()) { $errorInfo = $criteria->stmt->errorInfo(); $modx->log(xPDO::LOG_LEVEL_ERROR, "Error " . $criteria->stmt->errorCode() . " executing statement:\n" . $criteria->toSQL() . "\n" . print_r($errorInfo, true)); return false; } } return true;