Exemplo n.º 1
0
 /**
  * Constructor
  * @param string $name name of the corresponding class
  * @param string $type either "has" or "composed_of"
  * @param string $class the name of the class related
  * @param epClassMap
  */
 public function __construct($name, $type, $class, $is_many = false, $inverse = false, $class_map = false)
 {
     parent::__construct($name, $type, $class_map);
     $this->setIsMany($is_many);
     $this->setClass($class);
     $this->setInverse($inverse);
 }
Exemplo n.º 2
0
 /**
  * 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;
 }
Exemplo n.º 3
0
 /**
  * Returns the relation ids for the variable specified of the object
  * @param epObject $o the object
  * @param epFieldMap $fm the field map of the variable
  * @param epClassMap $cm the class map of the object
  * @return false|string|array
  */
 public function getRelationIds(&$o, $fm, $cm)
 {
     // make sure we are dealing with valid object and non-primitive field
     if (!$o || !$fm || !$cm) {
         return false;
     }
     // object needs to have a valid id and has to be non-primitive
     if (!($oid_a = $o->epGetObjectId())) {
         return false;
     }
     // get class_a, var_a, and the related class
     $base_a = $fm->getBase_a();
     $class_a = $cm->getName();
     $var_a = $fm->getName();
     $base_b = $fm->getBase_b();
     if (!$base_a || !$class_a || !$var_a || !$base_b) {
         throw new epExceptionManager('Cannot find related class for var [' . $class_a . '::' . $var_a . ']');
         return false;
     }
     // switch relations table
     $this->_setRelationTable($base_a, $base_b);
     // make an example relation objects
     if (!($eo =& $this->_relationExample($class_a, $oid_a, $var_a, $base_b))) {
         return false;
     }
     // find all relation objects using the example object
     // (find from db only, false: no cache, false: don't convert to objects)
     $rs =& parent::find($eo, EP_GET_FROM_DB, false, false);
     // convert result into oids
     $oids_b = null;
     if ($fm->isSingle()) {
         if (is_array($rs) && count($rs) > 1) {
             throw new epExceptionManager('Field ' . $fm->getName() . ' mapped as composed_of_/has_one but is associated with > 1 objects');
             return false;
         }
         if ($rs) {
             $oids_b = $rs[0];
         }
     } else {
         if ($fm->isMany()) {
             $oids_b = array();
             if ($rs) {
                 $oids_b = $rs;
             }
         }
     }
     return $oids_b;
 }
Exemplo n.º 4
0
 /**
  * Generates SQL statement for -this- node and set up 
  * aliases for all classes (root class and subclasses)
  * @return false|string
  * @throws epExceptionQueryPath
  */
 protected function _generateSql()
 {
     // -no- sql for primitive field
     if ($this->fm->isPrimitive()) {
         // only pass aliases from the parent to children
         $this->class2alias = $this->getParent()->getAliases();
         return '';
     }
     // get base a
     $base_a = $this->fm->getBase_a();
     // get base_b
     $base_b = $this->fm->getBase_b();
     // get class alias from parent
     if (!($class2alias_a = $this->getParent()->getAliases())) {
         throw new epExceptionQueryPath("no aliases found from parent node");
         return false;
     }
     // check if spcific class is set. use it only if so.
     if ($sc = $this->specificClass()) {
         // get class map of specific class
         if (!($cm_b = $this->_em()->getClassMap($sc))) {
             throw new epExceptionQueryPath("no class map for classes and '{$sc}'");
             return false;
         }
     } else {
         // get class map of base b
         if (!($cm_b = $this->_em()->getClassMap($base_b))) {
             throw new epExceptionQueryPath("no class map for classes and '{$base_b}'");
             return false;
         }
     }
     // get relationship table with base_a and base_b
     if (!($rt = $this->_em()->getRelationTable($base_a, $base_b))) {
         throw new epExceptionQueryPath("no relationship table for classes '{$base_a}' and '{$base_b}'");
         return false;
     }
     $aliases = array();
     $aliases[] = '';
     // check if we have any children contained
     $children_contained = false;
     if ($children = $this->getChildren()) {
         foreach ($children as $child) {
             if ($child->isRoot() && $child->isContained()) {
                 $aliases[] = $child->getAlias();
                 $children_contained = true;
             }
         }
     }
     $sql = '';
     // go through each contained child
     foreach ($aliases as $alias) {
         // get alias for relationship table
         if (!isset($this->table2alias[$rt . '.' . $alias])) {
             $rt_alias = $this->_am()->getTableAlias($rt, true);
             $this->table2alias[$rt . '.' . $alias] = $rt_alias;
         } else {
             $rt_alias = $this->table2alias[$rt . '.' . $alias];
         }
         // generate sql for class_a (including its subclasses)
         if ($alias || !$children_contained) {
             $sql .= $this->_generateSqlClassA($rt, $rt_alias, $this->fm->getName(), $class2alias_a);
         }
         // assemble sql for class b and subclasses
         $cms_b = array();
         // collect all children if no specific class set
         if (!$this->specificClass()) {
             $cms_b = $cm_b->getChildren(true);
         }
         array_unshift($cms_b, $cm_b);
         foreach ($cms_b as $cm_b_) {
             // skip abstract
             if ($cm_b_->isAbstract()) {
                 continue;
             }
             // get class b name and make alias
             $class_b = $cm_b_->getName();
             if ($children_contained) {
                 // @@@ alias key may be in the form of 'ClassName.alias'
                 // @@@ to differentiate multiple aliases of the same class
                 if (!isset($this->class2alias[$class_b . '.' . $alias])) {
                     if (!$alias) {
                         $alias_b = $this->_am()->getClassAlias($class_b, true);
                     } else {
                         $alias_b = $this->class2alias[$class_b . '.'];
                         $this->_am()->setClassAlias($class_b, $alias_b . $alias);
                     }
                     $this->class2alias[$class_b . '.' . $alias] = $alias_b . $alias;
                 }
                 $alias_b = $this->class2alias[$class_b . '.' . $alias];
             } else {
                 if (!isset($this->class2alias[$class_b])) {
                     $alias_b = $this->_am()->getClassAlias($class_b, true);
                     $this->class2alias[$class_b] = $alias_b;
                 } else {
                     $alias_b = $this->class2alias[$class_b];
                 }
             }
             // generate sql for class b
             if ($alias || !$children_contained) {
                 $sql .= $this->_generateSqlClassB($rt_alias, $cm_b_->getTable(), $base_b, $class_b, $alias_b, $cm_b_->getOidColumn());
             }
         }
     }
     return $sql;
 }
