/**
  * Returns The SQL query join part (shared between getElementList and getElementCount)
  * @param string $mainTableName The main table name
  * @param string $join The join string to apply (ex : 'World IJ Region, Region LJ City, World IJ City')
  * @return array array($request, $joinTableNameList, $joinTableAttachements, $specificJoinConditions, $joinOrder)
  */
 public static function getJoin($mainTableName, $joinCondition)
 {
     $joinSelectRequest = '';
     // SELECT part of the request
     $joinFromRequest = '';
     // FROM part of the request
     // Parses join string (ex : 'World IJ Region, Region LJ User')
     $joinTableNameList = array();
     // Element types array (ex : [World, Region, City])
     $joinOperators = array();
     // Join operators array (ex : [IJ, LJ, RJ])
     $joinLeftTypes = array();
     // Join left types array (ex : [World, Region, World]])
     $joinRightTypes = array();
     // Join right types array (ex : [Region, City, City]])
     $joinConditions = array();
     $joinTableAttachements = array();
     // Join table attachements array (ex : [Region => World, City => [Region, World]])
     // Sets a join per table/condition match, separeted by comma (ie: 0 => Character IJ User, 1 => Character IJ Type)
     $joinList = StringTool::split(DatabaseFactory::JOIN_TABLE_SEPARATOR, $joinCondition);
     $joinOrder = array();
     // join order array (ex: ['Region'=>0, 'User'=>-1, 'Zone'=>1])
     $joinOrder[$mainTableName] = 0;
     // join order init
     foreach ($joinList as &$join) {
         // Parse join conditions and joined tables
         $joinSplit = StringTool::split(DatabaseFactory::JOIN_CONDITIONS_SEPARATOR, $join);
         $joinTables = $joinSplit[0];
         $joinCondition = isset($joinSplit[1]) ? $joinSplit[1] : NULL;
         // Separates left and right parts from spaces (ie: Character IJ Type => array(Character, IJ, Type))
         list($leftSyntax, $joinOperator, $rightSyntax) = StringTool::split(DatabaseFactory::JOIN_SYNTAX_SEPARATOR, $joinTables);
         // Scans left/right part for aliases
         $leftType = $leftSyntax;
         $rightType = $rightSyntax;
         // Gets table names from types
         $leftTableName = DatabaseFactory::getElementTableName($leftType);
         $rightTableName = DatabaseFactory::getElementTableName($rightType);
         if (isset($joinOrder[$leftTableName])) {
             $joinOrder[$rightTableName] = $joinOrder[$leftTableName] + 1;
         } elseif (isset($joinOrder[$rightTableName])) {
             $joinOrder[$leftTableName] = $joinOrder[$rightTableName] - 1;
         } else {
             LogTool::getInstance()->logWarning('Join syntax is not in the right order');
         }
         if ($leftTableName != $mainTableName && !in_array($leftTableName, $joinTableNameList)) {
             $joinTableNameList[] = $leftTableName;
         }
         if ($rightTableName != $mainTableName && !in_array($rightTableName, $joinTableNameList)) {
             $joinTableNameList[] = $rightTableName;
         }
         $joinOperators[] = $joinOperator;
         $joinLeftTypes[] = $leftType;
         $joinRightTypes[] = $rightType;
         $joinConditions[] = $joinCondition;
         $joinTableAttachements[$rightTableName][] = $leftTableName;
     }
     // Builds request field list part
     $usedTableNameList = array($mainTableName);
     $joinSelectRequest .= $mainTableName . '.*';
     foreach ($joinTableNameList as &$joinTableName) {
         $joinSelectRequest .= ', NULL AS ' . $joinTableName . DatabaseFactory::JOIN_TABLE_FIELD_SEPARATOR . ', ' . $joinTableName . '.*';
     }
     // Builds request "FROM" part
     $joinFromRequest .= ' FROM ' . $mainTableName;
     // Builds request join list part
     $specificJoinConditions = FALSE;
     $joinOperatorsCount = count($joinOperators);
     for ($fieldIndex = 0; $fieldIndex < $joinOperatorsCount; $fieldIndex++) {
         $joinOperator = $joinOperators[$fieldIndex];
         $joinLeftType = $joinLeftTypes[$fieldIndex];
         $joinRightType = $joinRightTypes[$fieldIndex];
         $joinLeftTableName = DatabaseFactory::getElementTableName($joinLeftType);
         $joinRightTableName = DatabaseFactory::getElementTableName($joinRightType);
         $joinLeftField = $joinLeftTableName . '_id';
         $joinRightField = DatabaseFactory::getParentIdColumnName($joinLeftType);
         $joinCondition = $joinConditions[$fieldIndex];
         if ($joinCondition === NULL) {
             $joinCondition = $joinRightTableName . '.' . $joinRightField . '=' . $joinLeftTableName . '.' . $joinLeftField;
         } else {
             $specificJoinConditions = TRUE;
         }
         switch ($joinOperator) {
             // Inner join
             case 'IJ':
                 $joinOperatorSql = ' INNER JOIN ';
                 break;
                 // Left join
             // Left join
             case 'LJ':
                 $joinOperatorSql = ' LEFT JOIN ';
                 break;
             default:
                 // Unknown join
                 throw new DatabaseException('Invalid join operator specified : "' . $joinOperator . '"');
         }
         // Right type already used (joining on left type)
         if (in_array($joinRightTableName, $usedTableNameList)) {
             $joinFromRequest .= $joinOperatorSql . $joinLeftTableName;
         } else {
             $joinFromRequest .= $joinOperatorSql . $joinRightTableName;
         }
         $joinFromRequest .= ' ON ' . $joinCondition;
         // Marks join types as used
         $usedTableNameList[] = array($joinLeftTableName);
         $usedTableNameList[] = array($joinRightTableName);
     }
     return array($joinSelectRequest, $joinFromRequest, $joinTableNameList, $joinTableAttachements, $specificJoinConditions, $joinOrder);
 }
 /**
  * Gets parent element from an element
  * @param Element $element The child element
  * @param string $parentClass The parent element class
  * @param string $conditions The conditions string to apply
  * @param string $orderBy The order string to apply
  * @return Element The parent element
  */
 public static function getParentElement($element, $parentClass, $conditions = NULL, $orderBy = NULL)
 {
     $logInstance = LogTool::getInstance();
     $logInstance->logDebug('Gets ' . $element->getElementClass() . ' parent ' . $parentClass . ' element...');
     // Gets parent element by type and id
     $parentIdFieldName = DatabaseFactory::getParentIdColumnName($parentClass);
     // Split parent class name for search like people_mother, to get mother_people_id field from People table
     $parentClassNameList = StringTool::split(ElementFactory::TABLE_FIELD_SEPARATOR, $parentClass);
     $parentClass = end($parentClassNameList);
     $parentId = $element->{$parentIdFieldName};
     // Parent element id is null
     if ($parentId === NULL) {
         throw new ElementException('Cannot get ' . $parentClass . ' parent for ' . $element->getElementClass() . ' with id #' . $element->id . ': ' . $parentIdFieldName . ' is NULL');
     }
     return ElementFactory::getElement($parentClass, $parentId, $conditions, $orderBy);
 }