/** * Updates the value of the inverse var * @param epFieldMap $fm The field map toward the inverse var * @param epObject &$o The opposite object * @param string $actoin The update action to take: INVERSE_ADD|REMOVE * @param bool $one_way Whether inverse update is one way only * @return bool */ protected function _updateInverse($fm, &$o, $action = epObject::INVERSE_ADD, $one_way = true) { // check if object is epObject if (!$o || !$o instanceof epObject) { return false; } // no action if an object is updating (to prevent endless loop) if ($o->epIsUpdating($action)) { return true; } // get inverse var if (!($ivar = $fm->getInverse())) { return true; } // set inverse updating flag if ($one_way) { $this->epSetUpdating(true, $action); } $o->epSetUpdating(true, $action); // a single-valued field if (!$o->epIsMany($ivar)) { switch ($action) { case epObject::INVERSE_ADD: $o[$ivar] = $this; break; case epObject::INVERSE_REMOVE: $o[$ivar] = null; break; } } else { switch ($action) { case epObject::INVERSE_ADD: $o[$ivar][] = $this; break; case epObject::INVERSE_REMOVE: $o[$ivar]->remove($this); break; } } // reset inverse updating flag $o->epSetUpdating(false, $action); if ($one_way) { $this->epSetUpdating(false, $action); } return true; }
/** * Validate related class and inverse on a field map * @param epFieldMap $fm the field map to be checked * @param string $class the name of the class that the field belongs to * @return array (errors) */ protected function _validateRelationshipField(&$fm, $class) { // array to hold error messages $errors = array(); // // 1. check the opposite class for the field // // string for class and field $class_field = '[' . $class . '::' . $fm->getName() . ']'; // does the relation field have the related class defined? if (!($rclass = $fm->getClass())) { // shouldn't happend $errors[] = $class_field . ' does not have opposite class specified'; return $errors; } // does the related class exist? if (!isset($this->class_maps[$rclass])) { // alert if not $errors[] = 'Class [' . $rclass . '] for ' . $class_field . ' does not exist'; return $errors; } // // 2. check inverse of the field // // does this field have an inverse? if (!($inverse = $fm->getInverse())) { return $errors; } // get the related class map $rcm = $this->class_maps[$rclass]; // get all fields point to the current class in the related class $rfields = $rcm->getFieldsOfClass($class); // 2.a. default inverse (that is, set to true) if (true === $inverse) { // the related class must have only one relationship var to the current class if (!$rfields) { $errors[] = 'No inverse found for ' . $class_field; } else { if (count($rfields) > 1) { $errors[] = 'Ambiguilty in the inverse of ' . $class_field; } else { $rfms = array_values($rfields); $fm->setInverse($rfms[0]->getName()); $rfms[0]->setInverse($fm->getName()); } } return $errors; } // 2.b. inverse is specified // check if inverse exists if (!isset($rfields[$fm->getClass() . ':' . $inverse]) || !$rfields[$fm->getClass() . ':' . $inverse]) { $errors[] = 'Inverse of ' . $class_field . ' (' . $fm->getClass() . '::' . $inverse . ') does not exist'; return $errors; } // get the field map for the inverse $rfm = $rfields[$fm->getClass() . ':' . $inverse]; // set up the inverse on the other side -only if- inverse on the other side // is -not- already set or set to default if (!($rinverse = $rfm->getInverse()) || $rinverse === true) { $rfm->setInverse($fm->getName()); return $errors; } // if specified, check duality if ($class != $rfm->getClass() || $rinverse != $fm->getName()) { $errors[] = 'Inverse of [' . $rcm->getName() . '::' . $fm->getName() . '] is not specified as ' . $class_field; } return $errors; }
/** * Update the value of the inverse var * @param epObject $o the opposite object * @param string $actoin UPDATE_INVERSE_ADD or UPDATE_INVERSE_REMOVE * @return boolean */ protected function _updateInverse(&$o, $action = self::UPDATE_INVERSE_ADD) { // check if object is epObject if (!$o || !$this->fm || !$o instanceof epObject) { return false; } // get inverse var if (!($ivar = $this->fm->getInverse())) { return true; } // no action if an object is updating (to prevent endless loop) if ($o->epIsUpdating()) { return true; } // set inverse updating flag $o->epSetUpdating(true); // a single-valued field if (!$o->epIsMany($ivar)) { switch ($action) { case self::UPDATE_INVERSE_ADD: $o[$ivar] = $this->o; break; case self::UPDATE_INVERSE_REMOVE: $o[$ivar] = null; break; } } else { switch ($action) { case self::UPDATE_INVERSE_ADD: $o[$ivar][] = $this->o; break; case self::UPDATE_INVERSE_REMOVE: $o[$ivar]->remove($this->o); break; } } // reset inverse updating flag $o->epSetUpdating(false); return true; }