<commit_before><?php
/**
 * The User Settings table stores various settings/options related to the
 * application features (rather than the user profile).
 *
 * The settings are cached in the user attributes the first time one is
 * accessed via rtkUser::getUserSetting().
 *
 *
 * Methods:
 *  getDefaultSettings()
 *  getUserSettings($userId)
 *  hasUserSettings($userId)
 *  saveUserSettings($userId, $settings)
 *
 * Private:
 *  mapSettingsToCols($settings)
 */
class UsersSettingsPeer extends coreDatabaseTable
{
  protected $tableName = 'users_settings';

  // timestamp cols for self::insert/update/replace
  protected $columns = ['created_on', 'updated_on'];

  // array to map settings names to database fields
  public static $map = [
    'OPT_NO_SHUFFLE' => 'no_shuffle',
    'OPT_SRS_MAX_BOX' => 'srs_max_box',
    'OPT_SRS_MULT' => 'srs_mult',
    'OPT_SRS_HARD_BOX' => 'srs_hard_box',
  ];

  private static $defaultSettings = [
    'OPT_NO_SHUFFLE' => 0,    // do not shuffle new cards (blue pile)
    'OPT_SRS_MAX_BOX' => 7,    // num intervals (excludes Failed & New box)
    'OPT_SRS_MULT' => 205,  // 205 means 2.05
    'OPT_SRS_HARD_BOX' => 0,     // zero means default behaviour
  ];

  public static function getInstance(): self
  {
    return coreDatabaseTable::_getInstance(__CLASS__);
  }

  /**
   * Convert keys in associative array of settings to column names for database
   * updates.
   *
   * @param array $settings
   * @return array array for insert/updates
   */
  private static function mapSettingsToCols($settings)
  {
    $colData = [];
    foreach ($settings as $name => $value)
    {
      assert(array_key_exists($name, self::$map));
      $colName = self::$map[$name];
      $colData[$colName] = $value;
    }

    return $colData;
  }

  /**
   * @return array
   */
  public static function getDefaultSettings()
  {
    return self::$defaultSettings;
  }

  /**
   * Get user settings as an associative array. This function normalizes the
   * settings (numbers as integers).
   *
   * @param   int     user id
   * @param mixed $userId
   *
   * @return array Associative array (col => value) with normalized types
   */
  public static function getUserSettings($userId)
  {
    $select = self::getInstance()->select('*')->where('userid = ?', $userId)->query();
    if ($row = self::$db->fetch())
    {
      // fab: not worth making more fancy code atm ...
      $settings = [
        'OPT_NO_SHUFFLE' => $row['no_shuffle'],
        'OPT_SRS_MAX_BOX' => $row['srs_max_box'],
        'OPT_SRS_MULT' => $row['srs_mult'],
        'OPT_SRS_HARD_BOX' => $row['srs_hard_box'],
      ];
    }
    else
    {
      $settings = self::getDefaultSettings();
    }

    // normalize the settings
    $settings['OPT_NO_SHUFFLE'] = (int) $settings['OPT_NO_SHUFFLE'];
    $settings['OPT_SRS_MAX_BOX'] = (int) $settings['OPT_SRS_MAX_BOX'];
    $settings['OPT_SRS_MULT'] = (int) $settings['OPT_SRS_MULT'];
    $settings['OPT_SRS_HARD_BOX'] = (int) $settings['OPT_SRS_HARD_BOX'];

    return $settings;
  }

  public static function hasUserSettings($userId)
  {
    $count = self::getInstance()->count('userid = ?', $userId);

    return $count > 0;
  }

  public static function saveUserSettings($userId, array $settings)
  {
    // if the settings aren't saved yet, fill in the defaults
    if (!self::hasUserSettings($userId))
    {
      $defaults = self::getDefaultSettings();
      $settings = array_merge($defaults, $settings);
      $colData = self::mapSettingsToCols($settings);
      $colData['userid'] = $userId;

      return self::getInstance()->insert($colData);
    }
    else
    {
      $colData = self::mapSettingsToCols($settings);

      return self::getInstance()->update($colData, 'userid = ?', $userId);
    }
  }
}<commit_msg>(UsersSettingsPeer): improve code a bit<commit_after><?php
/**
 * The User Settings table stores various settings/options related to the
 * application features (rather than the user profile).
 *
 * The settings are cached in the user attributes the first time one is
 * accessed via rtkUser::getUserSetting().
 *
 *
 * Methods:
 *  getDefaultSettings()
 *  getUserSettings($userId)
 *  hasUserSettings($userId)
 *  saveUserSettings($userId, $settings)
 *
 * Private:
 *  mapSettingsToCols($settings)
 */
