示例#1
0
 /**
  * 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;
 }
示例#2
0
 /**
  * Preloads certain properties for beans.
  * Understands aliases.
  * 
  * Usage: $redbean->preload($books, array('coauthor'=>'author'));
  * 
  * Usage for nested beans:
  * 
  * $redbean->preload($texts, array('page', 'page.book', 'page.book.author'));
  * 
  * preloads pages, books and authors.
  * You may also use a shortcut here: 
  * 
  * $redbean->preload($texts, array('page', '*.book', '*.author'));
  * 
  * Can also load preload lists:
  * 
  * $redbean->preload($books, array('ownPage'=>'page', '*.ownText'=>'text', 'sharedTag'=>'tag'));
  * 
  * @param array $beans beans
  * @param array $types types to load
  */
 public function preload($beans, $types, $closure = null)
 {
     if (is_string($types)) {
         $types = explode(',', $types);
     }
     $oldFields = array();
     $i = 0;
     $retrievals = array();
     $oldField = '';
     foreach ($types as $key => $typeInfo) {
         list($type, $sqlObj) = is_array($typeInfo) ? $typeInfo : array($typeInfo, null);
         $map = $ids = $retrievals[$i] = array();
         $field = is_numeric($key) ? $type : $key;
         //use an alias?
         if (strpos($field, '*') !== false) {
             $oldFields[] = $oldField;
             $field = str_replace('*', implode('.', $oldFields), $field);
         }
         if (strpos($field, '&') !== false) {
             $field = str_replace('&', implode('.', $oldFields), $field);
         }
         $filteredBeans = $beans;
         $counterID = 0;
         foreach ($filteredBeans as $bean) {
             $bean->setMeta('sys.input-bean-id', array($counterID => $counterID));
             $counterID++;
         }
         while ($p = strpos($field, '.')) {
             //filtering: find the right beans in the path
             $nesting = substr($field, 0, $p);
             $filtered = array();
             foreach ($filteredBeans as $bean) {
                 $inputBeanID = $bean->getMeta('sys.input-bean-id');
                 if (is_array($bean->{$nesting})) {
                     $nestedBeans = $bean->{$nesting};
                     foreach ($nestedBeans as $nestedBean) {
                         $currentInputBeanIDs = $nestedBean->getMeta('sys.input-bean-id');
                         if (!is_array($currentInputBeanIDs)) {
                             $currentInputBeanIDs = array();
                         }
                         $addInputIDs = $bean->getMeta('sys.input-bean-id');
                         foreach ($addInputIDs as $addInputID) {
                             $currentInputBeanIDs[$addInputID] = $addInputID;
                         }
                         $nestedBean->setMeta('sys.input-bean-id', $currentInputBeanIDs);
                     }
                     $filtered = array_merge($filtered, $nestedBeans);
                 } elseif (!is_null($bean->{$nesting})) {
                     $nestedBean = $bean->{$nesting};
                     $currentInputBeanIDs = $nestedBean->getMeta('sys.input-bean-id');
                     if (!is_array($currentInputBeanIDs)) {
                         $currentInputBeanIDs = array();
                     }
                     $addInputIDs = $bean->getMeta('sys.input-bean-id');
                     foreach ($addInputIDs as $addInputID) {
                         $currentInputBeanIDs[$addInputID] = $addInputID;
                     }
                     $nestedBean->setMeta('sys.input-bean-id', $currentInputBeanIDs);
                     $filtered[] = $bean->{$nesting};
                 }
             }
             $filteredBeans = $filtered;
             $field = substr($field, $p + 1);
         }
         $oldField = $field;
         if (strpos($type, '.')) {
             $type = $field;
         }
         if (strpos($field, 'shared') !== 0) {
             foreach ($filteredBeans as $bean) {
                 //gather ids to load the desired bean collections
                 if (strpos($field, 'own') === 0) {
                     //based on bean->id for ownlist
                     $id = $bean->id;
                     $ids[$id] = $id;
                 } elseif ($id = $bean->{$field . '_id'}) {
                     //based on bean_id for parent
                     $ids[$id] = $id;
                     if (!isset($map[$id])) {
                         $map[$id] = array();
                     }
                     $map[$id][] = $bean;
                 }
             }
         }
         if (strpos($field, 'shared') === 0) {
             $bean = reset($filteredBeans);
             $link = $bean->getMeta('type') . '_id';
             $keys = $this->assocManager->related($filteredBeans, $type, true);
             $linkTable = $this->assocManager->getTable(array($type, $bean->getMeta('type')));
             $linkBeans = $this->batch($linkTable, $keys);
             $linked = $targetIDs = array();
             $targetIDField = $type . '_id';
             foreach ($linkBeans as $linkBean) {
                 $linkID = $linkBean->{$link};
                 if (!isset($linked[$linkID])) {
                     $linked[$linkID] = array();
                 }
                 $linked[$linkID][] = $linkBean;
                 $targetIDs[$linkBean->{$targetIDField}] = $linkBean->{$targetIDField};
             }
             $sharedBeans = $this->find($type, array('id' => $targetIDs), $sqlObj, !is_null($sqlObj));
             foreach ($filteredBeans as $filteredBean) {
                 $list = array();
                 if (isset($linked[$filteredBean->id])) {
                     foreach ($linked[$filteredBean->id] as $linkBean) {
                         foreach ($sharedBeans as $sharedBean) {
                             if ($sharedBean->id == $linkBean->{$targetIDField}) {
                                 $list[$sharedBean->id] = $sharedBean;
                             }
                         }
                     }
                 }
                 $filteredBean->setProperty($field, $list);
                 $inputBeanIDs = $filteredBean->getMeta('sys.input-bean-id');
                 foreach ($inputBeanIDs as $inputBeanID) {
                     if (!isset($retrievals[$i][$inputBeanID])) {
                         $retrievals[$i][$inputBeanID] = array();
                     }
                     foreach ($list as $listKey => $listBean) {
                         $retrievals[$i][$inputBeanID][$listKey] = $listBean;
                     }
                 }
             }
         } elseif (strpos($field, 'own') === 0) {
             //preload for own-list using find
             $link = $bean->getMeta('type') . '_id';
             $children = $this->find($type, array($link => $ids), $sqlObj, !is_null($sqlObj));
             foreach ($filteredBeans as $filteredBean) {
                 $list = array();
                 foreach ($children as $child) {
                     if ($child->{$link} == $filteredBean->id) {
                         $list[$child->id] = $child;
                     }
                 }
                 $filteredBean->setProperty($field, $list);
                 $inputBeanIDs = $filteredBean->getMeta('sys.input-bean-id');
                 foreach ($inputBeanIDs as $inputBeanID) {
                     if (!isset($retrievals[$i][$inputBeanID])) {
                         $retrievals[$i][$inputBeanID] = array();
                     }
                     foreach ($list as $listKey => $listBean) {
                         $retrievals[$i][$inputBeanID][$listKey] = $listBean;
                     }
                 }
             }
         } else {
             //preload for parent objects using batch()
             foreach ($this->batch($type, $ids) as $parent) {
                 foreach ($map[$parent->id] as $childBean) {
                     $childBean->setProperty($field, $parent);
                     $inputBeanIDs = $childBean->getMeta('sys.input-bean-id');
                     foreach ($inputBeanIDs as $inputBeanID) {
                         $retrievals[$i][$inputBeanID] = $parent;
                     }
                 }
             }
         }
         $i++;
     }
     if ($closure) {
         $key = 0;
         foreach ($beans as $bean) {
             $params = array();
             foreach ($retrievals as $r) {
                 $params[] = isset($r[$key]) ? $r[$key] : null;
             }
             array_unshift($params, $bean);
             call_user_func_array($closure, $params);
             $key++;
         }
     }
 }
