/**
  *    List models
  *
  * @param Charcoal_Sandbox $sandbox
  * @param int $find_path
  *
  * @return Charcoal_ITableModel[]
  */
 public function listModels($sandbox, $find_path)
 {
     // get root path of framework,project,web_app
     $dir_framework = Charcoal_ResourceLocator::getFrameworkPath();
     $dir_project = Charcoal_ResourceLocator::getProjectPath();
     $dir_application = Charcoal_ResourceLocator::getApplicationPath();
     // get module root path of framework,project,web_app
     $dir_framework_module = $dir_framework . '/module';
     $dir_project_module = $dir_project . '/module';
     $dir_application_module = $dir_application . '/module';
     $config_target_list = array();
     if (Charcoal_System::isAnyBitSet($find_path, Charcoal_EnumFindPath::FIND_PATH_FRAMEWORK)) {
         $config_target_list[] = $dir_framework . '/config/table_model';
         $config_target_list[] = $dir_framework_module . '/config/table_model';
     }
     if (Charcoal_System::isAnyBitSet($find_path, Charcoal_EnumFindPath::FIND_PATH_PROJECT)) {
         $config_target_list[] = $dir_project . '/config/table_model';
         $config_target_list[] = $dir_project_module . '/config/table_model';
     }
     if (Charcoal_System::isAnyBitSet($find_path, Charcoal_EnumFindPath::FIND_PATH_APPLICATION)) {
         $config_target_list[] = $dir_application . '/config/table_model';
         $config_target_list[] = $dir_application_module . '/config/table_model';
     }
     // find model names in target directory
     $table_model_names = array();
     foreach ($config_target_list as $path) {
         $found_models = $sandbox->getRegistry()->listObjects($path, 'table_model');
         $table_model_names = array_merge($table_model_names, $found_models);
     }
     // convert model name into table model instance
     $table_models = array();
     foreach ($table_model_names as $model_name) {
         $model = $this->getModel($model_name);
         if ($model && $model instanceof Charcoal_ITableModel) {
             $table_models[$model_name] = $model;
         }
     }
     return $table_models;
 }
 /**
  *    Generate RDBMS-specific SQL for SELECT
  *
  *    @param Charcoal_ITableModel $model        table model object related with th query
  *    @param string $alias                      table model alias which is specified by $model
  *    @param int $options                       options for SQL generation
  *    @param Charcoal_SQLCriteria $criteria     criteria which should be used in WHERE clause
  *    @param array $joins                       list of join(list of Charcoal_QueryJoin object)
  *    @param array $fields                      list of fields which will be returned in query result
  *
  *    @return string                            SQL
  */
 public function buildSelectSQL($model, $alias, $options, $criteria, $joins, $fields = NULL)
 {
     Charcoal_ParamTrait::validateIsA(1, 'Charcoal_ITableModel', $model);
     Charcoal_ParamTrait::validateString(2, $alias, TRUE);
     Charcoal_ParamTrait::validateInteger(3, $options);
     Charcoal_ParamTrait::validateIsA(4, 'Charcoal_SQLCriteria', $criteria);
     Charcoal_ParamTrait::validateVector(5, $joins);
     Charcoal_ParamTrait::validateVector(6, $fields, NULL);
     $options = ui($options);
     $alias = us($alias);
     $table = $model->getTableName();
     $fields = v($fields)->join(",");
     if (Charcoal_System::isAnyBitSet($options, Charcoal_EnumQueryOption::DISTINCT)) {
         $sql = "SELECT DISTINCT {$fields} FROM " . us($table);
     } else {
         $sql = "SELECT {$fields} FROM " . us($table);
     }
     if ($alias && !empty($alias)) {
         $sql .= ' AS ' . $alias;
     }
     foreach ($joins as $join) {
         /** @var Charcoal_QueryJoin $join */
         $join_type = $join->getJoinType();
         $join_model_name = $join->getModelName();
         $join_alias = $join->getAlias();
         $join_cond = $join->getCondition();
         $join_model = $this->getSandbox()->createObject($join_model_name, 'table_model');
         /** @var Charcoal_ITableModel $join_model */
         switch ($join_type) {
             case Charcoal_EnumSQLJoinType::INNER_JOIN:
                 $sql .= ' INNER JOIN ' . $join_model->getTableName();
                 break;
             case Charcoal_EnumSQLJoinType::LEFT_JOIN:
                 $sql .= ' LEFT JOIN ' . $join_model->getTableName();
                 break;
             case Charcoal_EnumSQLJoinType::RIGHT_JOIN:
                 $sql .= ' RIGHT JOIN ' . $join_model->getTableName();
                 break;
         }
         if ($join_alias && !empty($join_alias)) {
             $sql .= ' AS ' . $join_alias;
         }
         if ($join_cond && !empty($join_cond)) {
             $sql .= ' ON ' . $join_cond;
         }
     }
     $where_clause = $criteria->getWhere();
     $order_by = $criteria->getOrderBy();
     $limit = $criteria->getLimit();
     $offset = $criteria->getOffset();
     $group_by = $criteria->getGroupBy();
     if (!empty($where_clause)) {
         $sql .= ' WHERE ' . $where_clause;
     }
     if (!empty($group_by)) {
         $sql .= ' GROUP BY ' . $group_by;
     }
     if (!empty($order_by)) {
         $sql .= ' ORDER BY ' . $order_by;
     }
     if (!empty($limit)) {
         $sql .= ' LIMIT ' . $limit;
     }
     if (!empty($offset)) {
         $sql .= ' OFFSET ' . $offset;
     }
     if (Charcoal_System::isAnyBitSet($options, Charcoal_EnumQueryOption::FOR_UPDATE)) {
         $sql .= " FOR UPDATE";
     }
     return $sql;
 }