Exemplo n.º 5
0
 /**
  * Test var orm tag
  */
 function testVarPrimTag()
 {
     // get all supported column types
     include_once EP_SRC_ORM . '/epFieldMap.php';
     $alltypes = epFieldMap::getSupportedTypes();
     $keytypes = array('', 'unique', 'index');
     $keynames = array('', 'testingname');
     foreach ($alltypes as $type) {
         // skip relationship types
         if ($type == epFieldMap::DT_HAS || $type == epFieldMap::DT_COMPOSED_OF) {
             continue;
         }
         $name = '_' . md5($type);
         $params = array();
         if ($type == epFieldMap::DT_CHAR || $type == epFieldMap::DT_TEXT || $type == epFieldMap::DT_BLOB) {
             $params[] = rand(1, self::MAX_REPEATS);
         } elseif ($type == epFieldMap::DT_DECIMAL) {
             $params[] = rand(1, self::MAX_REPEATS);
             $params[] = rand(1, self::MAX_REPEATS);
         }
         foreach ($keytypes as $keytype) {
             foreach ($keynames as $keyname) {
                 // skip the situations where we have no keytype but we have a keyname
                 if ($keytype == '' && $keyname != '') {
                     continue;
                 }
                 $this->_varPrimTag($name, $type, $params, $keytype, $keyname);
             }
         }
     }
 }
Exemplo n.º 6
0
 /**
  * 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;
 }
Exemplo n.º 7
0
 /**
  * Make where part of a SQL select for relationship fields
  * @param epDbObject $db the db connection  
  * @param epFieldMap $fm the field map
  * @param epClassMap $cm the child object for query
  * @param string $alias the alias of this table in the previous part
  * @return array('from', 'where')
  * @author Oak Nauhygon <*****@*****.**>
  * @author Trevan Richins <*****@*****.**>
  */
 public static function sqlSelectRelations($db, $fm, $cm, $table, $alias, $parentTable)
 {
     $base_a = $fm->getBase_a();
     $class_a = $cm->getName();
     $var_a = $fm->getName();
     $base_b = $fm->getBase_b();
     // call manager to get relation table for base class a and b
     $rt = epManager::instance()->getRelationTable($base_a, $base_b);
     // the alias of the table we are dealing with right now
     $tbAlias = '_' . $alias;
     $rtAlias = 'rt' . $alias;
     // quoted aliases (avoid repeating)
     $tbAlias_q = $db->quoteId($tbAlias);
     $rtAlias_q = $db->quoteId($rtAlias);
     // compute 'from' parts: tables with aliases
     $from = array();
     $from[] = $db->quoteId($table) . ' AS ' . $tbAlias_q;
     $from[] = $db->quoteId($rt) . ' AS ' . $rtAlias_q;
     // compute expressions 'where'
     $where = array();
     // rt.class_a =
     $where[] = $rtAlias_q . '.' . $db->quoteId('class_a') . ' = ' . $db->quote($class_a);
     // rt.var_a =
     $where[] = $rtAlias_q . '.' . $db->quoteId('var_a') . ' = ' . $db->quote($var_a);
     // rt.base_b =
     $where[] = $rtAlias_q . '.' . $db->quoteId('base_b') . ' = ' . $db->quote($base_b);
     // rt.class_b =  TODO: doesn't look like it is used
     //$where .= 'rt.'.$db->quoteId('class_b') . ' = ' . $db->quote($val->getClass());
     // A.oid = rt.oid_a
     $where[] = $db->quoteId($parentTable) . '.' . $db->quoteId($cm->getOidColumn()) . ' = ' . $rtAlias_q . '.' . $db->quoteId('oid_a');
     // Child.oid = rt.oid_b
     $where[] = $tbAlias_q . '.' . $db->quoteId($fm->getClassMap()->getOidColumn()) . ' = ' . $rtAlias_q . '.' . $db->quoteId('oid_b');
     return array('from' => $from, 'where' => $where);
 }
