cjp2600
7/17/2013 - 12:27 PM

dbCJP - ORM касс для Bitrix framework

dbCJP - ORM касс для Bitrix framework

<?php
/**
 * ActiveRecords класс для Bitrix framework
 * Date: 16.07.13
 * Time: 15:12
 * Автор: cjp2600, email: cjp2600@ya.ru
 */

class dbCJP
{
    private $_table_name;
    private $_data;
    private $_where = '';
    private $_ar_where = array();
    private $_ar_wherein = array();
    private $_ar_like = array();
    private $_dirty_fields = array();
    private $_expr_fields = array();
    private $_ar_get = array();
    private $_ar_limit = array();
    private $_ar_sort_by = '';
    private $_sort_by    = '';
    private $_limit = '';
    private $_ar_offset = array();
    private $_count_get = NULL;

    /**
     * Конфиг с параметрами по умолчани.
     * @var array
     */
    private $_config = array(
        'table'      => 'default_table_name',
        'engine'     => 'MyISAM',
        'cache'      => FALSE,
        'cache_time' => 3600
    );

    /**
     * Конструктор класса
     * @param null $table_name
     * @param array $data
     */
    private function __construct($table_name = null, $data = array())
    {
        if ((is_null($table_name)) && (count($data) > 0)) {
            $this->_config['table'] = (isset($data['table'])) ? $data['table'] : $this->_config['table'];
        } else {
            $this->_config['table'] = $table_name;
        }
        $this->_table_name = $this->_config['table'];
        self::__config_build($data);
    }

    /**
     * Обновляем переменные.
     */
    private function reset()
    {
        $this->_where = '';
        $this->_ar_where = array();
        $this->_ar_wherein = array();
        $this->_ar_like = array();
        $this->_dirty_fields = array();
        $this->_expr_fields = array();
        $this->_ar_get = array();
        $this->_ar_limit = array();
        $this->_limit = '';
        $this->_ar_offset = array();
        $this->_count_get = NULL;
    }

    /**
     * @param $config
     * @return dbCJP
     */
    public static function init($config)
    {
        return new self(null, $config);
    }

    /**
     * @param $array
     */
    private function __config_build($array){
        if (!is_null($array) && is_array($array) && count($array)>0 ) {
            foreach ($array as $k=>$v){
                $this->_config[$k] = $v;
            }
        }
    }

    /**
     * @param $table_name
     * @return dbCJP
     */
    public static function table($table_name)
    {
        return new self($table_name, array());
    }

    /**
     * @param $value
     * @return int|string
     */
    private function escape($value)
    {
        if (is_string($value)) {
            $str = "'" . self::escape_str($value) . "'";
        } elseif (is_numeric($value)) {
            $str = "'$value'";
        } elseif (is_bool($value)) {
            $str = ($value === FALSE) ? 0 : 1;
        } elseif (is_null($value)) {
            $str = 'NULL';
        }
        return $str;
    }

    /**
     * @param $str
     * @return string
     */
    private function escape_str($str)
    {
        return preg_quote($str);
    }

    /**
     * Создаем таблицу
     * @param $data_array
     * @param $premaryfeid
     * @return mixed
     */
    private function _create($data_array, $PRIMARY)
    {
        global $DB;
        $sql = "CREATE TABLE IF NOT EXISTS `{$this->_table_name}` (";
        $sql .= "`$PRIMARY` int(11) NOT NULL AUTO_INCREMENT,";
        foreach ($data_array as $key => $val) {
            $sql .= "`$key` $val " . ",";
        }
        $sql .= "PRIMARY KEY (`$PRIMARY`) ";
        $sql .= ") ENGINE={$this->_config['engine']} AUTO_INCREMENT=1;";
        return $DB->Query($sql, false, "File: " . __FILE__ . "<br>Line: " . __LINE__);
    }

    /**
     * @param $data_array
     * @param string $PRIMARY
     * @return bool|mixed
     */
    public function create($data_array, $PRIMARY = "id")
    {
        return (is_array($data_array) && count($data_array) > 0) ? self::_create($data_array, $PRIMARY) : false;
    }

