<commit_before><?php

class Application_Model_Preference
{
    
    private static function getUserId()
    {
        //pass in true so the check is made with the autoloader
        //we need this check because saas calls this function from outside Zend
        if (!class_exists("Zend_Session", true) || !Zend_Session::isStarted() || !class_exists("Zend_Auth", true) || !Zend_Auth::getInstance()->hasIdentity()) {
            $userId = null;
        } else {
            $auth = Zend_Auth::getInstance();
            $userId = $auth->getIdentity()->id;
        }
        
        return $userId;
    }
    
    /**
     *
     * @param boolean $isUserValue is true when we are setting a value for the current user
     */
    private static function setValue($key, $value, $isUserValue = false)
    {
        $con = Propel::getConnection(CcPrefPeer::DATABASE_NAME);

        //We are using row-level locking in Postgres via "FOR UPDATE" instead of a transaction here
        //because sometimes this function needs to be called while a transaction is already started.

        try {
            /* Comment this out while we reevaluate it in favor of a unique constraint
            static::_lock($con); */
            $userId = self::getUserId();
            
            if ($isUserValue && is_null($userId)) {
                throw new Exception("User id can't be null for a user preference {$key}.");
            }

            //Check if key already exists
            $sql = "SELECT valstr FROM cc_pref"
                ." WHERE keystr = :key";
            
            $paramMap = array();
            $paramMap[':key'] = $key;
            
            //For user specific preference, check if id matches as well
            if ($isUserValue) {
                $sql .= " AND subjid = :id";
                $paramMap[':id'] = $userId;
            }

            $sql .= " FOR UPDATE";

            $result = Application_Common_Database::prepareAndExecute($sql, 
                    $paramMap, 
                    Application_Common_Database::ROW_COUNT,
                    PDO::FETCH_ASSOC,
                    $con);

            $paramMap = array();
            if ($result > 1) {
                //this case should not happen.
                throw new Exception("Invalid number of results returned. Should be ".
                    "0 or 1, but is '$result' instead");
            } else if ($result == 1) {
                
                // result found
                if (!$isUserValue) {
                    // system pref
                    $sql = "UPDATE cc_pref"
                        ." SET subjid = NULL, valstr = :value"
                        ." WHERE keystr = :key";
                } else {
                    // user pref
                    $sql = "UPDATE cc_pref"
                        . " SET valstr = :value"
                        . " WHERE keystr = :key AND subjid = :id";
                   
                    $paramMap[':id'] = $userId;
                }
            } else {
                
                // result not found
                if (!$isUserValue) {
                    // system pref
                    $sql = "INSERT INTO cc_pref (keystr, valstr)"
                        ." VALUES (:key, :value)";
                } else {
                    // user pref
                    $sql = "INSERT INTO cc_pref (subjid, keystr, valstr)"
                        ." VALUES (:id, :key, :value)";
                   
                    $paramMap[':id'] = $userId;
                }
            }
            $paramMap[':key'] = $key;
            $paramMap[':value'] = $value;

            Application_Common_Database::prepareAndExecute($sql, 
                    $paramMap,
                    Application_Common_Database::EXECUTE,
                    PDO::FETCH_ASSOC, 
                    $con);

        } catch (Exception $e) {
            header('HTTP/1.0 503 Service Unavailable');
            Logging::info("Database error: ".$e->getMessage());
            exit;
        }
    }

    /**
     * Given a PDO connection, lock the cc_pref table for the current transaction
     *
     * Creates a table level lock, which defaults to ACCESS EXCLUSIVE mode;
     * see http://www.postgresql.org/docs/9.1/static/explicit-locking.html
     *
     * @param PDO $con
     */
    private static function _lock($con) {
        // If we're not in a transaction, a lock is pointless
        if (!$con->inTransaction()) {
            return;
        }
        // Don't specify NOWAIT here; we should block on obtaining this lock
        // in case we're handling simultaneous requests.
        // Locks only last until the end of the transaction, so we shouldn't have to
        // worry about this causing any noticeable difference in request processing speed
        $sql = "LOCK TABLE cc_pref";
        $st = $con->prepare($sql);
        $st->execute();
    }