Exemplo n.º 8
0
 /**
  * Toggles the token type of data types between EPL_T_DATA_TYPE
  * and EPL_T_IDENTIFIER. This is to allow data types to be 
  * used for class names. 
  */
 public function toggleDataTypeTokens()
 {
     // get data types (including 'has' and 'composed_of')
     $dtypes = epFieldMap::getSupportedTypes();
     // go through all keywords
     foreach ($this->keywords as $keyword => $token) {
         if (!in_array($keyword, $dtypes)) {
             continue;
         }
         // has
         if ($keyword == epFieldMap::DT_HAS) {
             $this->keywords[$keyword] = $token == EPL_T_HAS ? EPL_T_IDENTIFIER : EPL_T_HAS;
             continue;
         }
         // composed of
         if ($keyword == epFieldMap::DT_COMPOSED_OF) {
             $this->keywords[$keyword] = $token == EPL_T_COMPOSED_OF ? EPL_T_IDENTIFIER : EPL_T_COMPOSED_OF;
             continue;
         }
         // primitive types
         $this->keywords[$keyword] = $token == EPL_T_DATA_TYPE ? EPL_T_IDENTIFIER : EPL_T_DATA_TYPE;
     }
 }
Exemplo n.º 9
0
 /**
  * Check if the value to be set matches the type set in orm tag
  * @param epObject|string $value
  * @param epFieldMap $fm
  * @return boolean
  */
 protected function _checkValueType($value, $fm)
 {
     // no check if no manager
     if (!$this->ep_m) {
         return true;
     }
     // no checking on primitve, ignore false|null|empty, and non-epObject
     if ($fm->isPrimitive() || !$value) {
         // always true
         return true;
     }
     // epObject
     if ($value instanceof epObject) {
         return $this->_typeMatch($this->ep_m->getClass($value), $fm->getClass());
     } else {
         if (is_array($value) || $value instanceof epArray) {
             foreach ($value as $k => $v) {
                 if (!$v instanceof epObject) {
                     continue;
                 }
                 if (!$this->_typeMatch($this->ep_m->getClass($v), $fm->getClass())) {
                     return false;
                 }
             }
             return true;
         }
     }
     return true;
 }
Exemplo n.º 10
0
 /**
  * Builds SQL statement from 'contains' or alias assignment node
  * @param epQueryNode &$node either a 'contains' node or an assignment node
  * @param epFieldMap $fm the starting field map
  * @param array $var_exprs expressions for var
  * @param array|epObject $arg the argument|value for the operation
  * @return false|string
  * @throws epExceptionQueryBuilder
  */
 protected function _buildSqlRelationship(epQueryNode &$node, $fm, $var_exprs, $arg)
 {
     // is arg a string
     if (is_string($arg)) {
         // go through each where (notice &)
         foreach ($var_exprs as $alias => &$expr) {
             // remove last alias
             $expr = str_replace($alias, $arg, $expr);
             // remove this alias (important)
             unset($this->aliases[$alias]);
         }
         return implode(' OR ', $var_exprs);
     } else {
         if (is_array($arg) || $arg instanceof epObject) {
             // convert array to an object
             $o = $arg;
             if (is_array($arg)) {
                 // false: no event dispatching, true: null vars if no value
                 $o =& $this->em->createFromArray($fm->getClass(), $arg, false, true);
                 // object and children not to be committed
                 $o->epSetCommittable(false, true);
             }
             // array to keep all expressions
             $exprs = array();
             // go through each var exprs
             foreach ($var_exprs as $var_alias => $var_expr) {
                 // build sql for array or object
                 $obj_exprs = $this->_buildSqlObject($o, $fm, $var_alias);
                 // go through each returned expr from the array or object
                 foreach ($obj_exprs as $obj_expr) {
                     $exprs[] = $obj_expr . ' AND ' . $var_expr;
                 }
             }
             return implode(' OR ', $exprs);
         }
     }
     // unrecognized
     throw new epExceptionQueryBuilder($this->_e("Unrecognized argument in 'contains()'", $node));
     return false;
 }
Exemplo n.º 11
0
 /**
  * Constructor
  * @param string tag value
  */
 public function __construct($value)
 {
     // make match pattern of all supported types
     if (!self::$alltypes) {
         include_once EP_SRC_ORM . '/epFieldMap.php';
         self::$alltypes = epFieldMap::getSupportedTypes();
     }
     parent::__construct($value);
 }