示例#3
0
 /**
  * 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)
 {
     $toolbox = RedBean_Setup::getToolBox();
     RedBean_CompatManager::scanDirect($toolbox, array(RedBean_CompatManager::C_SYSTEM_MYSQL => "5", RedBean_CompatManager::C_SYSTEM_SQLITE => "3", RedBean_CompatManager::C_SYSTEM_POSTGRESQL => "7"));
     $association = new RedBean_AssociationManager($toolbox);
     $writer = $toolbox->getWriter();
     $oodb = $toolbox->getRedBean();
     $adapter = $toolbox->getDatabaseAdapter();
     if ($oodb->isFrozen()) {
         return false;
     }
     $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);
     $fkCode = "fk" . md5($table . $property1 . $property2);
     if (isset(self::$fkcache[$fkCode])) {
         return false;
     }
     try {
         if ($writer instanceof RedBean_QueryWriter_PostgreSQL) {
             return self::constraintPostgreSQL($toolbox, $table, $table1, $table2, $property1, $property2, $dontCache);
         }
         if ($writer instanceof RedBean_QueryWriter_SQLite) {
             return self::constraintSQLite($toolbox, $table, $table1, $table2, $property1, $property2, $dontCache);
         }
         if ($writer instanceof RedBean_QueryWriter_MySQL) {
             return self::constraintMySQL($toolbox, $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;
 }