/** * Unrelate entities from each other * * @param array $options * @return bool */ public function unrelate(array $options) { $this->_checkAcl('relate'); extract($options); if (!isset($primaryKey) || !isset($model) || !isset($foreignKeys)) { throw new Garp_Content_Exception('Not enough options. "primaryKey", "model" and "foreignKeys" are required.'); } $model = Garp_Content_Api::modelAliasToClass($model); $primaryKey = (array) $primaryKey; $foreignKeys = (array) $foreignKeys; $rule = isset($rule) ? $rule : null; $rule2 = isset($rule2) ? $rule2 : null; $bindingModel = isset($bindingModel) ? 'Model_' . $bindingModel : null; $bidirectional = isset($bidirectional) ? $bidirectional : null; Garp_Content_Relation_Manager::unrelate(array('modelA' => $this->_model, 'modelB' => $model, 'keyA' => $primaryKey, 'keyB' => $foreignKeys, 'rule' => $rule, 'ruleB' => $rule2, 'bindingModel' => $bindingModel, 'bidirectional' => $bidirectional)); }
/** * Relate Chapters. * Called after insert and after update. * @param Array $chapters * @param Garp_Model_Db $model The subject model * @param Int $articleId The id of the involved article * @return Void */ public function relateChapters(array $chapters, Garp_Model_Db $model, $articleId) { // Start by unrelating all chapters Garp_Content_Relation_Manager::unrelate(array('modelA' => $model, 'modelB' => 'Model_Chapter', 'keyA' => $articleId)); // Reverse order since the Weighable behavior sorts chapter by weight DESC, // giving each new chapter the highest weight. $chapters = array_reverse($chapters); foreach ($chapters as $chapterData) { $chapterData = $this->_getValidChapterData($chapterData); /** * Insert a new chapter. * The chapter will take care of storing and relating the * content nodes. */ $chapterModel = new Model_Chapter(); $chapterId = $chapterModel->insert(array('type' => $chapterData['type'], 'content' => $chapterData['content'])); Garp_Content_Relation_Manager::relate(array('modelA' => $model, 'modelB' => 'Model_Chapter', 'keyA' => $articleId, 'keyB' => $chapterId)); } }
/** * Unrelate records. * * @param array|Garp_Util_Configuration $options Lots o' options: * 'modelA' string|Garp_Model_Db The first model or classname thereof * 'modelB' string|Garp_Model_Db The second model or classname thereof * 'keyA' mixed Primary key(s) of the first model * 'keyB' mixed Primary key(s) of the second model * 'rule' string The rule that stores this relationship in one of the * reference maps * @return bool Success */ public static function unrelate($options) { self::_normalizeOptionsForUnrelate($options); $modelA = $options['modelA']; $modelB = $options['modelB']; /** * If bindingModel is set, we can safely skip all those difficult checks below. */ if (is_object($options['bindingModel'])) { return self::_unrelateHasAndBelongsToMany($options); } try { /** * If this succeeds, it's a regular relationship where the foreign key * resides inside modelA. Continue as usual. */ $reference = $modelA->getReference(get_class($modelB), $options['rule']); } catch (Exception $e) { if (!self::isInvalidReferenceException($e)) { throw $e; } try { /** * If this succeeds, the foreign key resides in the modelA. * Flip modelA and modelB and keyA and keyB in order to normalize the * given configuration. * Call self::relate() recursively with these new options. */ $reference = $modelB->getReference(get_class($modelA), $options['rule']); $keyA = $options['keyA']; $keyB = $options['keyB']; $options['modelA'] = $modelB; $options['modelB'] = $modelA; $options['keyA'] = $keyB; $options['keyB'] = $keyA; return Garp_Content_Relation_Manager::unrelate($options); } catch (Exception $e) { if (!self::isInvalidReferenceException($e)) { throw $e; } /** * Goody, we're dealing with a hasAndBelongsToMany relationship here. * Try to construct the intersection model and save the relation * that way. */ return self::_unrelateHasAndBelongsToMany($options); } } /** * Figure out which model is leading. This depends on which of the two keys is provided. * This kind of flips the query around. For instance, when keyA is given, the query is * something like this: * UPDATE modelA SET foreignkey = NULL WHERE primarykey = keyA * When keyB is given however, the query goes something like this: * UPDATE modelA SET foreignkey = NULL WHERE foreignkey = keyB */ $query = 'UPDATE `' . $modelA->getName() . '` SET '; $columnsToValues = array(); foreach ($reference['columns'] as $column) { $columnsToValues[] = '`' . $column . '` = NULL'; } $columnsToValues = implode(' AND ', $columnsToValues); $query .= $columnsToValues; $whereColumnsToValues = array(); if ($options['keyA']) { $useColumns = 'refColumns'; $useKeys = 'keyA'; } else { $useColumns = 'columns'; $useKeys = 'keyB'; } foreach ($reference[$useColumns] as $i => $column) { $whereColumnsToValues[] = '`' . $column . '` = ' . $options[$useKeys][$i]; } $whereColumnsToValues = implode(' AND ', $whereColumnsToValues); $query .= ' WHERE '; $query .= $whereColumnsToValues; return $modelA->getAdapter()->query($query); }