/** * * @param RedBean_OODBBean $parent * @return array $childObjects */ public function children(RedBean_OODBBean $parent) { $idfield = $this->writer->getIDField($parent->getMeta("type")); try { $ids = $this->adapter->getCol("SELECT `" . $idfield . "` FROM\n\t\t\t`" . $parent->getMeta("type") . "`\n\t\t\tWHERE `" . $this->property . "` = " . intval($parent->{$idfield}) . "\n\t\t"); } catch (RedBean_Exception_SQL $e) { return array(); } return $this->oodb->batch($parent->getMeta("type"), $ids); }
/** * Returns all the nodes that have been attached to the specified * parent node. * @param RedBean_OODBBean $parent * @return array $childObjects */ public function children(RedBean_OODBBean $parent) { $idfield = $this->writer->getIDField($parent->getMeta("type")); try { $ids = $this->writer->selectByCrit($idfield, $parent->getMeta("type"), $this->property, intval($parent->{$idfield})); } catch (RedBean_Exception_SQL $e) { return array(); } return $this->oodb->batch($parent->getMeta("type"), $ids); }
/** * Given two beans this function returns TRUE if they are associated using a * many-to-many association, FALSE otherwise. * * @throws RedBean_Exception_SQL * * @param RedBean_OODBBean $bean1 bean * @param RedBean_OODBBean $bean2 bean * * @return bool $related whether they are associated N-M */ public function areRelated(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2) { if (!$bean1->getID() || !$bean2->getID()) { return false; } $table = $this->getTable(array($bean1->getMeta("type"), $bean2->getMeta("type"))); $idfield1 = $this->writer->getIDField($bean1->getMeta("type")); $idfield2 = $this->writer->getIDField($bean2->getMeta("type")); $type = $bean1->getMeta("type"); if ($type == $bean2->getMeta("type")) { $type .= "2"; $cross = 1; } else { $cross = 0; } $property1 = $type . "_id"; $property2 = $bean2->getMeta("type") . "_id"; $value1 = (int) $bean1->{$idfield1}; $value2 = (int) $bean2->{$idfield2}; try { $rows = $this->writer->selectRecord($table, array($property1 => array($value1), $property2 => array($value2)), null); if ($cross) { $rows2 = $this->writer->selectRecord($table, array($property2 => array($value1), $property1 => array($value2)), null); $rows = array_merge($rows, $rows2); } } catch (RedBean_Exception_SQL $e) { if (!$this->writer->sqlStateIn($e->getSQLState(), array(RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN, RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE))) { throw $e; } return false; } return count($rows) > 0; }
/** * * @param RedBean_OODBBean $parent * @return array $childObjects */ public function children(RedBean_OODBBean $parent) { $idfield = $this->writer->getIDField($parent->getMeta("type")); try { /* $ids = $this->adapter->getCol("SELECT `".$idfield."` FROM `".$parent->getMeta("type")."` WHERE `".$this->property."` = ".intval( $parent->$idfield )." "); */ /* $ids = $this->adapter->getCol($this->writer->buildSimpleQuery( "select",array($idfield),$parent->getMeta("type"), array("name"=>$this->property, "value"=>intval($parent->$idfield), "operator"=>"=","structure"=>"") )); */ $ids = $this->writer->selectByCrit($idfield, $parent->getMeta("type"), $this->property, intval($parent->{$idfield})); } catch (RedBean_Exception_SQL $e) { return array(); } return $this->oodb->batch($parent->getMeta("type"), $ids); }
/** * Returns all the beans associated with $bean. * This method will return an array containing all the beans that have * been associated once with the associate() function and are still * associated with the bean specified. The type parameter indicates the * type of beans you are looking for. You can also pass some extra SQL and * values for that SQL to filter your results after fetching the * related beans. * * Don't try to make use of subqueries, a subquery using IN() seems to * be slower than two queries! * * Since 3.2, you can now also pass an array of beans instead just one * bean as the first parameter. * * @param RedBean_OODBBean|array $bean the bean you have * @param string $type the type of beans you want * @param string $sql SQL snippet for extra filtering * @param array $bindings values to be inserted in SQL slots * @param boolean $glue whether the SQL should be prefixed with WHERE * * @return array */ public function relatedSimple($bean, $type, $sql = '', $bindings = array()) { $sql = $this->writer->glueSQLCondition($sql); $rows = $this->relatedRows($bean, $type, FALSE, $sql, $bindings); $links = array(); foreach ($rows as $key => $row) { if (!isset($links[$row['id']])) { $links[$row['id']] = array(); } $links[$row['id']][] = $row['linked_by']; unset($rows[$key]['linked_by']); } $beans = $this->oodb->convertToBeans($type, $rows); foreach ($beans as $bean) { $bean->setMeta('sys.belongs-to', $links[$bean->id]); } return $beans; }
/** * Loads a batch of beans all at once. * This function first inspects the cache; if every element in the batch * is available in the cache, the function will return the collected beans * from the cache. If one or more beans cannot be found, the function will * ask oodb for the beans and update the cache. * @param string $type * @param integer $ids * @return array $beans */ public function batch($type, $ids) { $idfield = $this->writer->getIDField($type); $collect = array(); foreach ($ids as $id) { $bean = $this->fetchFromCacheByTypeID($type, $id); if ($bean) { $collect[$id] = $bean; } } if (count($collect) == count($ids)) { return $collect; } else { $beans = $this->oodb->batch($type, $ids); foreach ($beans as $bean) { $this->putInCache($bean); } return $beans; } }
/** * Performs the actual optimization. In this case the optimizer looks * at the size of the column and the size of the value. If the value size is * smaller than the column size it tries to convert the column to a smaller * size. Next, it counts if there is any different between the smaller column * and the original column. If no differences are found the original column * gets replaced. * Like the other optimizers, this optimizer returns TRUE if it thinks * further optimizations can happen, FALSE otherwise. * * @return boolean $yesNo advance to next optimizer */ public function optimize() { //get the type of the current value $type = $this->writer->scanType($this->value); //get all the fields in the table $fields = $this->writer->getColumns($this->table); //If the column for some reason does not occur in fields, return if (!in_array($this->column, array_keys($fields))) { return false; } //get the type we got in the field of the table $typeInField = $this->writer->code($fields[$this->column]); //Is the type too wide? if ($type < $typeInField) { try { @$this->adapter->exec("alter table " . $this->writer->safeTable($this->table) . " drop __test"); } catch (Exception $e) { } //Try to re-fit the entire column; by testing it. $type = $this->writer->typeno_sqltype[$type]; //Add a test column. @$this->adapter->exec("alter table " . $this->writer->safeTable($this->table) . " add __test " . $type); //Copy the values and see if there are differences. @$this->adapter->exec("update " . $this->writer->safeTable($this->table) . " set __test=" . $this->writer->safeColumn($this->column) . ""); $rows = $this->adapter->get("select " . $this->writer->safeColumn($this->column) . " as a, __test as b from " . $this->writer->safeTable($this->table)); $diff = 0; foreach ($rows as $row) { $diff += $row["a"] != $row["b"]; } if (!$diff) { //No differences; shrink column. @$this->adapter->exec("alter table " . $this->writer->safeTable($this->table) . " change " . $this->writer->safeColumn($this->column) . " " . $this->writer->safeColumn($this->column) . " " . $type); } //Throw away test column; we don't need it anymore! @$this->adapter->exec("alter table " . $this->writer->safeTable($this->table) . " drop __test"); } return false; }
/** * Removes all relations for a bean * @param RedBean_OODBBean $bean * @param string $type */ public function clearRelations(RedBean_OODBBean $bean, $type) { $this->oodb->store($bean); $table = $this->getTable(array($bean->getMeta("type"), $type)); $idfield = $this->writer->getIDField($bean->getMeta("type")); if ($type == $bean->getMeta("type")) { $property2 = $type . "2_id"; $cross = 1; } else { $cross = 0; } $property = $bean->getMeta("type") . "_id"; try { $this->writer->deleteByCrit($table, array($property => $bean->{$idfield})); if ($cross) { $this->writer->deleteByCrit($table, array($property2 => $bean->{$idfield})); } } catch (RedBean_Exception_SQL $e) { if ($e->getSQLState() != "42S02" && $e->getSQLState() != "42S22") { throw $e; } } }
/** * Performs the actual optimization. In this case the optimizer first * scans the value. If the value if of type 'datetime' and the column * is not it tries to make the column datetime. If the column is 'datetime' * and the value 'datetime' it blocks further optimization. If the value * is NOT 'datetime' then it immediately returns true, thus allowing further * optimization. * * @return boolean $yesNo advance to next optimizer */ public function optimize() { if (!$this->matchesDateTime($this->value)) { return true; } //get the type of the current value $type = $this->writer->scanType($this->value); //get all the fields in the table $fields = $this->writer->getColumns($this->table); //If the column for some reason does not occur in fields, return //print_r($fields); if (!in_array($this->column, array_keys($fields))) { return false; } //get the type we got in the field of the table $typeInField = $this->writer->code($fields[$this->column]); //Is column already datetime? if ($typeInField != "datetime") { if ($this->matchesDateTime($this->value)) { //Ok, value is datetime, can we convert the column to support this? $cnt = (int) $this->adapter->getCell("select count(*) as n from " . $this->writer->safeTable($this->table) . " where\n\t\t\t\t\t\t {$this->column} regexp '[0-9]{4}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]'\n\t\t\t\t\t\t OR {$this->column} IS NULL"); $total = (int) $this->adapter->getCell("SELECT count(*) FROM " . $this->writer->safeTable($this->table)); //Is it safe to convert: ie are all values compatible? if ($total === $cnt) { //yes $this->adapter->exec("ALTER TABLE " . $this->writer->safeTable($this->table) . " change " . $this->writer->safeColumn($this->column) . " " . $this->writer->safeColumn($this->column) . " datetime "); } //No further optimization required. return false; } //Further optimization could be useful. return true; } else { //yes column is datetime, if value is stop further optimizing return false; } }
/** * Removes all relations for a bean * @param RedBean_OODBBean $bean * @param <type> $type */ public function clearRelations(RedBean_OODBBean $bean, $type) { $this->oodb->store($bean); $table = $this->getTable(array($bean->getMeta("type"), $type)); $idfield = $this->writer->getIDField($bean->getMeta("type")); if ($type == $bean->getMeta("type")) { $property2 = $type . "2_id"; $cross = 1; } else { $cross = 0; } $property = $bean->getMeta("type") . "_id"; $sql = "DELETE FROM `{$table}`\n\t\tWHERE " . $this->adapter->escape($property) . " = " . $this->adapter->escape($bean->{$idfield}); if ($cross) { $sql .= " OR " . $this->adapter->escape($property2) . " = " . $this->adapter->escape($bean->{$idfield}); } try { $this->adapter->exec($sql); } catch (RedBean_Exception_SQL $e) { if ($e->getSQLState() != "42S02" && $e->getSQLState() != "42S22") { throw $e; } } }
/** * Nukes the entire database. */ public static function nuke() { if (!self::$redbean->isFrozen()) { self::$writer->wipeAll(); } }
/** * Nukes the entire database. * This will remove all schema structures from the database. * Only works in fluid mode. Be careful with this method. * * @warning dangerous method, will remove all tables, columns etc. * * @return void */ public function nuke() { if (!$this->redbean->isFrozen()) { $this->writer->wipeAll(); } }
/** * Executes SQL function but corrects for SQL states. * @param closure $func * @param mixed $default * @param string $sql * @param array $values * @return mixed $results */ private static function secureExec($func, $sql, $values, $default = NULL) { if (!self::$redbean->isFrozen()) { try { $rs = R::$adapter->{$func}($sql, $values); } catch (RedBean_Exception_SQL $e) { //die($e); if (self::$writer->sqlStateIn($e->getSQLState(), array(RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN, RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE))) { return $default; } else { throw $e; } } return $rs; } else { return R::$adapter->{$func}($sql, $values); } }
/** * Set prefix in query writer * * @param string $prefix */ public function prefix($prefix) { $this->writer->setPrefix($prefix); }
/** * Creates a view with name $viewID based on $refType bean type * and then left-joining the specified types in $types in the given * order. * * @param string $viewID desired name of the view * @param string $refType first bean type to be used as base * @param array $types array with types to be left-joined in view * * @return boolean $success whether we created a new view (false if already exists) */ public function createView($viewID, $refType, $types) { if ($this->oodb->isFrozen()) { return false; } $history = array(); $tables = array_flip($this->writer->getTables()); $refTable = $refType; //$this->writer->safeTable($refType, true); $currentTable = $refTable; $history[$refType] = $refType; foreach ($types as $t) { if (!isset($history[$t])) { $history[$t] = $t; $connection = array($t, $currentTable); sort($connection); $connection = implode("_", $connection); $connectionTable = $this->writer->safeTable($connection, true); if (isset($tables[$connectionTable])) { //this connection exists $srcPoint = $this->writer->safeTable($connection) . "." . $this->writer->safeColumn($currentTable . "_id"); //i.e. partic_project.project_id $dstPoint = $this->writer->safeTable($currentTable) . "." . $this->writer->safeColumn($this->writer->getIDField($currentTable)); //i.e. project.id $joins[$connection] = array($srcPoint, $dstPoint); //now join the type $srcPoint = $this->writer->safeTable($connection) . "." . $this->writer->safeColumn($t . "_id"); $dstPoint = $this->writer->safeTable($t) . "." . $this->writer->safeColumn($this->writer->getIDField($t)); $joins[$t] = array($srcPoint, $dstPoint); } else { //this connection does not exist $srcPoint = $this->writer->safeTable($t) . "." . $this->writer->safeColumn($currentTable . "_id"); $dstPoint = $this->writer->safeTable($currentTable) . "." . $this->writer->safeColumn($this->writer->getIDField($currentTable)); $joins[$t] = array($srcPoint, $dstPoint); } } //now set the new refTable $currentTable = $t; } try { $rs = (bool) $this->writer->createView($refType, $joins, $viewID); } catch (Exception $e) { throw new RedBean_Exception_SQL('Could not create view, types does not seem related (yet)..'); } return $rs; }