    /**
     * @param $data_array
     * @return bool
     */
    public function insert($data_array = null, $is_uniq = FALSE)
    {
        global $DB;
        if (!is_null($data_array)) {
            if ((is_array($data_array) && count($data_array) > 0)) {
                if ($is_uniq) {
                    if (self::where($data_array)->count() > 0) {
                        return FALSE;
                    }
                }
                $ID = $DB->Add($this->_table_name, $data_array);
                self::reset();
                return $ID;

            }
        } else {
            $inDA = self::get_object_rows();
            if ($inDA) {
                if ($is_uniq) {
                    if (self::where($inDA)->count() > 0) {
                        self::reset();
                        return FALSE;
                    }
                }
                $ID = $DB->Add($this->_table_name, $inDA);
                self::reset();
                return $ID;
            }
        }
        return FALSE;
    }

    /**
     * @param null $data_array
     * @param null $where
     * @return bool
     */
    public function update($data_array = null, $where = null)
    {
        global $DB;
        self::_b_where();
        if (is_null($where)||!is_array($where)||count($where)==0){
            $strw = $this->_where;
        } else {
            $strw = " WHERE ";
            $strw .= self::__where_array($where);
        }
        if (!is_null($data_array)) {
                $strUpdate = self::__where_array($data_array,",");
                if($strUpdate!="")
                {
                    $strSql = "UPDATE $this->_table_name SET ".$strUpdate." {$strw} ";
                    $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
                    self::reset();
                    return true;
                }
        } else {
            $inDA = self::get_object_rows();
            if ($inDA) {
                $strUpdate = self::__where_array($inDA,",");
                if($strUpdate!="")
                {
                    $strSql = "UPDATE $this->_table_name SET ".$strUpdate." {$strw} ";
                    $DB->Query($strSql, false, "File: ".__FILE__."<br>Line: ".__LINE__);
                    self::reset();
                    return true;
                }
            }
        }
       return false;
    }

    /**
     * @param null $where
     * @return mixed
     */
    public function delete($where = null)
    {
        global $DB;  self::_b_where();
        if (is_null($where)||!is_array($where)||count($where)==0){
            $strw = $this->_where;
        } else {
            $strw = " WHERE ";
            $strw .= self::__where_array($where);
        }
        $DB->StartTransaction();
        $res = $DB->Query("DELETE FROM {$this->_table_name} {$strw} {$this->_sort_by} {$this->_limit}", false, "File: ".__FILE__."<br>Line: ".__LINE__);
        if($res)
            $DB->Commit();
        else
            $DB->Rollback();
        return $res;
    }


    /**
     * Set LIMIT value
     * @param    integer    the limit value
     * @param    integer    the offset value
     * @return    object
     */
    public function limit($value, $offset = '')
    {
        $this->_ar_limit = (int)$value;
        if ($offset != '') {
            $this->_ar_offset = (int)$offset;
        }
        return $this;
    }

    /**
     * Set OFFSET
     * @param    integer    the offset value
     * @return    object
     */
    public function offset($offset)
    {
        $this->_ar_offset = $offset;
        return $this;
    }

    /**
     * Sets the ORDER BY value
     *
     * @access	public
     * @param	string
     * @param	string	direction: asc or desc
     * @return	object
     */
    function order_by($orderby, $direction = '')
    {
        if (strtolower($direction) == 'random')
        {
            $orderby = '';
            $direction = 'RAND()';
        }
        elseif (trim($direction) != '')
        {
            $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC';
        }
        if (strpos($orderby, ',') !== FALSE)
        {
            $temp = array();
            foreach (explode(',', $orderby) as $part)
            {
                $part = trim($part);
                $temp[] = $part;
            }
            $orderby = implode(', ', $temp);
        }
        else if ($direction != 'RAND()')
        {
            $orderby = $orderby;
        }

        $orderby_statement = $orderby.$direction;
        $this->_ar_sort_by = $orderby_statement;

        return $this;
    }

