/**
  * Gets the primary keys of the related records for *-to-many relationships
  *
  * @internal
  *
  * @param  string $class             The class to get the related primary keys for
  * @param  array  &$values           The values for the fActiveRecord class
  * @param  array  &$related_records  The related records existing for the fActiveRecord class
  * @param  string $related_class     The class that is related to the current record
  * @param  string $route             The route to follow for the class specified
  * @return array  The primary keys of the related records
  */
 public static function getPrimaryKeys($class, &$values, &$related_records, $related_class, $route = NULL)
 {
     fActiveRecord::validateClass($related_class);
     fActiveRecord::forceConfigure($related_class);
     $table = fORM::tablize($class);
     $related_table = fORM::tablize($related_class);
     $db = fORMDatabase::retrieve($class, 'read');
     $schema = fORMSchema::retrieve($class);
     $route = fORMSchema::getRouteName($schema, $table, $related_table, $route, '*-to-many');
     if (!isset($related_records[$related_table])) {
         $related_records[$related_table] = array();
     }
     if (!isset($related_records[$related_table][$route])) {
         $related_records[$related_table][$route] = array();
     }
     $related_info =& $related_records[$related_table][$route];
     if (!isset($related_info['primary_keys'])) {
         if (isset($related_info['record_set'])) {
             $related_info['primary_keys'] = $related_info['record_set']->getPrimaryKeys();
             // If we don't have a record set yet we want to use a single SQL query to just get the primary keys
         } else {
             $relationship = fORMSchema::getRoute($schema, $table, $related_table, $route, '*-to-many');
             $related_pk_columns = $schema->getKeys($related_table, 'primary');
             $column_info = $schema->getColumnInfo($related_table);
             $column = $relationship['column'];
             $aliased_related_pk_columns = array();
             foreach ($related_pk_columns as $related_pk_column) {
                 // We explicitly alias the columns due to SQLite issues
                 $aliased_related_pk_columns[] = $db->escape("%r AS %r", $related_table . '.' . $related_pk_column, $related_pk_column);
             }
             if (isset($relationship['join_table'])) {
                 $table_with_route = $table . '{' . $relationship['join_table'] . '}';
             } else {
                 $table_with_route = $table . '{' . $relationship['related_column'] . '}';
             }
             $column = $relationship['column'];
             $related_column = $relationship['related_column'];
             $params = array($db->escape(sprintf("SELECT %s FROM :from_clause WHERE", join(', ', $aliased_related_pk_columns)) . " %r = ", $table_with_route . '.' . $column));
             $params[0] .= $schema->getColumnInfo($table, $column, 'placeholder');
             $params[] = $values[$column];
             $params[0] .= " :group_by_clause ";
             if (!($order_bys = self::getOrderBys($class, $related_class, $route))) {
                 $order_bys = array();
                 foreach ($related_pk_columns as $related_pk_column) {
                     $order_bys[$related_pk_column] = 'ASC';
                 }
             }
             $params[0] .= " ORDER BY ";
             $params = fORMDatabase::addOrderByClause($db, $schema, $params, $related_table, $order_bys);
             $params = fORMDatabase::injectFromAndGroupByClauses($db, $schema, $params, $related_table);
             $result = call_user_func_array($db->translatedQuery, $params);
             $primary_keys = array();
             foreach ($result as $row) {
                 if (sizeof($row) > 1) {
                     $primary_key = array();
                     foreach ($row as $column => $value) {
                         $value = $db->unescape($column_info[$column]['type'], $value);
                         $primary_key[$column] = $value;
                     }
                     $primary_keys[] = $primary_key;
                 } else {
                     $column = key($row);
                     $primary_keys[] = $db->unescape($column_info[$column]['type'], $row[$column]);
                 }
             }
             $related_info['record_set'] = NULL;
             $related_info['count'] = sizeof($primary_keys);
             $related_info['associate'] = FALSE;
             $related_info['primary_keys'] = $primary_keys;
         }
     }
     return $related_info['primary_keys'];
 }
 /**
  * Adds an `ORDER BY` clause to the SQL for the primary keys of this record set
  * 
  * @param  fDatabase $db             The database the query will be executed on 
  * @param  fSchema   $schema         The schema for the database
  * @param  array     $params         The parameters for the fDatabase::query() call
  * @param  string    $related_class  The related class to add the order bys for
  * @param  string    $route          The route to this table from another table
  * @return array  The params with the `ORDER BY` clause added
  */
 private function addOrderByParams($db, $schema, $params, $related_class, $route = NULL)
 {
     $table = fORM::tablize($this->class);
     $table_with_route = $route ? $table . '{' . $route . '}' : $table;
     $pk_columns = $schema->getKeys($table, 'primary');
     $first_pk_column = $pk_columns[0];
     $escaped_pk_columns = array();
     foreach ($pk_columns as $pk_column) {
         $escaped_pk_columns[$pk_column] = $db->escape('%r', $table_with_route . '.' . $pk_column);
     }
     $column_info = $schema->getColumnInfo($table);
     $sql = '';
     $number = 0;
     foreach ($this->getPrimaryKeys() as $primary_key) {
         $sql .= 'WHEN ';
         if (is_array($primary_key)) {
             $conditions = array();
             foreach ($pk_columns as $pk_column) {
                 $value = $primary_key[$pk_column];
                 // This makes sure the query performs the way an insert will
                 if ($value === NULL && $column_info[$pk_column]['not_null'] && $column_info[$pk_column]['default'] !== NULL) {
                     $value = $column_info[$pk_column]['default'];
                 }
                 $conditions[] = str_replace('%r', $escaped_pk_columns[$pk_column], fORMDatabase::makeCondition($schema, $table, $pk_column, '=', $value));
                 $params[] = $value;
             }
             $sql .= join(' AND ', $conditions);
         } else {
             $sql .= str_replace('%r', $escaped_pk_columns[$first_pk_column], fORMDatabase::makeCondition($schema, $table, $first_pk_column, '=', $primary_key));
             $params[] = $primary_key;
         }
         $sql .= ' THEN ' . $number . ' ';
         $number++;
     }
     $params[0] .= 'CASE ' . $sql . 'END ASC';
     if ($related_order_bys = fORMRelated::getOrderBys($this->class, $related_class, $route)) {
         $params[0] .= ', ';
         $params = fORMDatabase::addOrderByClause($db, $schema, $params, fORM::tablize($related_class), $related_order_bys);
     }
     return $params;
 }