/** * Does an optimization cycle for each UPDATE event. * * @param string $event event * @param RedBean_OODBBean $bean bean * * @return void */ public function onEvent($event, $bean) { try { if ($event == "update") { //export the bean as an array $arr = $bean->export(); //print_r($arr); //remove the id property unset($arr["id"]); //If we are left with an empty array we might as well return if (count($arr) == 0) { return; } //fetch table name for this bean //get the column names for this table $table = $bean->getMeta("type"); $columns = array_keys($arr); //Select a random column for optimization. $column = $columns[array_rand($columns)]; //get the value to be optimized $value = $arr[$column]; $this->optimize($table, $column, $value); } } catch (RedBean_Exception_SQL $e) { } }
public static function getKeys(RedBean_OODBBean $bean, $typeName) { $fieldName = self::getLinkField($typeName); $id = (int) $bean->{$fieldName}; $ids = R::getCol("select id from {$typeName} where " . $bean->getMeta("type") . "_id" . " = {$bean->id}"); return $ids; }
/** * Throws an exception if information in the bean has been changed * by another process or bean. This is actually the same as journaling * using timestamps however with timestamps you risk race conditions * when the measurements are not fine-grained enough; with * auto-incremented primary key ids we dont have this risk. * @param string $event * @param RedBean_OODBBean $item */ public function onEvent($event, $item) { $id = $item->id; if (!(int) $id) { $event = "open"; } $type = $item->getMeta("type"); if ($event == "open") { if (isset($this->stash[$id])) { $insertid = $this->stash[$id]; unset($this->stash[$id]); return $insertid; } $insertid = $this->writer->insertRecord("__log", array("action", "tbl", "itemid"), array(array(1, $type, $id))); $item->setMeta("opened", $insertid); } if ($event == "update" || $event == "delete") { if ($item->getMeta("opened")) { $oldid = $item->getMeta("opened"); } else { $oldid = 0; } $newid = $this->checkChanges($type, $id, $oldid); $item->setMeta("opened", $newid); } }
/** * Does an optimization cycle for each UPDATE event * @param string $event * @param RedBean_OODBBean $bean */ public function onEvent($event, $bean) { try { if ($event == "update") { $arr = $bean->export(); unset($arr["id"]); if (count($arr) == 0) { return; } $table = $this->adapter->escape($bean->getMeta("type")); $columns = array_keys($arr); $column = $this->adapter->escape($columns[array_rand($columns)]); $value = $arr[$column]; $type = $this->writer->scanType($value); $fields = $this->writer->getColumns($table); if (!in_array($column, array_keys($fields))) { return; } $typeInField = $this->writer->code($fields[$column]); if ($type < $typeInField) { $type = $this->writer->typeno_sqltype[$type]; $this->adapter->exec("alter table `{$table}` add __test " . $type); $this->adapter->exec("update `{$table}` set __test=`{$column}`"); $diff = $this->adapter->getCell("select\n\t\t\t\t\t\t\tcount(*) as df from `{$table}` where\n\t\t\t\t\t\t\tstrcmp(`{$column}`,__test) != 0"); if (!$diff) { $this->adapter->exec("alter table `{$table}` change `{$column}` `{$column}` " . $type); } $this->adapter->exec("alter table `{$table}` drop __test"); } } } catch (RedBean_Exception_SQL $e) { //optimizer might make mistakes, dont care.. } }
/** * Ensures that given an association between * $bean1 and $bean2, * if one of them gets trashed the association will be * automatically removed. * @param RedBean_OODBBean $bean1 * @param RedBean_OODBBean $bean2 * @return boolean $addedFKS */ public static function addConstraint(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2, $dontCache = false) { //Fetch the toolbox $toolbox = RedBean_Setup::getToolBox(); RedBean_CompatManager::scanDirect($toolbox, array(RedBean_CompatManager::C_SYSTEM_MYSQL => "5")); //Create an association manager $association = new RedBean_AssociationManager($toolbox); $writer = $toolbox->getWriter(); $oodb = $toolbox->getRedBean(); $adapter = $toolbox->getDatabaseAdapter(); //Frozen? Then we may not alter the schema! if ($oodb->isFrozen()) { return false; } //$adapter->getDatabase()->setDebugMode(1); $table1 = $bean1->getMeta("type"); $table2 = $bean2->getMeta("type"); $table = $association->getTable(array($table1, $table2)); $idfield1 = $writer->getIDField($bean1->getMeta("type")); $idfield2 = $writer->getIDField($bean2->getMeta("type")); $bean = $oodb->dispense($table); $property1 = $bean1->getMeta("type") . "_id"; $property2 = $bean2->getMeta("type") . "_id"; if ($property1 == $property2) { $property2 = $bean2->getMeta("type") . "2_id"; } $table = $adapter->escape($table); $table1 = $adapter->escape($table1); $table2 = $adapter->escape($table2); $property1 = $adapter->escape($property1); $property2 = $adapter->escape($property2); //In Cache? Then we dont need to bother if (isset(self::$fkcache[$table])) { return false; } $db = $adapter->getCell("select database()"); $fks = $adapter->getCell("\n\t\t\tSELECT count(*)\n\t\t\tFROM information_schema.KEY_COLUMN_USAGE\n\t\t\tWHERE TABLE_SCHEMA ='{$db}' AND TABLE_NAME ='{$table}' AND\n\t\t\tCONSTRAINT_NAME <>'PRIMARY' AND REFERENCED_TABLE_NAME is not null\n\t\t"); //already foreign keys added in this association table if ($fks > 0) { return false; } //add the table to the cache, so we dont have to fire the fk query all the time. if (!$dontCache) { self::$fkcache[$table] = true; } $columns = $writer->getColumns($table); if ($writer->code($columns[$property1]) !== RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32) { $writer->widenColumn($table, $property1, RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32); } if ($writer->code($columns[$property2]) !== RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32) { $writer->widenColumn($table, $property2, RedBean_QueryWriter_MySQL::C_DATATYPE_UINT32); } $sql = "\n\t\t\tALTER TABLE " . $writer->noKW($table) . "\n\t\t\tADD FOREIGN KEY({$property1}) references {$table1}(id) ON DELETE CASCADE;\n\n\t\t"; $adapter->exec($sql); $sql = "\n\t\t\tALTER TABLE " . $writer->noKW($table) . "\n\t\t\tADD FOREIGN KEY({$property2}) references {$table2}(id) ON DELETE CASCADE\n\t\t"; $adapter->exec($sql); return true; }
/** * * @param RedBean_OODBBean $parent * @return array $childObjects */ public function children(RedBean_OODBBean $parent) { try { $ids = $this->adapter->getCol("SELECT id FROM\n\t\t\t`" . $parent->getMeta("type") . "`\n\t\t\tWHERE `" . $this->property . "` = " . intval($parent->id) . "\n\t\t"); } catch (RedBean_Exception_SQL $e) { return array(); } return $this->oodb->batch($parent->getMeta("type"), $ids); }
public static function getKeys(RedBean_OODBBean $bean, $typeName, $name = null) { $fieldName = self::getLinkField($typeName, $name); $id = (int) $bean->{$fieldName}; $columnPrefix = self::resolveColumnPrefix($name); $columnName = $columnPrefix . $bean->getMeta("type") . '_id'; $ids = ZurmoRedBean::getCol("select id from {$typeName} where " . $columnName . " = {$bean->id}"); return $ids; }
private function boxIfModel(\RedBean_OODBBean $bean) { $model = $bean->box(); if (!$model instanceof Model) { return $bean; } $model->bindApp($this->app); return $model; }
/** * 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); }
/** * Tests whether getID never produces a notice. * * @return void */ public function testGetIDShouldNeverPrintNotice() { set_error_handler(function ($err, $errStr) { die('>>>>FAIL :' . $err . ' ' . $errStr); }); $bean = new RedBean_OODBBean(); $bean->getID(); restore_error_handler(); pass(); }
/** * Does an optimization cycle for each UPDATE event. * @param string $event * @param RedBean_OODBBean $bean */ public function onEvent($event, $bean) { try { if ($event == "update") { $arr = $bean->export(); unset($arr["id"]); if (count($arr) == 0) { return; } $table = $this->adapter->escape($bean->getMeta("type")); $columns = array_keys($arr); //Select a random column for optimization. $column = $this->adapter->escape($columns[array_rand($columns)]); $value = $arr[$column]; $type = $this->writer->scanType($value); $fields = $this->writer->getColumns($table); if (!in_array($column, array_keys($fields))) { return; } $typeInField = $this->writer->code($fields[$column]); //Is the type too wide? if ($type < $typeInField) { try { @$this->adapter->exec("alter table " . $this->writer->noKW($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->noKW($table) . " add __test " . $type); //Copy the values and see if there are differences. @$this->adapter->exec("update " . $this->writer->noKW($table) . " set __test=" . $this->writer->noKW($column) . ""); $rows = $this->adapter->get("select " . $this->writer->noKW($column) . " as a, __test as b from " . $this->writer->noKW($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->noKW($table) . " change " . $this->writer->noKW($column) . " " . $this->writer->noKW($column) . " " . $type); } //Throw away test column; we don't need it anymore! @$this->adapter->exec("alter table " . $this->writer->noKW($table) . " drop __test"); } else { $this->MySQLSpecificColumns($table, $column, $fields[$column], $value); } } } catch (RedBean_Exception_SQL $e) { //optimizer might make mistakes, don't care. //echo $e->getMessage()."<br>"; } }
/** * Test import from and tainted. * * @return void */ public function testImportFromAndTainted() { testpack('Test importFrom() and Tainted'); $bean = R::dispense('bean'); R::store($bean); $bean->name = 'abc'; asrt($bean->getMeta('tainted'), TRUE); R::store($bean); asrt($bean->getMeta('tainted'), FALSE); $copy = R::dispense('bean'); R::store($copy); $copy = R::load('bean', $copy->id); asrt($copy->getMeta('tainted'), FALSE); $copy->import(array('name' => 'xyz')); asrt($copy->getMeta('tainted'), TRUE); $copy->setMeta('tainted', FALSE); asrt($copy->getMeta('tainted'), FALSE); $copy->importFrom($bean); asrt($copy->getMeta('tainted'), TRUE); testpack('Test basic import() feature.'); $bean = new RedBean_OODBBean(); $bean->import(array("a" => 1, "b" => 2)); asrt($bean->a, 1); asrt($bean->b, 2); $bean->import(array("a" => 3, "b" => 4), "a,b"); asrt($bean->a, 3); asrt($bean->b, 4); $bean->import(array("a" => 5, "b" => 6), " a , b "); asrt($bean->a, 5); asrt($bean->b, 6); $bean->import(array("a" => 1, "b" => 2)); testpack('Test inject() feature.'); $coffee = R::dispense('coffee'); $coffee->id = 2; $coffee->liquid = 'black'; $cup = R::dispense('cup'); $cup->color = 'green'; // Pour coffee in cup $cup->inject($coffee); // Do we still have our own property? asrt($cup->color, 'green'); // Did we pour the liquid in the cup? asrt($cup->liquid, 'black'); // Id should not be transferred asrt($cup->id, 0); }
/** * Returns the alias for a type * * @param $type aliased type * * @return string $type type */ public function getAlias($type) { if ($t = RedBean_OODBBean::$fetchType) { $type = $t; RedBean_OODBBean::$fetchType = null; } return $type; }
/** * Checks whether a bean is valid * @param RedBean_OODBBean $bean */ public function check(RedBean_OODBBean $bean) { //Is all meta information present? if (!isset($bean->id) || !$bean->getMeta("type")) { throw new RedBean_Exception_Security("Bean has incomplete Meta Information"); } //Pattern of allowed characters $pattern = '/[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]/'; //Does the type contain invalid characters? if (preg_match($pattern, $bean->getMeta("type"))) { throw new RedBean_Exception_Security("Bean Type is invalid"); } //Are the properties and values valid? foreach ($bean as $prop => $value) { if (is_array($value) || is_object($value) || strlen($prop) < 1 || preg_match($pattern, $prop)) { throw new RedBean_Exception_Security("Invalid Bean: property {$prop} "); } } }
/** * Returns all beans that have been tagged with one or more * of the specified tags. * * Tag list can be either an array with tag names or a comma separated list * of tag names. * * @param string $beanType type of bean you are looking for * @param array|string $tagList list of tags to match * * @return array */ public function tagged($beanType, $tagList) { $tags = $this->extractTagsIfNeeded($tagList); $collection = array(); $tags = $this->redbean->find('tag', array('title' => $tags)); if (is_array($tags) && count($tags) > 0) { $collectionKeys = $this->associationManager->related($tags, $beanType); if ($collectionKeys) { $collection = $this->redbean->batch($beanType, $collectionKeys); } } return $collection; }
/** * Test meta data methods. * * @return void */ public function testMetaData() { testpack('Test meta data'); $bean = new RedBean_OODBBean(); $bean->setMeta("this.is.a.custom.metaproperty", "yes"); asrt($bean->getMeta("this.is.a.custom.metaproperty"), "yes"); asrt($bean->getMeta("nonexistant"), NULL); asrt($bean->getMeta("nonexistant", "abc"), "abc"); asrt($bean->getMeta("nonexistant.nested"), NULL); asrt($bean->getMeta("nonexistant,nested", "abc"), "abc"); $bean->setMeta("test.two", "second"); asrt($bean->getMeta("test.two"), "second"); $bean->setMeta("another.little.property", "yes"); asrt($bean->getMeta("another.little.property"), "yes"); asrt($bean->getMeta("test.two"), "second"); // Copy Metadata $bean = new RedBean_OODBBean(); $bean->setMeta("meta.meta", "123"); $bean2 = new RedBean_OODBBean(); asrt($bean2->getMeta("meta.meta"), NULL); $bean2->copyMetaFrom($bean); asrt($bean2->getMeta("meta.meta"), "123"); }
/** * * @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); }
/** * Test if RedBeanPHP can properly handle keywords. * * @return void */ public function testKeywords() { $keywords = array('anokeyword', 'znokeyword', 'group', 'DROP', 'inner', 'JOIN', 'select', 'table', 'int', 'cascade', 'float', 'CALL', 'in', 'status', 'order', 'limit', 'having', 'else', 'if', 'while', 'distinct', 'like'); R::setStrictTyping(FALSE); RedBean_OODBBean::setFlagBeautifulColumnNames(FALSE); foreach ($keywords as $k) { R::nuke(); $bean = R::dispense($k); $bean->{$k} = $k; $id = R::store($bean); $bean = R::load($k, $id); $bean2 = R::dispense('other'); $bean2->name = $k; $bean->bean = $bean2; $bean->ownBean[] = $bean2; $bean->sharedBean[] = $bean2; $id = R::store($bean); R::trash($bean); pass(); } RedBean_OODBBean::setFlagBeautifulColumnNames(TRUE); R::setStrictTyping(TRUE); }
/** * Generates a key from the bean type and its ID and determines if the bean * occurs in the trail, if not the bean will be added to the trail. * Returns TRUE if the bean occurs in the trail and FALSE otherwise. * * @param array $trail list of former beans * @param RedBean_OODBBean $bean currently selected bean * * @return boolean */ private function inTrailOrAdd(&$trail, RedBean_OODBBean $bean) { $type = $bean->getMeta('type'); $key = $type . $bean->getID(); if (isset($trail[$key])) { return TRUE; } $trail[$key] = $bean; return FALSE; }
/** * Creates a 1 to Many Association * If the association fails it throws an exception. * @throws RedBean_Exception_SQL $failedToEnforce1toN * @param RedBean_OODBBean $bean1 * @param RedBean_OODBBean $bean2 * @return RedBean_AssociationManager $chainable */ public function set1toNAssoc(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2) { $type = $bean1->getMeta("type"); $this->clearRelations($bean2, $type); $this->associate($bean1, $bean2); if (count($this->related($bean2, $type)) === 1) { return $this; } else { throw new RedBean_Exception_SQL("Failed to enforce 1toN Relation for {$type} "); } }
$default_config['default_sql_limit'] = array(0, 25); $default_config['rate_limit'] = 100; $config = array_merge($default_config, $config); if (file_exists('config.php.default') && $config['debug'] === false) { die('Please remove the config.php.default.'); } require_once 'utils.php'; /* make sure admin pass has changed */ if ($config['password'] === 'admin') { die('Change the password in config.php'); } /* setup database */ use RedBean_Facade as R; R::setup($config['db_conn'], $config['db_user'], $config['db_pass']); R::$writer->setUseCache(false); RedBean_OODBBean::setFlagBeautifulColumnNames(false); /* app start */ if ($config['debug'] === false) { ini_set('display_errors', '0'); } $app = new \Slim\Slim(array('debug' => $config['debug'], 'templates.path' => 'templates')); /* Middlewares */ $r = new Util($app); /* load hooks */ $r->loadHooks(); function API() { $app = \Slim\Slim::getInstance(); $app->view(new \JsonApiView()); $app->add(new \JsonApiMiddleware()); $app->response->headers->set('Content-Type', 'application/json');
/** * Returns the ID of the Model. */ public function getID() { $idField = $this->tools->getWriter()->getIDField($this->bean->getMeta("type")); return $this->bean->{$idField}; }
/** * Injects the properties of another bean but keeps the original ID. * Just like import() but keeps the original ID. * Chainable. * * @param RedBean_OODBBean $otherBean the bean whose properties you would like to copy * * @return RedBean_OODBBean */ public function inject(RedBean_OODBBean $otherBean) { $myID = $this->properties['id']; $this->import($otherBean->export()); $this->id = $myID; return $this; }
/** * Counts the number of beans of a specific type * @param RedBean_OODBBean $bean * @return integer $count */ public function numberOf(RedBean_OODBBean $bean) { $type = $this->adapter->escape($bean->getMeta("type")); return (int) $this->adapter->getCell("SELECT count(*) FROM `{$type}`"); }
/** * Returns the bean identified by the RESTful path. * For instance: * * $user * /site/1/page/3 * * returns page with ID 3 in ownPage of site 1 in ownSite of * $user bean. * * Works with shared lists as well: * * $user * /site/1/page/3/shared-ad/4 * * Note that this method will open all intermediate beans so you can * attach access control rules to each bean in the path. * * @param RedBean_OODBBean $bean * @param array $steps (an array representation of a REST path) * * @return RedBean_OODBBean * * @throws RedBean_Exception_Security */ public function findByPath($bean, $steps) { $numberOfSteps = count($steps); if (!$numberOfSteps) { return $bean; } if ($numberOfSteps % 2) { throw new RedBean_Exception_Security('Invalid path: needs 1 more element.'); } for ($i = 0; $i < $numberOfSteps; $i += 2) { $steps[$i] = trim($steps[$i]); if ($steps[$i] === '') { throw new RedBean_Exception_Security('Cannot access list.'); } if (strpos($steps[$i], 'shared-') === FALSE) { $listName = 'own' . ucfirst($steps[$i]); $listType = $this->toolbox->getWriter()->esc($steps[$i]); } else { $listName = 'shared' . ucfirst(substr($steps[$i], 7)); $listType = $this->toolbox->getWriter()->esc(substr($steps[$i], 7)); } $list = $bean->withCondition(" {$listType}.id = ? ", array($steps[$i + 1]))->{$listName}; if (!isset($list[$steps[$i + 1]])) { throw new RedBean_Exception_Security('Cannot access bean.'); } $bean = $list[$steps[$i + 1]]; } return $bean; }
/** * Makes a copy of a bean. This method makes a deep copy * of the bean.The copy will have the following features. * - All beans in own-lists will be duplicated as well * - All references to shared beans will be copied but not the shared beans themselves * - All references to parent objects (_id fields) will be copied but not the parents themselves * In most cases this is the desired scenario for copying beans. * This function uses a trail-array to prevent infinite recursion, if a recursive bean is found * (i.e. one that already has been processed) the ID of the bean will be returned. * This should not happen though. * * Note: * This function does a reflectional database query so it may be slow. * * @param RedBean_OODBBean $bean bean to be copied * @param array $trail for internal usage, pass array() * @param boolean $pid for internal usage * * @return array $copiedBean the duplicated bean */ protected function duplicate($bean, $trail = array(), $pid = false) { $type = $bean->getMeta('type'); $key = $type . $bean->getID(); if (isset($trail[$key])) { return $bean; } $trail[$key] = $bean; $copy = $this->redbean->dispense($type); $copy->import($bean->getProperties()); $copy->id = 0; $tables = $this->toolbox->getWriter()->getTables(); foreach ($tables as $table) { if (strpos($table, '_') !== false || $table == $type) { continue; } $owned = 'own' . ucfirst($table); $shared = 'shared' . ucfirst($table); if ($beans = $bean->{$owned}) { $copy->{$owned} = array(); foreach ($beans as $subBean) { array_push($copy->{$owned}, $this->duplicate($subBean, $trail, $pid)); } } $copy->setMeta('sys.shadow.' . $owned, null); if ($beans = $bean->{$shared}) { $copy->{$shared} = array(); foreach ($beans as $subBean) { array_push($copy->{$shared}, $subBean); } } $copy->setMeta('sys.shadow.' . $shared, null); } if ($pid) { $copy->id = $bean->id; } return $copy; }
/** * Removes a bean from the database. * This function will remove the specified RedBean_OODBBean * Bean Object from the database. * @throws RedBean_Exception_Security $exception * @param RedBean_OODBBean $bean */ public function trash(RedBean_OODBBean $bean) { $idfield = $this->writer->getIDField($bean->getMeta("type")); $this->signal("delete", $bean); $this->check($bean); try { $this->writer->deleteRecord($bean->getMeta("type"), $bean->{$idfield}); } catch (RedBean_Exception_SQL $e) { if ($e->getSQLState() != "42S02" && $e->getSQLState() != "42S22") { throw $e; } } }
/** * Adds a constraint. If one of the beans gets trashed * the other, related bean should be removed as well. * * @param RedBean_OODBBean $bean1 first bean * @param RedBean_OODBBean $bean2 second bean * @param bool $dontCache by default we use a cache, TRUE = NO CACHING (optional) * * @return void */ public function addConstraint(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2, $dontCache = false) { $table1 = $bean1->getMeta("type"); $table2 = $bean2->getMeta("type"); $writer = $this; $adapter = $this->adapter; $table = $this->getAssocTableFormat(array($table1, $table2)); $idfield1 = $writer->getIDField($bean1->getMeta("type")); $idfield2 = $writer->getIDField($bean2->getMeta("type")); $property1 = $bean1->getMeta("type") . "_id"; $property2 = $bean2->getMeta("type") . "_id"; if ($property1 == $property2) { $property2 = $bean2->getMeta("type") . "2_id"; } $table = $adapter->escape($table); $table1 = $adapter->escape($table1); $table2 = $adapter->escape($table2); $property1 = $adapter->escape($property1); $property2 = $adapter->escape($property2); //In Cache? Then we dont need to bother $fkCode = "fk" . md5($table . $property1 . $property2); if (isset($this->fkcache[$fkCode])) { return false; } //Dispatch to right method try { return $this->constrain($table, $table1, $table2, $property1, $property2, $dontCache); } catch (RedBean_Exception_SQL $e) { if (!$writer->sqlStateIn($e->getSQLState(), array(RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN, RedBean_QueryWriter::C_SQLSTATE_NO_SUCH_TABLE))) { throw $e; } } return false; }
/** * Creates a 1 to Many Association * @param RedBean_OODBBean $bean1 * @param RedBean_OODBBean $bean2 */ public function set1toNAssoc(RedBean_OODBBean $bean1, RedBean_OODBBean $bean2) { $this->clearRelations($bean2, $bean1->getMeta("type")); $this->associate($bean1, $bean2); }
/** * Used for mixins. */ protected function mapAndCacheMetadataAndSetHints($modelClassName, RedBean_OODBBean $bean) { assert('is_string($modelClassName)'); assert('$modelClassName != ""'); $metadata = $this->getMetadata(); if (isset($metadata[$modelClassName])) { $hints = array(); if (isset($metadata[$modelClassName]['members'])) { foreach ($metadata[$modelClassName]['members'] as $memberName) { $this->attributeNameToBeanAndClassName[$memberName] = array($bean, $modelClassName); //$this->attributeNamesNotBelongsToOrManyMany[] = $memberName; if (substr($memberName, -2) == 'Id') { $columnName = strtolower($memberName); $hints[$columnName] = 'id'; } } } if (isset($metadata[$modelClassName]['relations'])) { foreach ($metadata[$modelClassName]['relations'] as $relationName => $relationTypeModelClassNameAndOwns) { assert('in_array(count($relationTypeModelClassNameAndOwns), array(2, 3, 4, 5))'); $relationType = $relationTypeModelClassNameAndOwns[0]; $relationModelClassName = $relationTypeModelClassNameAndOwns[1]; if ($relationType == self::HAS_MANY_BELONGS_TO && strtolower($relationName) != strtolower($relationModelClassName)) { $label = 'Relations of type HAS_MANY_BELONGS_TO must have the relation name ' . 'the same as the related model class name. Relation: {relationName} ' . 'Relation model class name: {relationModelClassName}'; throw new NotSupportedException(Zurmo::t('Core', $label, array('{relationName}' => $relationName, '{relationModelClassName}' => $relationModelClassName))); } if (count($relationTypeModelClassNameAndOwns) >= 3 && $relationTypeModelClassNameAndOwns[2] == self::OWNED) { $owns = true; } else { $owns = false; } // $linkType = null; // $relationLinkName = null; // self::resolveLinkTypeAndRelationLinkName($relationTypeModelClassNameAndOwns, $linkType, // $relationLinkName); assert('in_array($relationType, array(self::HAS_ONE_BELONGS_TO, self::HAS_MANY_BELONGS_TO, ' . 'self::HAS_ONE, self::HAS_MANY, self::MANY_MANY))'); $this->attributeNameToBeanAndClassName[$relationName] = array($bean, $modelClassName); /** $this->relationNameToRelationTypeModelClassNameAndOwns[$relationName] = array($relationType, $relationModelClassName, $owns, $linkType, $relationLinkName); * **/ if (!in_array($relationType, array(self::HAS_ONE_BELONGS_TO, self::HAS_MANY_BELONGS_TO, self::MANY_MANY))) { //$this->attributeNamesNotBelongsToOrManyMany[] = $relationName; } } } // Add model validators. Parent validators are already applied. if (isset($metadata[$modelClassName]['rules'])) { foreach ($metadata[$modelClassName]['rules'] as $validatorMetadata) { assert('isset($validatorMetadata[0])'); assert('isset($validatorMetadata[1])'); $attributeName = $validatorMetadata[0]; // Each rule in RedBeanModel must specify one attribute name. // This was just better style, now it is mandatory. assert('strpos($attributeName, " ") === false'); $validatorName = $validatorMetadata[1]; $validatorParameters = array_slice($validatorMetadata, 2); if (isset(CValidator::$builtInValidators[$validatorName])) { $validatorName = CValidator::$builtInValidators[$validatorName]; } if (isset(self::$yiiValidatorsToRedBeanValidators[$validatorName])) { $validatorName = self::$yiiValidatorsToRedBeanValidators[$validatorName]; } $validator = CValidator::createValidator($validatorName, $this, $attributeName, $validatorParameters); switch ($validatorName) { case 'RedBeanModelTypeValidator': case 'TypeValidator': $columnName = strtolower($attributeName); if (array_key_exists($columnName, $hints)) { unset($hints[$columnName]); } if (in_array($validator->type, array('date', 'datetime', 'blob', 'longblob', 'string', 'text', 'longtext'))) { $hints[$columnName] = $validator->type; } break; case 'CBooleanValidator': $columnName = strtolower($attributeName); $hints[$columnName] = 'boolean'; break; case 'RedBeanModelUniqueValidator': if (!static::isRelation($attributeName)) { $bean->setMeta("buildcommand.unique", array(array($attributeName))); } else { $relationAndOwns = static::getRelationNameToRelationTypeModelClassNameAndOwnsForModel(); $relatedModelClassName = $relationAndOwns[$attributeName][1]; $relatedModelTableName = self::getTableName($relatedModelClassName); $columnName = strtolower($attributeName); if ($columnName != $relatedModelTableName) { $columnName .= '_' . $relatedModelTableName; } $columnName .= '_id'; $bean->setMeta("buildcommand.unique", array(array($columnName))); } break; } $this->validators[] = $validator; } // Check if we need to update string type to long string type, based on validators. if (isset($metadata[$modelClassName]['members'])) { foreach ($metadata[$modelClassName]['members'] as $memberName) { $allValidators = $this->getValidators($memberName); if (!empty($allValidators)) { foreach ($allValidators as $validator) { if ((get_class($validator) == 'RedBeanModelTypeValidator' || get_class($validator) == 'TypeValidator') && $validator->type == 'string') { $columnName = strtolower($validator->attributes[0]); if (count($allValidators) > 1) { $haveCStringValidator = false; foreach ($allValidators as $innerValidator) { if (get_class($innerValidator) == 'CStringValidator' && isset($innerValidator->max) && $innerValidator->max > 0) { if ($innerValidator->max > 65535) { $hints[$columnName] = 'longtext'; } elseif ($innerValidator->max < 255) { $hints[$columnName] = "string({$innerValidator->max})"; } else { $hints[$columnName] = 'text'; } } if (get_class($innerValidator) == 'CStringValidator') { $haveCStringValidator = true; } } if (!$haveCStringValidator) { $hints[$columnName] = 'text'; } } else { $hints[$columnName] = 'text'; } } } } } } } $bean->setMeta('hint', $hints); } }