/**
  * 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;
 }
 /**
  * Add field
  * @param epFieldMap $field
  * @return void
  * @access public
  */
 public function addField(epFieldMap $field)
 {
     // check if field is non primitive
     if (!$field->isPrimitive()) {
         // increase the count of non primitive fields
         $this->num_non_primitive++;
         // check if the field is composed_of
         if ($field->isComposedOf()) {
             $this->num_composed_of++;
         }
     }
     // set class map to field map for easy retrieval
     $field->setClassMap($this);
     $this->fields[$field->getName()] =& $field;
 }
 /**
  * Checks if the value to be set matches the type set in the field map
  * @param epObject|string $value The value to be set
  * @param epFieldMap $fm The field map for the value
  * @return bool
  */
 protected function _typeMatches($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->_isClassOf($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->_isClassOf($this->ep_m->getClass($v), $fm->getClass())) {
                     return false;
                 }
             }
             return true;
         }
     }
     return true;
 }