class UsersSettingsPeer extends coreDatabaseTable
{
  protected $tableName = 'users_settings';

  // timestamp cols for self::insert/update/replace
  protected $columns = ['created_on', 'updated_on'];

  // array to map settings names to database fields
  public static $map = [
    'no_shuffle' => 'OPT_NO_SHUFFLE',
    'srs_max_box' => 'OPT_SRS_MAX_BOX',
    'srs_mult' => 'OPT_SRS_MULT',
    'srs_hard_box' => 'OPT_SRS_HARD_BOX',
  ];

  private static $defaultSettings = [
    'OPT_NO_SHUFFLE' => 0,    // do not shuffle new cards (blue pile)
    'OPT_SRS_MAX_BOX' => 7,    // num intervals (excludes Failed & New box)
    'OPT_SRS_MULT' => 205,  // 205 means 2.05
    'OPT_SRS_HARD_BOX' => 0,     // zero means default behaviour
  ];

  public static function getInstance(): self
  {
    return coreDatabaseTable::_getInstance(__CLASS__);
  }

  /**
   * Swap keys in $data from SQL column names to settings names, or vice versa.
   *
   * @param array $settings ... row data (one mor more columns)
   * @param bool  $reverse
   *
   * @return array
   */
  private static function mapKeys(array $data, bool $reverse = false)
  {
    $map = $reverse ? array_flip(self::$map) : self::$map;
    $mapped_keys =array_map(fn($k) => $map[$k], array_keys($data)); 
    return array_combine($mapped_keys, $data);
  }

  /**
   * @return array
   */
  public static function getDefaultSettings()
  {
    return self::$defaultSettings;
  }

  /**
   * Get user settings as an associative array. This function normalizes the
   * settings (numbers as integers).
   *
   * @param   int     user id
   * @param mixed $userId
   *
   * @return array Associative array (col => value) with normalized types
   */
  public static function getUserSettings($userId)
  {
    $select = self::getInstance()
      ->select(array_keys(self::$map))
      ->where('userid = ?', $userId)->query();

    if ($row = self::$db->fetch())
    {
      $settings = self::mapKeys($row);
    }
    else
    {
      $settings = self::getDefaultSettings();
    }

    // normalize the settings
    $settings['OPT_NO_SHUFFLE'] = (int) $settings['OPT_NO_SHUFFLE'];
    $settings['OPT_SRS_MAX_BOX'] = (int) $settings['OPT_SRS_MAX_BOX'];
    $settings['OPT_SRS_MULT'] = (int) $settings['OPT_SRS_MULT'];
    $settings['OPT_SRS_HARD_BOX'] = (int) $settings['OPT_SRS_HARD_BOX'];

    return $settings;
  }

  public static function hasUserSettings($userId)
  {
    return self::getInstance()->count('userid = ?', $userId) > 0;
  }

  public static function saveUserSettings($userId, array $settings)
  {
    // if the settings aren't saved yet, fill in the defaults
    if (!self::hasUserSettings($userId))
    {
      $defaults = self::getDefaultSettings();
      $settings = array_merge($defaults, $settings);
      $colData = self::mapKeys($settings, true);

      $colData['userid'] = $userId;

      return self::getInstance()->insert($colData);
    }
    else
    {
      $colData = self::mapKeys($settings, true);

      return self::getInstance()->update($colData, 'userid = ?', $userId);
    }
  }
}
{'fraction_non_alphanumeric': 0.14252685978512172, 'fraction_numerical': 0.003535971712226302, 'mean_word_length': 3.385211687537269, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6521005', 'n_tokens_mistral': 2400, 'n_tokens_neox': 2352, 'n_words': 569}