    /**
     * @param string $key               the preference key string
     * @param bool|false $isUserValue   select the preference for the current user
     * @param bool|false $forceDefault  only look for default (no user ID) values
     * @return mixed the preference value
     */
    private static function getValue($key, $isUserValue = false, $forceDefault = false)
    {
        try {
            
            $userId = null;
            if ($isUserValue) {
                //This is nested in here because so we can still use getValue() when the session hasn't started yet.
                $userId = self::getUserId();
                if (is_null($userId)) {
                    throw new Exception("User id can't be null for a user preference.");
                }
            }

            //Check if key already exists
            $sql = "SELECT COUNT(*) FROM cc_pref"
            ." WHERE keystr = :key";
            
            $paramMap = array();
            $paramMap[':key'] = $key;
            
            //For user specific preference, check if id matches as well
            if ($isUserValue) {
                $sql .= " AND subjid = :id";
                $paramMap[':id'] = $userId;
            } else if ($forceDefault) {
                $sql .= " AND subjid IS NULL";
            }

            $result = Application_Common_Database::prepareAndExecute($sql, $paramMap, Application_Common_Database::COLUMN);

            //return an empty string if the result doesn't exist.
            if ($result == 0) {
                $res = "";
            } else {
                $sql = "SELECT valstr FROM cc_pref"
                ." WHERE keystr = :key";
                
                $paramMap = array();
                $paramMap[':key'] = $key;

                //For user specific preference, check if id matches as well
                if ($isUserValue) {
                    $sql .= " AND subjid = :id";
                    $paramMap[':id'] = $userId;
                }
                
                $result = Application_Common_Database::prepareAndExecute($sql, $paramMap, Application_Common_Database::COLUMN);

                $res = ($result !== false) ? $result : "";
            }
            
            return $res;
        } 
        catch (Exception $e) {
            header('HTTP/1.0 503 Service Unavailable');
            Logging::info("Could not connect to database: ".$e);
            exit;
        }
    }

    public static function GetHeadTitle()
    {
        $title = self::getValue("station_name");
        if (strlen($title) > 0)
            $title .= " - ";

        return $title.PRODUCT_NAME;
    }

    public static function SetHeadTitle($title, $view=null)
    {
        self::setValue("station_name", $title);

        // in case this is called from airtime-saas script
        if ($view !== null) {
            //set session variable to new station name so that html title is updated.
            //should probably do this in a view helper to keep this controller as minimal as possible.
            $view->headTitle()->exchangeArray(array()); //clear headTitle ArrayObject
            $view->headTitle(self::GetHeadTitle());
        }

        $eventType = "update_station_name";
        $md = array("station_name"=>$title);

        Application_Model_RabbitMq::SendMessageToPypo($eventType, $md);
    }<commit_msg>:sparkles: Do not add LibreTime to title if station name is set<commit_after><?php

class Application_Model_Preference
{
    
    private static function getUserId()
    {
        //pass in true so the check is made with the autoloader
        //we need this check because saas calls this function from outside Zend
        if (!class_exists("Zend_Session", true) || !Zend_Session::isStarted() || !class_exists("Zend_Auth", true) || !Zend_Auth::getInstance()->hasIdentity()) {
            $userId = null;
        } else {
            $auth = Zend_Auth::getInstance();
            $userId = $auth->getIdentity()->id;
        }
        
        return $userId;
    }
    
    /**
     *
     * @param boolean $isUserValue is true when we are setting a value for the current user
     */
    private static function setValue($key, $value, $isUserValue = false)
    {
        $con = Propel::getConnection(CcPrefPeer::DATABASE_NAME);

        //We are using row-level locking in Postgres via "FOR UPDATE" instead of a transaction here
        //because sometimes this function needs to be called while a transaction is already started.

        try {
            /* Comment this out while we reevaluate it in favor of a unique constraint
            static::_lock($con); */
            $userId = self::getUserId();
            
            if ($isUserValue && is_null($userId)) {
                throw new Exception("User id can't be null for a user preference {$key}.");
            }

            //Check if key already exists
            $sql = "SELECT valstr FROM cc_pref"
                ." WHERE keystr = :key";
            
            $paramMap = array();
            $paramMap[':key'] = $key;
            
            //For user specific preference, check if id matches as well
            if ($isUserValue) {
                $sql .= " AND subjid = :id";
                $paramMap[':id'] = $userId;
            }

            $sql .= " FOR UPDATE";

            $result = Application_Common_Database::prepareAndExecute($sql, 
                    $paramMap, 
                    Application_Common_Database::ROW_COUNT,
                    PDO::FETCH_ASSOC,
                    $con);

            $paramMap = array();
            if ($result > 1) {
                //this case should not happen.
                throw new Exception("Invalid number of results returned. Should be ".
                    "0 or 1, but is '$result' instead");
            } else if ($result == 1) {
                
                // result found
                if (!$isUserValue) {
                    // system pref
                    $sql = "UPDATE cc_pref"
                        ." SET subjid = NULL, valstr = :value"
                        ." WHERE keystr = :key";
                } else {
                    // user pref
                    $sql = "UPDATE cc_pref"
                        . " SET valstr = :value"
                        . " WHERE keystr = :key AND subjid = :id";
                   
                    $paramMap[':id'] = $userId;
                }
            } else {
                
                // result not found
                if (!$isUserValue) {
                    // system pref
                    $sql = "INSERT INTO cc_pref (keystr, valstr)"
                        ." VALUES (:key, :value)";
                } else {
                    // user pref
                    $sql = "INSERT INTO cc_pref (subjid, keystr, valstr)"
                        ." VALUES (:id, :key, :value)";
                   
                    $paramMap[':id'] = $userId;
                }
            }
            $paramMap[':key'] = $key;
            $paramMap[':value'] = $value;

            Application_Common_Database::prepareAndExecute($sql, 
                    $paramMap,
                    Application_Common_Database::EXECUTE,
                    PDO::FETCH_ASSOC, 
                    $con);

        } catch (Exception $e) {
            header('HTTP/1.0 503 Service Unavailable');
            Logging::info("Database error: ".$e->getMessage());
            exit;
        }
    }