    /**
     * @return array
     */
    function get_column()
    {
        global $DB;
        $strSql = "SHOW COLUMNS FROM " . $this->_table_name;
        $res = $DB->Query($strSql, false, "File: " . __FILE__ . "<br>Line: " . __LINE__);
        $colAr = array();
        while ($arRes = $res->NavNext(true, "f_")) {
            $colAr[] = $arRes['Field'];
        }
        return $colAr;
    }

    /**
     * @param $key
     * @param null $value
     * @param string $type
     * @return $this
     */
    function where($key, $value = NULL, $type = 'AND')
    {
        if (!is_array($key)) {
            $key = array($key => $value);
        }
        foreach ($key as $k => $v) {
            $prefix = (count($this->_ar_where) > 0) ? $type : '';
            if (!self::_has_operator($k)) {
                $k .= ' = ';
            }
            $v = self::escape($v);
            $this->_ar_where[] = ' ' . $prefix . ' ' . $k . $v;
        }
        return $this;
    }

    /**
     * @param $str
     * @return bool
     */
    function _has_operator($str)
    {
        $str = trim($str);
        if (!preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str)) {
            return FALSE;
        }
        return TRUE;
    }

    /**
     * Строим sql для where и like
     */
    private function _b_where()
    {
        if (count($this->_ar_like) > 0) {
            $this->_ar_where[] = implode($this->_ar_like);
        }
        if (strlen($this->_ar_sort_by)>0) {
            $this->_sort_by = " ORDER BY ".$this->_ar_sort_by;
        }
        $whstr = (count($this->_ar_where) > 0) ? ' WHERE ' : '';
        $this->_where = $whstr . implode($this->_ar_where);

        if (is_numeric($this->_ar_limit)) {
            $offsetstr = (is_numeric($this->_ar_offset)) ? ", " . $this->_ar_offset : '';
            $this->_limit = " LIMIT " . $this->_ar_limit . $offsetstr;
        }
    }

    /**
     * @param $key
     * @param null $value
     * @param string $type
     * @return $this
     */
    function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ')
    {
        if ($key === NULL OR $values === NULL) {
            return;
        }
        if (!is_array($values)) {
            $values = array($values);
        }
        $not = ($not) ? ' NOT' : '';
        foreach ($values as $value) {
            $this->_ar_wherein[] = self::escape($value);
        }
        $prefix = (count($this->_ar_where) == 0) ? '' : " " . $type . " ";
        $where_in = $prefix . $key . $not . " IN (" . implode(", ", $this->_ar_wherein) . ") ";
        $this->_ar_where[] = $where_in;
        $this->_ar_wherein = array();
        return $this;
    }

    /**
     * @param null $key
     * @param null $values
     * @return $this
     */
    function where_in($key = NULL, $values = NULL)
    {
        return self::_where_in($key, $values);
    }

    /**
     * @param null $key
     * @param null $values
     * @return $this
     */
    function or_where_in($key = NULL, $values = NULL)
    {
        return self::_where_in($key, $values, FALSE, 'OR');
    }

    /**
     * @param null $key
     * @param null $values
     * @return $this
     */
    function where_not_in($key = NULL, $values = NULL)
    {
        return self::_where_in($key, $values, TRUE);
    }

    /**
     * @param null $key
     * @param null $values
     * @return $this
     */
    function or_where_not_in($key = NULL, $values = NULL)
    {
        return self::_where_in($key, $values, TRUE, 'OR');
    }

    /**
     * @param $field
     * @param string $match
     * @param string $type
     * @param string $side
     * @param string $not
     */
    private function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '')
    {
        if (!is_array($field)) {
            $field = array($field => $match);
        }
        foreach ($field as $k => $v) {
            $prefix = (count($this->_ar_like) > 0) ? ' ' . $type . ' ' : '';
            $v = self::escape_str($v);

            if ($side == 'before') {
                $like_statement = $prefix . " $k $not LIKE '%{$v}'";
            } elseif ($side == 'after') {
                $like_statement = $prefix . " $k $not LIKE '{$v}%'";
            } else {
                $like_statement = $prefix . " $k $not LIKE '%{$v}%'";
            }
            $this->_ar_like[] = $like_statement;
        }
        return $this;
    }

    /**
     * @param $field
     * @param string $match
     * @param string $side
     * @return $this
     */
    function like($field, $match = '', $side = 'both')
    {
        return self::_like($field, $match, 'AND ', $side);
    }

    /**
     * @param $field
     * @param string $match
     * @param string $side
     * @return $this
     */
    function not_like($field, $match = '', $side = 'both')
    {
        return self::_like($field, $match, 'AND ', $side, 'NOT');
    }

    /**
     * @param $field
     * @param string $match
     * @param string $side
     * @return $this
     */
    function or_like($field, $match = '', $side = 'both')
    {
        return self::_like($field, $match, 'OR ', $side);
    }

    /**
     * @param $field
     * @param string $match
     * @param string $side
     * @return $this
     */
    function or_not_like($field, $match = '', $side = 'both')
    {
        return $this->_like($field, $match, 'OR ', $side, 'NOT');
    }


    /**
     * @param $key
     * @param null $value
     * @return $this
     */
    function or_where($key, $value = NULL)
    {
        return self::where($key, $value, 'OR');
    }

    /**
     * @return int
     */
    private function count()
    {
        self::_b_where();
        global $DB;
        $strSql = "
			SELECT COUNT(*) AS CNT
			FROM `{$this->_table_name}` {$this->_where}
		";
        $res = $DB->Query($strSql, false, "File: " . __FILE__ . "<br>Line: " . __LINE__);
        if ($res_arr = $res->Fetch())
            return intval($res_arr["CNT"]);
        else
            return 0;
    }

    /**
     * @param $array
     * @param string $type
     * @return string
     */
    private function __where_array($array,$type = "AND"){
        $reAr = array();
        foreach ($array as $k=>$v) {
            if (!self::_has_operator($k)) {
                $k .= ' = ';
            }
            $reAr[] = $k.self::escape($v);
        }
        return implode($reAr," ".$type." ");
    }

    /**
     * @param $array
     */
    private function __update_array($array){
        $reAr = array();
        foreach ($array as $k=>$v){
            $reAr[] = "`".$k."` = ". self::escape($v) ."";
        }
        //$reAr =
    }


    /**
     * Обработчик
     * @return $this
     */
    public function get()
    {
        self::_b_where();
        global $DB;
        $strSql = "
			SELECT * FROM `{$this->_table_name}` {$this->_where} {$this->_sort_by} {$this->_limit}
		";
        $result = $DB->Query($strSql, false, "File: " . __FILE__ . "<br>Line: " . __LINE__);
        $i = 0;
        while ($arRes = $result->NavNext(true, "f_")) {
            $this->_ar_get[] = (object)$arRes;
            $i++;
        }
        $this->_count_get = $i;
        return $this;
    }

    /**
     * Получаем массив объектов значений таблицы
     * @return array
     */
    public function result()
    {
        return $this->_ar_get;
    }

    /**
     * Еденичное получение данных.
     * @return mixed
     */
    public function row()
    {
        return $this->_ar_get[0];
    }

    /**
     * Функция получения общего числа записей
     * В зависимости от выборки.
     * @return int|null
     */
    public function count_rows()
    {
        return (is_null($this->_count_get)) ? self::count() : $this->_count_get;
    }

    /**
     * Преобразовываем объекты для получение полей таблицы.
     * @param $object
     * @return array
     */
    private function _object_to_array($object)
    {
        if (!is_object($object)) {
            return $object;
        }
        $array = array();
        foreach (get_object_vars($object) as $key => $val) {
            if (!is_object($val) && !is_array($val) && (in_array($key, self::get_column()))) {
                $array[$key] = $val;
            }
        }
        return $array;
    }

    /**
     * Обвертка для получение массива данных полей их объектов.
     * @return array|bool
     */
    private function get_object_rows()
    {
        $data = self::_object_to_array($this);
        return (count($data) > 0) ? $data : false;
    }

}