Codeigniter. Создаем модель для рейтинга.

2015, 13 сентября

И так поехали объяснять как поставить codeigniter,apache и прочее я не буду и изначально расчитываю на набор необходимых знаний , создадим таблицу под нашу будущею систему оценок.
Создаем таблицу, я пишу под mysql, но если у вас есть понимание можно и под psql все сделать и так создаем:

  CREATE TABLE `rating`( `rating_id` INT(5) NOT NULL AUTO_INCREMENT, `rate` FLOAT(1), `voted` INT(7), `active` BOOL, PRIMARY KEY (`rating_id`) );

rating_id – наш ключ, по которому мы будем находить оценку и работать с ней
rate – сама оценка
voted – кол-во проголосовавших
active – возможность отключить голосовалку без удаления и вернуть обратно Как же эта система будет взаитмодействовать с другими элементами сайта, да легко. Мы просто
сможем добавить в любую таблицу например article поле rating_id, или в таблицу images то же поле
и привязать к объекту нашу оценку. Для начало создадим конфигурационный файл в папке applicationconfig создаем rating.php
И добавляем в него наши настройки

<?php
$rating_config[‘table_name’] = ‘rating’;

// Максимально допустимая оценка  
$rating_config[‘max_rate’] = 10;

//Добавляем к основному конфигу  
$config[‘rating_config’] = $rating_config;
?>

Приступим к реализации, создадим в папке applicationmodels файл Rating.php
со следующим значением:

<?
config->load('rating');
        if (($this->_table_name = $this->config->item('table_name', 'rating_config')) === FALSE) {
            //Если не получил имя таблицы, то выводим окно ошибки
            show_error('Не удалось получить имя таблицы в базе данных для системы оценок');
        }
        $this->_max_rate = $this->config->item('max_rate', 'rating_config');
    }

    /**
     * Создаем оценку
     * @param float $rate - Оценка, по умолчанию 0
     * @param int $voted - Кол-во проголосовавших
     * @param bool $active - Активировать оценку
     * @return bool - результат создания объекта
     */
    public function create($rate = 0, $voted = 0, $active = true) {
        $sql = INSERT INTO  . $this->_table_name .  (rate,voted,active) VALUES(?,?,?);;
        $this->db->query($sql, array($rate, $voted, $active));
        if ($this->db->affected_rows() > 0) {
            $this->rating_id = $this->db->insert_id();
            $this->rate = $rate;
            $this->voted = $voted;
            $this->active = $active;
            return TRUE;
        } else {
            $this->_clear_rate();
            return FALSE;
        }
    }

    /**
     * Удаляем оценку
     * @param type $id - ид оценки, если не указан ид, то пытается удалить текущий объект
     * @return boolean - результат удаления
     */
    public function delete($id = false) {
        if ($id !== false) {
            $this->db->delete($this->_table_name, array('rating_id' => $id));
        } else {
            if (is_numeric($this->rating_id)) {
                $this->db->delete($this->_table_name, array('rating_id' => $this->rating_id));
            } else {
                return FALSE;
            }
        }
        if ($this->db->affected_rows() > 0) {
            if (($id === false) || ($id == $this->rating_id)) {
                $this->_clear_rate();
            }
            return TRUE;
        } else {
            return FALSE;
        }
    }

    /**
     * Клас ищет оценку по ид
     * @param type $id - ид оценки
     * @param type $active - искать только активные
     * @return boolean - true если нашел, ну или false
     */
    public function find_by_id($id, $active = true) {
        $sql = SELECT rating_id,rate,voted,active FROM  . $this->_table_name .  WHERE rating_id=?;
        $result = null;
        if ($active) {
            $sql .=  AND active=?;
            $result = $this->db->query($sql, array($id, $active));
        } else {
            $result = $this->db->query($sql, array($id));
        }
        if ($result->num_rows() > 0) {
            $tmp = $result->row();
            $this->rating_id = $tmp->rating_id;
            $this->rate = $tmp->rate;
            $this->voted = $tmp->voted;
            $this->active = $tmp->active;
            return TRUE;
        } else {
            $this->_clear_rate();
            return FALSE;
        }
    }

    /**
     * Редактируем данные
     * @return boolean результат обновления
     */
    public function edit() {
        if (is_numeric($this->rating_id)) {
            $sql = UPDATE  . $this->_table_name .  SET rate=?,voted=?,active=? WHERE rating_id=?;
            $this->db->query($sql, array($this->rate, $this->voted, $this->active, $this->rating_id));
            if ($this->db->affected_rows() > 0) {
                return TRUE;
            } else {
                return FALSE;
            }
        } else {
            return FALSE;
        }
    }

    /**
     * Добаляем оценку
     * @param type $rate - оценка проголосовавшего
     * @param type $id - ид оценки, если не указывать, то попытается использховать текущий объект
     * @param type $ret - возращать обновленный объект или нет
     * @return boolean если $ret=true, то вернет объект с новыми данными, если $ret=false, то просто вернет true
     */
    public function add_rate($rate, $id = FALSE, $ret = TRUE) {
        $sql = UPDATE  . $this->_table_name .  SET voted = voted+1, rate = ROUND(((rate*(voted-1))+?)/voted,1)  WHERE rating_id=?;
        if ($rate > $this->_max_rate)
            $rate = $this->_max_rate;

        if ($id !== FALSE) {
            $this->db->query($sql, array($rate, $id));
        } else {
            if (is_numeric($this->rating_id)) {
                $this->db->query($sql, array($rate, $this->rating_id));
                $id = $this->rating_id;
            } else {
                return FALSE;
            }
        }

        if ($this->db->affected_rows() > 0) {
            if($ret) {
                return $this->find_by_id($id);
            }
            return TRUE;
        } else {
            return FALSE;
        }
    }

    /**
     * Удаляем значения
     */
    private function _clear_rate() {
        $this->rating_id = NULL;
        $this->rate = NULL;
        $this->voted = NULL;
        $this->active = NULL;
    }

}