    /**
     * Given a PDO connection, lock the cc_pref table for the current transaction
     *
     * Creates a table level lock, which defaults to ACCESS EXCLUSIVE mode;
     * see http://www.postgresql.org/docs/9.1/static/explicit-locking.html
     *
     * @param PDO $con
     */
    private static function _lock($con) {
        // If we're not in a transaction, a lock is pointless
        if (!$con->inTransaction()) {
            return;
        }
        // Don't specify NOWAIT here; we should block on obtaining this lock
        // in case we're handling simultaneous requests.
        // Locks only last until the end of the transaction, so we shouldn't have to
        // worry about this causing any noticeable difference in request processing speed
        $sql = "LOCK TABLE cc_pref";
        $st = $con->prepare($sql);
        $st->execute();
    }

    /**
     * @param string $key               the preference key string
     * @param bool|false $isUserValue   select the preference for the current user
     * @param bool|false $forceDefault  only look for default (no user ID) values
     * @return mixed the preference value
     */
    private static function getValue($key, $isUserValue = false, $forceDefault = false)
    {
        try {
            
            $userId = null;
            if ($isUserValue) {
                //This is nested in here because so we can still use getValue() when the session hasn't started yet.
                $userId = self::getUserId();
                if (is_null($userId)) {
                    throw new Exception("User id can't be null for a user preference.");
                }
            }

            //Check if key already exists
            $sql = "SELECT COUNT(*) FROM cc_pref"
            ." WHERE keystr = :key";
            
            $paramMap = array();
            $paramMap[':key'] = $key;
            
            //For user specific preference, check if id matches as well
            if ($isUserValue) {
                $sql .= " AND subjid = :id";
                $paramMap[':id'] = $userId;
            } else if ($forceDefault) {
                $sql .= " AND subjid IS NULL";
            }

            $result = Application_Common_Database::prepareAndExecute($sql, $paramMap, Application_Common_Database::COLUMN);

            //return an empty string if the result doesn't exist.
            if ($result == 0) {
                $res = "";
            } else {
                $sql = "SELECT valstr FROM cc_pref"
                ." WHERE keystr = :key";
                
                $paramMap = array();
                $paramMap[':key'] = $key;

                //For user specific preference, check if id matches as well
                if ($isUserValue) {
                    $sql .= " AND subjid = :id";
                    $paramMap[':id'] = $userId;
                }
                
                $result = Application_Common_Database::prepareAndExecute($sql, $paramMap, Application_Common_Database::COLUMN);

                $res = ($result !== false) ? $result : "";
            }
            
            return $res;
        } 
        catch (Exception $e) {
            header('HTTP/1.0 503 Service Unavailable');
            Logging::info("Could not connect to database: ".$e);
            exit;
        }
    }

    public static function GetHeadTitle()
    {
        $title = self::getValue("station_name");
        if (empty($title)) {
            $title = PRODUCT_NAME;
        }

        return $title;
    }

    public static function SetHeadTitle($title, $view=null)
    {
        self::setValue("station_name", $title);

        // in case this is called from airtime-saas script
        if ($view !== null) {
            //set session variable to new station name so that html title is updated.
            //should probably do this in a view helper to keep this controller as minimal as possible.
            $view->headTitle()->exchangeArray(array()); //clear headTitle ArrayObject
            $view->headTitle(self::GetHeadTitle());
        }

        $eventType = "update_station_name";
        $md = array("station_name"=>$title);

        Application_Model_RabbitMq::SendMessageToPypo($eventType, $md);
    }
{'fraction_non_alphanumeric': 0.10723731666265929, 'fraction_numerical': 0.0021038711228660734, 'mean_word_length': 1.4419492147365331, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '5891067', 'n_tokens_mistral': 4366, 'n_tokens_neox': 4151, 'n_words': 1311}