/** * This method adds a foreign key from type and field to * target type and target field. * The foreign key is created without an action. On delete/update * no action will be triggered. The FK is only used to allow database * tools to generate pretty diagrams and to make it easy to add actions * later on. * This methods accepts a type and infers the corresponding table name. * * * @param string $type type that will have a foreign key field * @param string $targetType points to this type * @param string $field field that contains the foreign key value * @param string $targetField field where the fk points to * * @return void */ public function addFK($type, $targetType, $field, $targetField, $isDependent = FALSE) { $table = strtoupper($this->esc($type)); $tableNoQ = strtoupper($this->esc($type, TRUE)); $targetTable = strtoupper($this->esc($targetType)); $column = strtoupper($this->esc($field)); $columnNoQ = strtoupper($this->esc($field, TRUE)); $targetColumn = strtoupper($this->esc($targetField)); $targetColumnNoQ = strtoupper($this->esc($targetField, TRUE)); $fkName = 'FK_' . ($isDependent ? 'C_' : '') . $tableNoQ . '_' . $columnNoQ . '_' . $targetColumnNoQ; $fkName = $this->limitOracleIdentifierLength($fkName); $cfks = $this->adapter->getCell("\n\t\t\tSELECT A.CONSTRAINT_NAME\n\t\t FROM ALL_CONS_COLUMNS A JOIN ALL_CONSTRAINTS C ON A.CONSTRAINT_NAME = C.CONSTRAINT_NAME\n\t\t\tWHERE C.TABLE_NAME = '{$tableNoQ}' AND C.CONSTRAINT_TYPE = 'R'\tAND COLUMN_NAME='{$columnNoQ}'"); $flagAddKey = FALSE; try { // No keys if (!$cfks) { $flagAddKey = TRUE; //go get a new key } // Has fk, but different setting, --remove if ($cfks && $cfks != $fkName) { $this->adapter->exec("ALTER TABLE {$table} DROP CONSTRAINT {$cfks} "); $flagAddKey = TRUE; //go get a new key. } if ($flagAddKey) { $sql = "ALTER TABLE {$table}\n\t\t\t\tADD CONSTRAINT {$fkName} FOREIGN KEY ( {$column} ) REFERENCES {$targetTable} (\n\t\t\t\t{$targetColumn}) ON DELETE " . ($isDependent ? 'CASCADE' : 'SET NULL'); $this->adapter->exec($sql); } } catch (Exception $e) { // Failure of fk-constraints is not a problem } }
/** * Gets information about changed records using a type and id and a logid. * RedBean Locking shields you from race conditions by comparing the latest * cached insert id with a the highest insert id associated with a write action * on the same table. If there is any id between these two the record has * been changed and RedBean will throw an exception. This function checks for changes. * If changes have occurred it will throw an exception. If no changes have occurred * it will insert a new change record and return the new change id. * This method locks the log table exclusively. * @param string $type * @param integer $id * @param integer $logid * @return integer $newchangeid */ public function checkChanges($type, $id, $logid) { $type = $this->writer->check($type); $id = (int) $id; $logid = (int) $logid; $num = $this->adapter->getCell("\n SELECT count(*) FROM __log WHERE tbl=\"{$type}\" AND itemid={$id} AND action=2 AND id > {$logid}"); if ($num) { throw new RedBean_Exception_FailedAccessBean("Locked, failed to access (type:{$type}, id:{$id})"); } $this->adapter->exec("INSERT INTO __log (id,action,tbl,itemid) VALUES(NULL, 2,:tbl,:id)", array(":tbl" => $type, ":id" => $id)); $newid = $this->adapter->getInsertID(); if ($this->adapter->getCell("select id from __log where tbl=:tbl AND id < {$newid} and id > {$logid} and action=2 and itemid={$id} ", array(":tbl" => $type))) { throw new RedBean_Exception_FailedAccessBean("Locked, failed to access II (type:{$type}, id:{$id})"); } return $newid; }
/** * Magic method to construct SQL query. * Accepts any kind of message and turns it into an SQL statement and * adds it to the query string. * If camelcase is set to TRUE camelCase transitions will be turned into spaces. * Underscores will be replaced with spaces as well. * Arguments will be imploded using a comma as glue character and are also added * to the query. * * If capture mode is on, this method returns a reference to itself allowing * chaining. * * If capture mode if off, this method will immediately exceute the resulting * SQL query and return a string result. * * @param string $funcName name of the next SQL statement/keyword * @param array $args list of statements to be seperated by commas * * @return string|RedBean_SQLHelper */ public function __call($funcName, $args = array()) { if (self::$flagUseCamelCase) { static $funcCache = array(); if (!isset($funcCache[$funcName])) { $funcCache[$funcName] = strtolower(preg_replace('/(?<=[a-z])([A-Z])|([A-Z])(?=[a-z])/', '_$1$2', $funcName)); } $funcName = $funcCache[$funcName]; } $funcName = str_replace('_', ' ', $funcName); if ($this->capture) { $this->sql .= ' ' . $funcName . ' ' . implode(',', $args); return $this; } else { return $this->adapter->getCell('SELECT ' . $funcName . '(' . implode(',', $args) . ')'); } }
/** * Magic method to construct SQL query * * @param string $funcName name of the next SQL statement/keyword * @param array $args list of statements to be seperated by commas * * @return mixed $result either self or result depending on mode */ public function __call($funcName, $args = array()) { $funcName = str_replace('_', ' ', $funcName); if ($this->capture) { $this->sql .= ' ' . $funcName . ' ' . implode(',', $args); return $this; } else { return $this->adapter->getCell('SELECT ' . $funcName . '(' . implode(',', $args) . ')'); } }