?>

Как теперь с эти работать.
В контроллере загрузим нашу модель
$this->load->model(‘rating’);
При загрузке выполнится конструктор и проверит указан ли таблица. Далее мы можем создать оценку или найти ее.
Если мы используем данный объект в админке и хотим например для вновь созданой статьи добавить оценку, мы просто инициализируем нашу модель
и создаем оценку:

$this->load->model('rating');
   $this->rating->create();

В случае успеха $this->rating->create() вернет true и обновит данные внутри объекта, если же создать не удалось, то вернет false
как пример использования:

$this->load->model(‘rating’);

        if($this->rating->create()) {
echo ‘Оценка создана’;
        } else {
echo ‘Не получилось создать оценку’;
        }

После того, как мы создали объект мы можем получить данные о нем обратившись:
$this->rating->rating_id – получим ид созданой оценки
$this->rating->rate – Текущая общая оценка
$this->rating->voted – Кол-во проголосовавших
$this->rating->active – активна или нет Так же мы можем создавать оценку с уже готовыми параметрами
$this->rating->create(оценку, кол-во проголосовавших, активна или нет) После того как создали объект мы можем передать $this->rating->rating_id в нужную нам модель.
Например у нас есть модель article и в ней есть возможность к статье прикрепить оценку вызвав (article->add_rating($id_raing))
как пример:

$this->load->model(‘rating’);
       $this->load->model(‘article’);

       if($this->rating->create()) {
$this->article->add_rating($this->rating->rating_id);
       }

Как получить нам нашу оценку, наша модель article вернула нам id оценки теперь мы с помощью find_by_id можем получить объект оценку.
Пример:

$this->load->model('rating');
$this->load->model('article');
$rating_id = $this->article->get_rating_id();
if($this->rating->find_by_id($rating_id)) {
echo 'Средняя оценка: '.$this->rating->rate;
echo 'Проголосовало: '.$this->rating->voted;
}

Учтите, что find_by_id ищет оценку только ту у которой параметр active = TRUE, если вы хотите искать по всем оценками, то добавьте второй парамметр
this>rating>find_by_id(this->rating->find\_by\_id(rating_id,false); Редактирование оценки, допустим мы получили оценку и хотим ее сделать не активной, обнулив полностью, тогда код будет такой:

$this->load->model('rating');
$this->load->model('article');
$rating_id = $this->article->get_rating_id();
if($this->rating->find_by_id($rating_id)) {
$this->rating->rate = 0;
$this->rating->voted = 0;
$this->rating->active = false;
if($this->rating->edit()) {
echo 'Данные обновлены';
}
}

Добавление оценки, тут наверно оптимальней использовать ajax и контроллер, который это буедт обрабатовать:

public function add_rating($id, $paramm ) {
//тут всякие проверки и пр
$this->load->model(‘rating’);
if($this->rating->add_rate($paramm,$id)) {
echo ‘Обновленная оценка’;
echo ‘Средняя оценка:.$this->rating->rate;
echo ‘Проголосовало:.$this->rating->voted;
}
}

если мы просто хотим обновить оценку без обновления данных в объекте, то нужно указать 3 параметр в false
this>rating>add_rate(this->rating->add\_rate(paramm,$id,false) просто запишет обновленные данные в базу, сам объект обновлятся не будет.
Так же можно получить объект и добавить оценку:

$this->load->model('rating');
$this->load->model('article');
$rating_id = $this->article->get_rating_id();
if($this->rating->find_by_id($rating_id)) {
$this->rating->add_rate($paramm);
}

Ну практически и все, так же нашу оценку можно удалить вызвав перед этим find_by_id или указав id оценки
пример с id:

$this->load->model('rating');
$this->load->model('article');
$rating_id = $this->article->get_rating_id();
if($this->rating->find_by_id($rating_id)) {
if($this->rating->delete()) echo 'Удален..';
}

Или же:

$this->load->model('rating');
$this->load->model('article');
$rating_id = $this->article->get_rating_id();
if($this->rating->delete($rating_id)) echo 'Удален..';