Удобное расширение модели CodeIgniter

В system/application/models создаем файл base_model.php. В этом файле и будет описан наш класс, который расширяет основную модель фреймворка:

<?php

class Base_model extends Model {
    protected $table;
    protected static $count; //общее число записей (для пейджинации)

    function Base_model() {
        parent::Model();
        // Вырезаем из имени класса модели окончание "_model"
        //(Например, из User_model получаем User)
        $model_class_name = strtolower(get_class($this));
        $this->table = substr_replace($model_class_name,"",
                                   strpos($model_class_name,"_model"),6);
    }

    function get_all($limit='', $offset='', $order_by='') {
        $this->db->select('*');
        $this->db->from($this->table);
        if ($order_by)
            $this->db->order_by($order_by);
        self::$count = $this->db->count_all_results('', true);
        $this->apply_pagination_settings($limit, $offset);
        return $this->db->get()->result();
    }

    function apply_pagination_settings($limit, $offset) {
        if ($limit and $offset) {
            $this->db->limit($limit, $offset);
        }
        elseif ($limit) {
            $this->db->limit($limit);
        }
        return;
    }

    function count_all() {
        if (self::$count) {
            return self::$count;
        }
        return $this->db->count_all($this->table);
    }

    function find($where, $order_by='') {
        $this->db->select('*');
        $this->db->from($this->table);
        $this->db->where($where);
        if ($order_by != '') {
            $this->db->order_by($order_by);
        }
        $result = $this->db->get()->result();
        return $result;
     }

     function get_by_id($id) {
          $this->db->select('*');
          $this->db->from($this->table);
          $this->db->where('id', $id);
          $res = $this->db->get()->result();
          if (count($res) > 0)
              return $res[0];
          return null;
     }

    function save($id, $data) {
        if ($id) {
            foreach($data as $key=>&amp;$item)
            {
                 if($item===''){unset($data[$key]);}
            }
            $this->db->where('id', $id);
            $this->db->update($this->table, $data);
        }
        else {
            $this->db->insert($this->table, $data);
        }
    }

    function delete($id) {
        $this->db->delete($this->table, array('id' => $id));
    }

}

?>

Все остальные наши модели объявляем уже как расширения нашей base_model.
Например, создадим модель user_model. В файле user_model.php размещаем такой код:
<?php
class User_model extends Base_model {
}
?>

Наша новая модель унаследовала весь функционал base_model. Т.е. она может выбирать данные из таблицы user, вставлять, обновлять, удалять, считать количество записей:
<?php
class Main extends Controller {

    function index(){
        $this->load->model('base_model');
        $this->load->model('user_model');
        //выборка всех пользователе
        $users = $this->user_model->get_all();
        //добавление нового пользователя
        $data = array('username' => 'Petr',
                     'surname'  => 'Ivanov',
                     'email'      => 'ivanov.petr@gmail.com' );
        $this->user_model->save('',$data);
        // допустим данный id существует в таблице user
        $id = 15;
        // обновление данных (update) для id=15
        $this->user_model->save($id, $data);
        // удаление записи с id=15
        $this->user_model->delete($id);
    }
}
?>

<?php
class Main extends Controller {
 
    function index(){
        $this->load->model('base_model');
        $this->load->model('user_model');
        //выборка всех пользователе
        $users = $this->user_model->get_all();
        //добавление нового пользователя
        $data = array('username' => 'Petr',
                     'surname'  => 'Ivanov',
                     'email'      => 'ivanov.petr@gmail.com' );
        $this->user_model->save('',$data);
        // допустим данный id существует в таблице user
        $id = 15;
        // обновление данных (update) для id=15
        $this->user_model->save($id, $data);
        // удаление записи с id=15
        $this->user_model->delete($id);
    }
}
?>

Для работы данного кода необходимо соблюдать два правила:
1. Все таблицы БД должны содержать поле id.
(`id` int(11) NOT NULL auto_increment )
2. Классы моделей должны называться по следующему правилу Tablename_model.

Второе правило можно изменить под свои привычки, тогда нужно будет внести соответствующие корректировки в эти две строчки кода (в конструкторе base_model):
$model_class_name = strtolower(get_class($this));
$this->table = substr_replace($model_class_name,"",
                           strpos($model_class_name,"_model"),6);

Можно, вообще избавиться от ограничений по именованию классов и переписать все функции, для приема имени таблицы в качестве параметра. Но, это дело вкуса. Как по мне, то проще соблюсти несложные правила.

Добавлено: 29 Июня 2018 07:17:37 Добавил: Андрей Ковальчук

Codeigniter логирование ошибок

В данной статье описано как в фреймворке CodeIgniter отключить вывод ошибок на экран и настроить запись ошибок в лог-файл. В частности, показано какие изменения необходимо сделать в “движке” CI, чтобы SQL ошибки не отображались, но логировались.

В рабочем коде желательно убирать вывод ошибок пользователю и перенаправлять его в лог-файл.

В CodeIgniter для этого необходимо установить следующие настройки:

1. Файл index.php

error_reporting(0);

2. Файл config.php
/**
  0 = отключает логирование
  1 = записывает только сообщения с ошибками
  2 = добавляются отладочные сообщения
  3 = добавляются информационные сообщения
  4 = добавляются все оообщения
**/
$config['log_threshold'] = 1;

/**
  По умолчанию логи сохраняются в папку system/logs/
  Либо, указывается свой путь к папке для лог-файлов.
  Необходимо проверить права доступа у папки на запись
**/
$config['log_path'] = '';

3. Файл database.php
/**
  TRUE - ошибки базы данных отображаются
  FALSE - ошибки базы данных не отображаются
**/
$db['default']['db_debug'] = FALSE;

Так вот, после всех этих настроек ошибки перестанут отображаться пользователю и будут записываться в лог-файлы. Все, кроме ошибок базы данных! Т.е. настройка $db['default']['db_debug'] = FALSE;
отвечает как за отображение, так и за запись в лог. Если TRUE – ошибка показывается пользователю и записывается в лог. FALSE – ни пользователю, ни в лог.
Или это ошибка, или такая задумка разработчиков CI, но явно неудобный момент.
Его и предлагаю исправить.
Открываем файл /system/database/DB_driver.php и ищем конструкции такого типа:
if ($this->db_debug)
{
    log_message('error', 'Invalid query: '.$sql);
    return $this->display_error('db_invalid_query');
}

И исправляем на такую:
log_message('error', 'Invalid query: '.$sql);
if ($this->db_debug)
{
    return $this->display_error('db_invalid_query');
}

Т.е. просто выносим вызов функции log_message из условия if.
Возможно, придется проделать немного больше правок, но суть понятна.
Например, в функции query я выношу из проверочного условия
log_message('error', 'Query error: '.$error_msg); 

Значит, нужно вынести и $error_msg = $this->_error_message();, чтобы $error_msg была определена.
$error_msg = $this->_error_message();
log_message('error', 'Query error: '.$error_msg);

Записываемые сообщения об ошибках БД не очень информативны, поэтому удобно добавлять и сам текст sql-запроса, в котором произошла ошибка.
log_message('error', 'Query error: '.$error_msg.' '.$sql);

Добавлено: 29 Июня 2018 07:13:18 Добавил: Андрей Ковальчук

Ajax-фильтрация. CodeIgniter, jQuery. Часть 2.

В первой части статьи мы разобрались с исходными данными и сформулировали задачи, которые необходимо выполнить для реализации ajax-фильтрации.

1. Добавить select со списком годов и пунктом «Все».

2. Написать на jQuery обработчик на изменение года в данном select.

3. В данном обработчике получить год, который был выбран и отправить ajax-запрос на сервер с параметром «год выпуска».

4. В контроллере Ajax написать метод, который будет обрабатывать наш ajax-запрос.

Напоминаю ссылку на готовый пример: Ajax-фильтрация

Первые три пункта мы реализуем в отображении cars.php

1. Добавляем select:

Год: <select id="year">
   <option value="all">Все</option>
   <option value="2009">2009</option>
   <option value="2010">2010</option>
</select>

2. Подключаем библиотеку jQuery (если, она еще не подключена у Вас). И создаем обработчик на изменение элемента с id=”year”:
<script type="text/javascript"
             src="<?=$base_url?>/res/js/jquery-1.3.2.min.js"></script>

<script>
   $(document).ready(function(){
      $('#year').change(function(){
         alert($(this).val());
      });
   });
</script>

Напомню, что переменная $base_url получает свое значение (из config.php) в суперконтроллере MY_Controller таким образом :
$this->data['base_url'] = $this->config->item('base_url');

А в наше отображение cars.php попадает из метода index контроллера Ajax вместе с другими данными вот таким образом:
$this->data['results'] = $this->car_model->get_all();
$this->data['inner_view'] = "cars";
$this->load->view('main', $this->data);

Т.е. в родительское отображение main передается весь массив $this->data, который содержит:

- имя внутреннего отображения (cars – в нем мы выводим нашу таблицу с авто)

- базовый url из config.php

- массив объектов – это данные о наших авто.

Итак, сейчас у нас при изменении года появляется сообщение со значением выбранного года. Т.е. мы уже начали реализовывать пункт 3. Осталось отправить ajax-запрос, что бы завершить выполнение нашего пункта 3.

3. Вот окончательный код отображения cars.php, а ниже немного разъяснений:
<script>
$(document).ready(function(){
   $('#year').change(function(){
      $('#cars').load("<?=site_url('ajax/ajax_filter');?>",
                          {year:$(this).val()},
                          function(){
                          });
   });
});
</script>
<center><h3>Ajax-фильтрация. JQuery, CodeIgniter.</h3></center>
<br/>Год: <select>
   <option value="all">Все</option>
   <option value="2009">2009</option>
   <option value="2010">2010</option>
</select>

<div id="cars">
<table>
      <tr>
         <th>Марка</th>
         <th>Год</th>
         <th>Цена</th>
      </tr>
   <?foreach($results as $res):?>
      <tr>
         <td><?=$res->name?></td>
         <td><?=$res->year?></td>
         <td><?=$res->price?></td>
      </tr>
   <?endforeach;?>
</table>
</div>

Нашу таблицу с информацией, мы заключили в блок с помощью тегов

. И присвоили этому блоку уникальный идентификатор id=”cars”.

В обработчике изменения года вместо вывода сообщения написали:
$('#cars').load("<?=site_url('ajax/ajax_filter');?>",
                     {year:$(this).val()},
                     function(){
                     });

Т.е. в блок с идентификатором id=”cars” мы с помощью функции load загружаем результат, возвращаемый функцией ajax_filter контроллера ajax. Эту функцию мы напишем в следующем пункте 4.

Функция load – выполняет ajax-запрос.

1 параметр – url, куда мы посылаем запрос. Для нашего примера – это
““.

2 параметр –
, данные, отправляемые вместе с запросом на сервер. В нашем случае – это год выпуска автомобиля.

3 параметр – [callback], функция-колбэк, которая выполняется после завершения запроса и получения ответа. В нашем примере эта функция ничего не выполняет. Ее можно было и не писать.

4. Создаем метод, который будет обрабатывать наш ajax-запрос. По url запроса (‘ajax/ajax_filter’) видно, что этот метод должен называться ajax_filter и располагаться в контроллере ajax:
[PHP]function ajax_filter()
{
   $result = array();
   $year = $this->input->post('year');
   $where = '';
   if($year != 'all' ){
      $where = array('year'=>"{$year}");
   }
   $result['cars'] = $this->car_model->get_all($where);
   $this->load->view('ajax',$result);
}

В данном методе:

- инициализируем массив результата $result

- получаем год выпуска, который мы передали вторым параметром в функцию load.

- делаем проверку на то, выбран ли пункт «все» или конкретный год.

- в $result['cars'] получаем все автомобили согласно полученному условию

- передаем полученный результат в отображение ‘ajax’

Теперь осталось создать отображение ajax.php со следующим содержимым:
<table>
      <tr>
         <th>Марка</th>
         <th>Год</th>
         <th>Цена</th>
      </tr>
   <?foreach($cars as $car):?>
      <tr>
         <td><?=$car->name?></td>
         <td><?=$car->year?></td>
         <td><?=$car->price?></td>
      </tr>
   <?endforeach;?>
</table>

Здесь мы выводим таблицу, которая полностью заменит в отображении cars содержимое блока с id=”cars”.

Обратите внимание, что цикл foreach пробегает по массиву $cars, а не по $result.

Итак, мы реализовали поставленную задачу – ajax-фильтрация данных, т.е. фильтрация без перезагрузки web-страницы.

Добавлено: 29 Июня 2018 07:09:38 Добавил: Андрей Ковальчук

Ajax-фильтрация. CodeIgniter, jQuery. Часть 1.

В данной статье рассмотрим один из вариантов использования технологии Ajax в фреймворке CodeIgniter.

Допустим, у нас уже выводится таблица с информацией об автомобилях. Наша задача – сделать ajax-фильтрацию, например, по году выпуска автомобиля.

Итак, у нас есть:

1. Таблица в БД ex_cars:

id	name	year	price
1	Ваз-2109	2010	8000
2	Ланос	2009	9000
3	Toyota	2010	30000
4	BMW	2009	40000
5	Audi	2010	50000

2. Модель Car_model. И метод модели get_all(), который получает данные из таблицы ex_cars по условию или без условия, т.е. все данные.
class Car_model extends Model {
   protected $table = 'ex_cars';
   function get_all($where='') {
      $this->db->select('*');
      $this->db->from($this->table);
      if(!empty($where))
      {
         $this->db->where($where);
      }
      return $this->db->get()->result();
   }
}

3. Контроллер с именем Ajax. В контроллере есть конструктор, в нем мы подключаем нашу модель ‘car_model’. Еще есть метод index(). В нем с помощью метода get_all модели car_model мы получаем все данные из таблицы ex_cars и затем отсылаем их в отображение cars. Которое, в свою очередь выводится в основное отображение для всех моих примеров – main. Обратите внимание на то, что наш контроллер Ajax расширяет класс MY_Controller. Это мой суперконтроллер, от которого я наследую все контроллеры. Вы можете расширять стандартный контроллер Controller. В моем же суперконтроллере сейчас определена переменная public $data; и $this->data['base_url'] = $this->config->item(‘base_url’);
class MY_Controller extends Controller {
   public $data; //хранит массив данных, передаваемых во view
   function MY_Controller() {
      parent::Controller();
      $this->data = array();
      $this->data['base_url'] = $this->config->item('base_url');
   }
}

class Ajax extends MY_Controller {
   function Ajax()
   {
      parent::MY_Controller();
      $this->load->model('car_model');
   }
   function index()
   {
      $this->data['results'] = $this->car_model->get_all();
      $this->data['inner_view'] = "cars";
      $this->load->view('main', $this->data);
   }
}

4. Отображение cars.php. В нем мы выводим полученные данные в виде таблицы.
<table>
      <tr>
         <th>Марка</th>
         <th>Год</th>
         <th>Цена</th>
      </tr>
   <?foreach($results as $res):?>
      <tr>
         <td><?=$res->name?></td>
         <td><?=$res->year?></td>
         <td><?=$res->price?></td>
      </tr>
   <?endforeach;?>
</table>

Теперь распишем по пунктам, что нам надо сделать:

1. Фильтрация по году выпуска, значит надо добавить select со списком годов и пунктом «Все».

2. Написать на jQuery обработчик на изменение года в данном select.

3. В данном обработчике получить год, который был выбран и отправить ajax-запрос на сервер с параметром «год выпуска».

4. В контроллере Ajax написать метод, который будет обрабатывать наш ajax-запрос.

Т.е. получать все автомобили с указанным годом выпуска и возвращать их в виде таблицы.

Добавлено: 29 Июня 2018 07:05:11 Добавил: Андрей Ковальчук

Ajax-пагинация. CodeIgniter, jQuery.

В данной статье рассматривается реализация Ajax-пагинации в фреймворке CodeIgniter с использованием JavaScript-библиотеки jQuery.

Для начала сделаем обычную пагинацию, а потом разберемся как реализовать пагинацию без перезагрузки всей веб-страницы.
Здесь работающий пример: ajax-пагинация

У нас есть список автомобилей, который хранится в базе данных в таблице ex_cars:

1. Таблица в БД ex_cars (id, name, year, price)

id	name	year	price
1	Ваз-2109	2010	8000
2	Ланос	2009	9000
3	Toyota	2010	30000
4	BMW	2009	40000
5	Audi	2010	50000
6	Opel	2009	25000
7	Skoda	2010	20000

Нам нужно вывести этот список на веб-страницу. Но поскольку база данных будет пополняться новыми автомобилями, то необходимо отображать фиксированное число записей и номера страниц в виде ссылок. Кликая по которым, мы сможем просмотреть все необходимые нам данные. Проще говоря, нам надо прикрутить пагинацию к выводимому списку автомобилей.

В фреймворке CodeIgniter для работы с пагинацией есть библиотека pagination.

Итак, наши дальнейшие действия:

1. Создаем модель Car_model в файле application\models\car_model.php. Здесь будут функции по работе с данными, т.е. с нашей таблицей ex_cars.

2. В конструкторе контроллера (контроллер я назвал Ajax) подключаем библиотеку pagination и нашу модель car_model.

3. Создаем метод контроллера, в котором будет реализована вся необходимая логика.

4. Создаем отображение, в которое и выведем наши данные.

Ниже смотрите код. Он содержит комментарии. Думаю, там все понятно.

Модель (файл application\models\car_model.php):
class Car_model extends Model {
   protected $table = 'ex_cars';
   // возвращает общее кол-во записей в таблице ex_cars
   function count_all()
   {
      return $this->db->count_all($this->table);
   }
   // $limit - кол-во получаемых записей
   // $offset - смещение, с какой записи начинать выборку
   function list_cars($limit,$offset)
   {
      $this->db->limit($limit,$offset);
      $query = $this->db->get($this->table);
      return $query->result();
   }
}

Контроллер (application\controllers\ajax.php):
class Ajax extends MY_Controller {
   function Ajax()
   {
      parent::MY_Controller();
      // подключаем модель
      $this->load->model('car_model');
      // подключаем библиотеку для работы с пагинацией
      $this->load->library('pagination');
   }

   function paginate($offset='')
   {
      $limit = 3; //кол-во элементов списка на одной странице
      // получаем данные из таблицы
      // $limit - кол-во запрашиваемых записей
      // $offset - смещение, т.е. с какой записи начинать выборку
      $this->data['cars'] = $this->car_model->list_cars($limit,$offset);
      // путь к веб-странице на которой делается пагинация
      $config['base_url'] = site_url('ajax/paginate');
      // получаем общее кол-во записей в таблице ex_cars
      $config['total_rows'] = $this->car_model->count_all();
      // кол-во элементов, которое мы хотим показать на странице
      $config['per_page'] = $limit;
      // инициализация пагинации на основании заданных условий
      $this->pagination->initialize($config);
      $this->data['pag_links'] = $this->pagination->create_links();
      $this->data['inner_view'] = "pagination";
      // передача данных в отображение
      // main - главное отображение, в которое выводятся все остальные
      // pagination - это отображение с нашим списком авто
      $this->load->view('main', $this->data);
   }
}

Отображение (application\views\pagination.php):
<table>
<tr>
   <th>№</th>
   <th>Марка</th>
   <th>Год</th>
   <th>Цена</th>
</tr>
<?foreach($cars as $car):?>
<tr>
   <td><?=$car->id?></td>
   <td><?=$car->name?></td>
   <td><?=$car->year?></td>
   <td><?=$car->price?></td>
</tr>
<?endforeach;?>
</table>
<?=$pag_links;?>

Итак, обычная пагинация готова.

Теперь в наш код необходимо внести некоторые дополнения и получить уже ajax-пагинацию. Что необходимо сделать? Смотрите, сейчас у нас в контроллере есть строка:
$this->data['pag_links'] = $this->pagination->create_links();

В этой строке генерируются ссылки на страницы нашего списка (первую, вторую, следующую, предыдущую и т.д.) Эти ссылки мы и выводим в отображение. Теперь наша задача написать код, который будет перехватывать клик по этим ссылкам и вместо перенаправления, которое сейчас выполняется мы будет посылать ajax-запрос на получение необходимых данных и выводить эти данные в нужный блок.

Вносим изменения в наше отображение pagination
<script>
$(document).ready(function(){
   $('.ajax_pag a').click(function(event){
   // получаем содержимое ссылки
   var link = $(this).attr('href');
   // отменяем действие по умолчанию
   event.preventDefault();
   // посылаем ajax-запрос по полученной ссылке
   $('#ajax_content').load(link);
   });
});
</script>

<center><h3>Ajax-пагинация. JQuery, CodeIgniter.</h3>   </center>
<div id="ajax_content">
<table>
<tr>
   <th>№</th>
   <th>Марка</th>
   <th>Год</th>
   <th>Цена</th>
</tr>
<?foreach($cars as $car):?>
<tr>
   <td><?=$car->id?></td>
   <td><?=$car->name?></td>
   <td><?=$car->year?></td>
   <td><?=$car->price?></td>
</tr>
<?endforeach;?>
</table>
<span class="ajax_pag"><?=$pag_links;?> </span>
</div> <!-- ajax_content -->

Какие изменения?

- таблицу мы поместили в блок
<div id='ajax_content'>

и присвоили ему id=’ajax_content’. Содержимое этого блока будет меняться при клике на ссылки пагинации.

- вывод ссылок заключили в тег
<span class='ajax_pag'>

- написали jQuery скрипт.

Что происходит в скрипте?

При клике на любую ссылку внутри блока с классом, мы получаем значение ссылки, по которой был произведен клик. И вместо стандартного перехода по этой ссылке, мы делаем ajax-запрос по полученному пути.
Этот запрос вернет данные в блок

Теперь в контроллере в метод paginate внесем проверку на тип запроса (обычный или ajax). Для обычного запроса у нас уже есть обработка, а в случае ajax-запроса мы будем выводить другое отображение, которое создадим ниже.
if(IS_AJAX){
   $this->load->view('pagination_ajax', $this->data);
}else{
   $this->data['inner_view'] = "pagination";
   // передача данных в отображение
   // main - главное отображение, в которое выводятся все остальные
   // pagination - это отображение с нашим списком авто
   $this->load->view('main', $this->data);
}

IS_AJAX – это константа, которую необходимо определить в файле
application\config\constants.php следующим образом:
define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
         strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');

Теперь приведу содержимое отображения pagination_ajax, которое мы возвращаем в случае ajax-запроса.
<table>
<tr>
   <th>№</th>
   <th>Марка</th>
   <th>Год</th>
   <th>Цена</th>
</tr>
<?foreach($cars as $car):?>
<tr>
   <td><?=$car->id?></td>
   <td><?=$car->name?></td>
   <td><?=$car->year?></td>
   <td><?=$car->price?></td>
</tr>
<?endforeach;?>
</table>
<span class="ajax_pag"> <?=$pag_links;?> </span>

Как видите, здесь просто вывод нашей таблицы.

Вот и все. Надеюсь, все понятно. Спасибо за внимание.

Успехов! :)

Добавлено: 29 Июня 2018 07:01:44 Добавил: Андрей Ковальчук

Cannot redeclare class CI_Exceptions

После обновления php CodeIgniter может выдавать такую ошибку:

Cannot redeclare class CI_Exceptions in 
/usr/lib/php5/codeigniter/system/database/DB.php on line 133

В моем случае проблема была решена удалением амперсанда (&) в двух строках указанного файла DB.php:

1. В объявлении функции DB:

до редактирования (строка 25 файла DB.php)
function &DB($params = '', $active_record_override = FALSE)

после редактирования
function DB($params = '', $active_record_override = FALSE)

2. При создании объекта класса:

до редактирования (строка 133 файла DB.php)
$DB =& new $driver($params);

после редактирования
$DB = new CI_DB_mysql_driver($params);

здесь еще, вместо переменной $driver было сразу прописано значение CI_DB_mysql_driver.
После этих исправлений ошибка не появлялась, сервер перестал падать.

Добавлено: 24 Июня 2018 07:33:22 Добавил: Андрей Ковальчук

Подключение FCKEditor к CodeIgniter

Чем хорош FCKEditor так это тем, что в нем есть встроенный менеджер закачки файлов. Идем на сайт FCkEditor и скачиваем последнюю версию. Создаем папку www\js\fckeditor и распаковываем туда содержимое архива.

Создаем файл вида views\fckeditor.php

<!-- FCKEditor -->
 <script type="text/javaSCRIPT" src="<?=base_url()?>js/fckeditor/fckeditor.js"></script>
    <script type="text/javaSCRIPT">
     var oFCKeditor = new FCKeditor("<?=$id?>"); // привязка к textarea с id
     oFCKeditor.ToolbarSet="Default"; // число кнопочек на инструментальной панели
     oFCKeditor.Width = 800;
     oFCKeditor.Height = 400;
     oFCKeditor.BasePath="<?=base_url()?>js/fckeditor/"; //путь к fckeditor
     oFCKeditor.ReplaceTextarea(); // вставка текста из textarea с id="$id"
    </script>
<!-- /FCKEditor -->

Создаем хелпер www\system\application\helpers\fckeditor_helper.php
<?php
/**
 *
 * Описание файла: Хелпер для вывода FCKEditor 
 *
 * @изменён 8.9.2009
 */
 
if (!defined('BASEPATH')) exit('No direct script access allowed');
 
	//Возвращает код редактора для элемента с указанным ID 
function show_fckeditor ($id) {
 
		$CI = &get_instance ();		
		$data = array ();
		$data['id'] = $id;
 
//Считываем код из файла		
$code = $CI->load->view ('fckeditor',data,TRUE);		
		return $code;			
	}
 
?>

Произведем настройку FCKEditor.
Настроим директорию для загрузки картинок. Создадим в корне папки www\images\image
www\js\fckeditor\editor\filemanager\connectors\php\config.php
Находим строчку
$Config['Enabled'] = false ;

заменяем ее на
$Config['Enabled'] = true ;

Задаем путь к папке где храняться картинки:
Находим и меняем
$Config['UserFilesPath'] = '/userfiles/' ;

на
$Config['UserFilesPath'] = '/images/' ;

Открываем файл system/plugins/fckeditor/fckconfig.js
Находим и меняем строки
var _FileBrowserLanguage = 'asp' ; // asp | aspx | cfm | lasso | perl | php | py
var _QuickUploadLanguage = 'asp' ; // asp | aspx | cfm |
на
var _FileBrowserLanguage = 'php' ;
var _QuickUploadLanguage = 'php' ;

Там же проконтролируем наличие строки:
FCKConfig.ImageUpload = true ;

Не забывайте что функция upload не закрыта авторизацией.

Работа с редактором производится так:

В файле вида созадем textarea указываем id (например id=»anons»)
Добавляем в файл вида строку
В контроллере из которого будет вызываться вид. Перед вызовом вида добавляем вызов хелпера $this->load->helper('fckeditor');

Добавлено: 29 Мая 2018 08:53:56 Добавил: Андрей Ковальчук

Русские символы в URL сайта на CodeIgniter

Известно, что по умолчанию в Code Igniter русские буквы в адресах запрещены.
Однако даже при изменении в файле system/application/config/config.php строки

$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';

на
$config['permitted_uri_chars'] = 'a-zа-яё 0-9~%.:_\-';

проблема не решилась.
Для этого создаем файл system/application/libraries/MY_URI.php и размещаем там следующий код:
<?php 
class MY_URI extends CI_URI
{
    function _filter_uri($str)
    {
        if ($str != '' AND $this->config->item('permitted_uri_chars') != '')
        {
            if ( ! preg_match("|^[".preg_quote($this->config->item('permitted_uri_chars'))."]+$|ui", $str))
            {
                exit('The URI you submitted has disallowed characters.');
            }
        }
 
        return $str;
    }
}

Добавлено: 29 Мая 2018 08:36:00 Добавил: Андрей Ковальчук

Как сделать хлебные крошки (breadcrumbs) в CodeIgniter

В файле www\system\application\config\config.php дописываем в конце файла:

$config['breadcrumbs_index'] = 'Главная'; // название элемента, ссылка на который будет '/'
$config['breadcrumbs_delimeter'] = '»'; // разделитель, который будет вставляться между каждой крошкой.

Допустим у нас есть контроллер events. В конструкторе контроллера пишем:
class events extends Controller
{
    function events()
    {
        parent::Controller();
        $this->breadcrumbs = array();
        $this->breadcrumbs[] = anchor('', $this->config->item ('breadcrumbs_index'));
        $this->breadcrumbs[] = anchor('events', 'События');  
    }
}

Теперь у нас при вызове контроллера автоматом будет формироваться ссылка: Главная>>События
Далее в каждой функции контроллера в которой вызывается вид пишем:
$this->breadcrumbs[] = $title; // в $title передаем заголовок который будет выводиться.
$data = array('breadcrumbs' => $this->breadcrumbs);
$this->load->vars($data);

В файле вида пишем:
$delim = $this->config->item('breadcrumbs_delimeter');
if ( (isset($breadcrumbs)) AND (is_array($breadcrumbs)) )
{
    ?><div id="breadcrumbs"><?
    $cnt = count($breadcrumbs);
    for ($i=0; $i < $cnt-1; $i++)
    {
        echo $breadcrumbs[$i].' '.$delim.' ';
    }
    echo $breadcrumbs[$cnt-1];
    ?></div>
    <?
}

Добавлено: 24 Мая 2018 21:45:45 Добавил: Андрей Ковальчук

Как добавить rss в Code-Igniter

Сегодня рассмотрим как добавить в наш движок на CodeIgniter rss ленту для новостей.

Для этого создаем контроллер feed:

<?php
/**
 * @author allexe
 * @copyright 2010
 */
 
class feed extends Controller
{	
	function feed() {
		parent::Controller();				
	}
 
	function index() {
        $CI = &get_instance(); //Доступ к CodeIgniter
        $CI->load->model('mdl_news');
        $CI->load->model('mdl_nastr');
        $CI->load->helper('xml');
        $data['encoding'] = 'utf-8';
        $data['feed_name'] = 'alllexe.com';
        $data['feed_url'] = 'http://www.alllexe.com';
        $data['page_description'] = 'Kursk IT, Code Igniter, PHP';
        $data['page_language'] = 'ru-ru';
        $data['creator_email'] = 'your mail';
        $num_news = $CI->mdl_nastr->get_nastr_by_name('Новостей в RSS');
        $sort = array('desc' => 'date');
        $news = $CI->mdl_news->getlist(false,$num_news,false,$sort);        
 
        $data['news'] = $CI->mdl_news->getlist(false,$num_news,false,$sort);    
        header("Content-Type: application/rss+xml");
        $this->load->view('rss', $data);
	}	
}
?>

Тут все просто при заходе на наш сайт по ссылке нашсайт/feed, этот контроллер берет из базы последние новости. Количество новостей задается в настройках. Полученные новости передаются в файл вида rss.php. Также передаются служебные переменные, все передается в массиве date.
Содержание rss.php
<?php 
echo '<?xml version="1.0" encoding="utf-8"?>' . "\n";
?>
<rss version="2.0"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:admin="http://webns.net/mvcb/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:content="http://purl.org/rss/1.0/modules/content/">
 
    <channel>
 
    <title><?php echo $feed_name; ?></title>
 
    <link><?php echo $feed_url; ?></link>
    <description><?php echo $page_description; ?></description>
    <dc:language><?php echo $page_language; ?></dc:language>
    <dc:creator><?php echo $creator_email; ?></dc:creator>
 
    <dc:rights>Copyright <?php echo gmdate("Y", time()); ?></dc:rights>
    <admin:generatorAgent rdf:resource="http://www.codeigniter.com/" />
 
    <?php foreach($news as $one): ?>
 
        <item>
 
          <title><?php echo xml_convert($one['title']); ?></title>
          <link><?php echo base_url().'news/read/'.$one['id'] ?></link>
          <guid><?php echo base_url().'news/read/'.$one['id'] ?></guid>
 
          <description><![CDATA[
      <?= $one['anons']; ?>
      ]]></description>
      <pubDate>
	  <?php
	  $date_arr = explode('.',$one['date']); 
	  echo date('r', mktime(0,0,0,$date_arr[1],$date_arr[0],$date_arr[2]));
	  ?>
	  </pubDate>
        </item>        
    <?php endforeach; ?>    
    </channel></rss>

Чтобы в адресной строке браузера появился значок rss при нажатии на который открывается наша лента новостей, перед закрывающим тегом нужно вставить строку
<link rel="alternate" type="application/rss+xml" title="название_RSS-ленты_вашего_сайта" href="http://адрес_вашего_сайта/путь_и_имя_файла_RSS-ленты.xml" />

Добавлено: 21 Мая 2018 07:36:02 Добавил: Андрей Ковальчук

Управление внутренней адресацией

В этой заметке я покажу, как использовать встроенный роутер CodeIgniter'а для решения одной несложной задачи.

Прежде всего, пару слов о том, что это такое и зачем нужно.

Как вы, наверное, знаете CodeIgniter – это php фреймворк, одними из основных достоинств которого являются простота использования и низкая ресурсоемкость. Тем не менее, его возможности практически не уступают более «тяжелым» аналогам.

Одной из таких возможностей и является роутер. Он позволяет с помощью несложных правил настроить внутреннюю адресацию сайта по своему вкусу.

Любой запрос браузера передается роутеру, а уже потом – контроллеру. Таким образом, можно изменить любой из параметров запроса. Например, перенаправить запрос другому контроллеру или добавить/удалить параметры.

Делается это достаточно просто. В файле /application/config/routes.php нужно задать правила в виде:

$route[‘выражение’] = "новый_адрес";

выражение – здесь можно использовать регулярные выражения, которые будут использоваться для проверки того, нужно ли применить данное правило к полученному адресу или нет.

Теперь переходим к нашей задаче.

Допустим, у нас есть сайт (блог) и мы хотим создать для каждой из его записей постоянные ссылки (permalink) (такая функция есть практически во всех движках блогов).

Первоначально наши записи доступны по адресу:
http://mysite/index.php/main/goto/postid

Это стандартная адресация в CodeIgniter. Здесь:
main – названия контроллера;
goto – имя метода контроллера, который будет обрабатывать запрос;
postid – номер записи в базе данных.

Нам нужно, чтобы записи были доступны по адресу вида:
http://mysite/index.php/post_permalink

Сами ссылки создать и хранить не сложно. Для этого достаточно к таблице с записями добавить еще одно поле (permalink) и хранить в нем постоянные ссылки.

Примечание. Все постоянные ссылки должны быть уникальными.

Переходим к роутеру.

Прежде всего, нужно четко понимать как отличить адрес с постоянной ссылкой от обычного. В данном случае отсутствие имени контроллера (main) в начале адреса означает, что запрос содержит постоянную ссылку. Т.е. в этом случае мы должны перенаправить этот запрос методу goto.

Если имя контроллера в адресе найдено, то оставляем все без изменений.

Реализуется вся эта система с помощью двух простых правил:
$route['(^main.*$)'] = "$1";
$route['(^.+$)'] = "main/goto/$1";

Первое правило будет применено только для запросов, которые начинаются со слова main.

Второе правило вставит main/goto/ в начале полученного адреса.

Примечание. Как вы, наверное, догадались, роутер получает только ту часть адреса, которая идет после index.php. И еще одно, порядок следования правил в данном случае важен. Если их поменять местами, то правило $route['(^.+$)'] = "main/goto/$1" будет использовано для всех адресов.

Теперь взгляните на метод goto.
function goto($permalink) {
    $pageData['title'] = "Заголовок страницы";
 
    //здесь должен быть код получения записи из БД
    //запрос может выглядеть так
    //SELECT * FROM posts WHERE permalink = $permalink
    $this->load->view('header', $pageData);
    $this->load->view('page', $pageData);
    $this->load->view('footer');
}

Как видите, роутер просто меняет адрес и не требует специальной поддержки со стороны контроллера.

Кстати, вы можете передавать любое количество параметров в адресе с постоянной ссылкой. Например:
http://mysite/index.php/post_permalink/par1/par2/...

До встречи!

Добавлено: 09 Мая 2018 09:58:21 Добавил: Андрей Ковальчук

Авторизация посетителей и ограничение доступа

Прежде всего, вкратце обрисую сложившуюся ситуацию.

Большинство web ресурсов используют для защиты пару «имя — пароль». Это не самый безопасный вариант, но зато удобный (простой) в использовании.

Более сложные методы защиты требуют от посетителя либо специальных знаний, либо покупки оборудования, либо того и другого. Например, служба WebMoney использует сертификаты для авторизации пользователей. Метод хороший, но инструкция по использованию и безопасной работе с этими сертификатами занимает несколько страниц. Обычный пользователь интернета не станет связываться с такой системой без достаточно веской причины (в случае WebMoney речь идет о его собственных деньгах).

Об аппаратной защите (вроде биометрических датчиков и т.п.) и говорить не приходиться. Эти устройства стоят денег и, зачастую, немаленьких.

Поэтому, метод авторизации с помощью имени и пароля, похоже, останется самым распространенным в обозримом будущем.

В «классическом» варианте этот метод работает так. Посетитель вводит имя и пароль, вы их проверяете и, если все в порядке, записываете какой-нибудь параметр в сессию (например, имя пользователя). После этого, в каждую защищенную страницу сайта нужно добавить код, который будет проверять, установлен ли нужный параметр в сессии, и если нет, предлагать посетителю ввести имя и пароль.

Естественно, этот подход далеко не самый лучший, т.к. код проверки формы будет дублироваться на каждой странице.

CodeIgniter предлагает элегантное решение этой проблемы. Идея заключается в использовании метода _remap. Если в контроллере объявлен этот метод, то обращения к любому другому методу контроллера будут переадресованы ему.

Теперь можно разместить код проверки в методе _remap и он будет выполняться для всех обращений к сайту.

function _remap($method) {
    //страницы, доступные без авторизации
    $allowedPages = array('index', 'newuser', 'about');
    $pars = $this->uri->segment_array();
    unset($pars[1]);
    unset($pars[2]);
    if (($method != null) &&
        (($this->session->userdata('username') != null) ||    in_array($method, $allowedPages))) {
        call_user_func_array(array($this, $method), $pars);
    }
    else {
        $this->index();
    }
}

Разберем подробнее код этого примера.

Прежде всего, я объявил массив ($allowedPages) с перечнем страниц (методов контроллера) доступных без авторизации. Перечень составлен произвольно и предполагается, что страница 'index' содержит форму для ввода имени и пароля.

После этого, сохранил все сегменты адреса и удалил первые два (строки 4-6). Как вы помните, в CodeIgniter первый сегмент адреса содержит имя контроллера (оно нам не нужно), второй – имя метода (передается методу _remap в параметре $method), в остальных могут передаваться параметры (вот их нужно сохранить и передать вызываемому методу).

В строках 7, 8 проверяется можно ли вызвать указанный метод. Приведенный код вызовет метод в двух случаях:
1) если в сессии был установлен параметр 'username';
2) название метода содержится в массиве $allowedPages, т.е. доступ к нему разрешен без авторизации.

Вызов метода контроллера осуществляется с помощью функции call_user_func_array, т.к. параметры метода находятся в массиве.

Если условия не выполняются, будет вызван index(). Т.е. посетитель попадет на главную страницу сайта с формой ввода имени и пароля.

Как видите, все довольно просто.

Важно. Если ваш сайт содержит несколько контроллеров, то метод _remap должен быть объявлен в каждом из них.

Ограничения

Описанный метод удобно использовать, если вам достаточно одного пользователя с административными правами.

В случае, если вам нужно создавать группы пользователей и назначать им различные привилегии, то, стоит попробовать одну из библиотек авторизации, разработанных специально для CodeIgniter. Например, FreakAuth, EzAuth, UserAuth.

Добавлено: 08 Мая 2018 16:52:11 Добавил: Андрей Ковальчук

Работа с базой данных

Мы продолжаем изучение фрэймворка CodeIgniter. Сегодня речь пойдет о работе с базами данных.

В соответствии с архитектурой MVC для работы с данными используется модель. Что бы создать модель в CodeIgniter нужно написать класс, наследующий Model и поместить его в папку system/application/models.

Для нашего приложения достаточно одной модели, назовем ее Catalogmodel. Создаем файл system/application/models/catalogmodel.php и записываем в него следующий код.

<?php
class Catalogmodel extends Model {
 
    function Catalogmodel() {
        parent::Model();
    }
}
?>

Теперь нам нужно подключить библиотеку для работы с базами данных. Для этого открываем файл system/application/config/autoload.php и ищем переменную $autoload['libraries']. Она содержит массив с названиями всех библиотек, которые будут автоматически загружаться при обращении к сайту. Мы добавим загрузку библиотеки «database».
$autoload['libraries'] = array('database');

Небольшое отступление

Одним из преимуществ CodeIgniter является низкое потребление ресурсов. Достигается это в основном за счет того, что по-умолчанию загружается только минимально необходимый для работы набор библиотек (ядро). Какие из дополнительных библиотек загружать решаете вы. И CodeIgniter предоставляет несколько вариантов их загрузки.

В данном случае мы добавили название библиотеки в $autoload, т.к. все методы нашего контроллера будут работать с БД. Если данные из БД нужны только для создания части страниц, то лучше загружать библиотеку непосредственно перед использованием.
$this->load->database();

Переходим к подключению к базе данных. Вообще-то CodeIgniter позволяет работать одновременно с несколькими БД, но мы ограничимся самым простым вариантом. Открываем файл system/application/config/database.php и заполняем массив с параметрами подключения:
$db['default']['hostname'] = "localhost"; //имя хоста, на котором запущен сервер БД
$db['default']['username'] = "имя_пользователя_БД";
$db['default']['password'] = "пароль";
$db['default']['database'] = "bookcatalog"; // имя базы данных

Теперь можно работать с БД с помощью объекта db. Например, отправить запрос можно с помощью функции query().
$this->db->query('строка_запроса');

Итак, база данных доступна, запросы мы выполнять можем. Осталось написать методы нашей модели. Для нашего примера достаточно двух методов.

Первый будет возвращать данные обо всех книгах в БД без аннотаций, т.е. информацию, необходимую для создания главной страницы каталога.
function getAllBooks() {
    $qGetAll = "SELECT id, title, author, pages, genre FROM books";
    $res = $this->db->query($qGetAll);
    $booksData = $res->result_array();
    if (count($booksData) == 0) {
        return false;
    }
    return $booksData;
}

В строках 2 и 3 мы формируем и отправляем запрос. В результате получаем объект с результатами и преобразуем его в массив (с помощью метода result_array()).

Примечание. CodeIgniter предоставляет ряд методов для работы с результатами запроса. Их описание можно посмотреть здесь.

После этого, мы проверяем длину массива. И если она равна нулю (каталог пуст), возвращаем false. В противном случае, возвращаем массив с результатами.

Второй метод используется для создания страницы с подробной информацией о выбранной книге.
function getBookDetails($bookId) {
    $qGetBook = "SELECT * FROM books WHERE id=?";
    $res = $this->db->query($qGetBook, array($bookId));
    $bookData = $res->result_array();
    if (count($bookData) == 0) {
        return false;
    }
    return $bookData[0];
}

В параметре $bookId методу передается значения поля id выбранной книги.

Обратите внимание на то, как мы формируем запрос. В строке запроса вместо значения параметра id мы ставим знак вопроса. А методу query() в качестве второго параметра передаем массив со значениями. При отправке запроса значения будут подставлены вместо знаков вопроса.

Что дает такой подход? Во-первых, запрос легче читается. Во-вторых, все спецсимволы SQL будут автоматически преобразованы в эскейп последовательности.

Примечание. Если вы формируете строку с параметрами запроса самостоятельно, не забывайте использовать метод escape(). Например, так $this->db->escape($title). Это позволит защититься от SQL Injection.

Дальнейшая работа метода практически полностью аналогична getAllBooks(). Единственное отличие заключается в том, что в данном случае мы возвращаем только первый элемент массива с результатами, т.к. в нем не может быть больше одного элемента.

Все, модель нашего каталога готова. В следующий раз мы допишем контроллер и создадим страницы нашего каталога.

До встречи!

Добавлено: 08 Мая 2018 11:40:48 Добавил: Андрей Ковальчук

Контроллер и представления

В предыдущих выпусках мы начали разработку небольшого сайта, представляющего собой обычный каталог. Кратко напомню, о чем шла речь в предыдущих статьях.

В первой части мы установили и настроили фрэймворк (CodeIgniter).
Во второй – определились с требованиями к нашему приложению, создали БД, написали каркас контроллера и разобрались с передачей параметров в ссылках.
В третьей части описана модель нашего приложения, т.е. мы создали класс, выполняющий все операции с данными.

Подключаем модель к контроллеру

Для этого в конструкторе контроллера (system/application/controllers/catalog.php) добавляем строку

$this->load->model('catalogmodel');

Обратите внимание, что имя файла модели указывается без расширения (.php). Это правило относится и ко всем остальным компонентам фрэймворка (библиотекам, представлениям).

У вас мог возникнуть вопрос: «Почему подключение выполняется именно в конструкторе?». Тут все просто. Подключить модель можно в любом из методов. Но тогда она будет доступна только внутри этого метода, а т.к. оба метода нашего контроллера используют одну и ту же модель, то лучше подключить ее в конструкторе (не дублируется код).

Теперь мы можем вызывать методы модели. Например,
$this->catalogmodel->getAllBooks();
$this->catalogmodel->getBookDetails($bookid);

Как видите, CodeIgniter создал объект catalogmodel, с помощью которого мы и работаем с моделью. Кстати, обратите внимание, мы не используем функции include() и require(). Все необходимые вызовы выполняются объектом load.

Переходим к методам контроллера. В первой части мы уже объявили эти методы.
Первый метод называется index() и служит для создания главной страницы каталога.
function index() {
    $pageData['title'] = "Каталог книг - главная";
    $pageData['books'] = $this->catalogmodel->getAllBooks();
    if ($pageData['books'] == false) {
        $pageData['errDescription'] = "Книги не найдены";
    }
    $this->load->view("main", $pageData);
}

Здесь мы сталкиваемся еще с одной возможностью CodeIgniter, а именно передачей данных из контроллера в представление.

Все, что нам нужно сделать, это создать массив с данными, которые нужны для формирования страницы, и передать его во втором параметре метода view() (строка 7). Учтите, что массив должен быть ассоциативным, т.к. в представлении ключи используются для доступа к данным.

О представлениях мы поговорим чуть ниже, а сейчас разберемся какие данные нужно передавать. Прежде всего, это данные из БД, т.е. информация о книгах. Поэтому в строке 3 мы читаем эти данные из базы (с помощью модели) и сохраняем их в $pageData['books']. Если метод getAllBooks() вернул false, мы создаем элемент массива $pageData['errDescription'] с описанием ошибки.

Кроме того, мы передаем еще и заголовок страницы $pageData['title']. В общем-то, он может быть и постоянным, но вдруг вы захотите добавить в него какую-нибудь информацию (например, количество записей).

После того, как массив сформирован, мы загружаем представление (строка 7).

Представление (согласно архитектуре MVC) формирует страницу, которая будет отправлена браузеру. Как мы уже говорили, все представления должны находиться в папке system/application/views. Т.к. мы загружаем представление с именем main, то файл представления должен называться main.php.
<?php
$this->load->view('header');
?>
<h1>Каталог книг</h1>
<ul>
<?php
if (isset($errDescription)) {
echo "<h1>".$errDescription."</h1>";
}
else {
foreach ($books as $book) {
echo "<li>";
echo "<p>".anchor('catalog/bookdetails/'.$book['id'], $book['title'])."</p>";
echo "<p>Автор: ".$book['author']."</p>";
echo "<p>Жанр: ".$book['genre']."</p>";
echo "<p>Страниц: ".$book['pages']."</p>";
echo "</li>";
}
}
?>
</ul>
<?php
$this->load->view('footer');
?>

Разберем, что мы здесь написали. Прежде всего, обратите внимание, что в строках 2 и 23 мы загружаем два других представления ('header' и 'footer'), т.е. заголовок и завершение страницы. Это, конечно, не обязательно, но эти фрагменты будут повторяться во всех страницах, поэтому удобно вынести их в отдельные файлы.Теперь посмотрите на строки 7-9. Здесь мы проверяем, установлена ли переменная $errDescription. Эту переменную автоматически создает фрэймворк, если в массиве $pageData был создан элемент с ключом errDescription (как вы помните, этот элемент создается, если книги в БД отсутствуют).

В основном цикле (строки 11 — 18) мы формируем обычный список с данными из массива. Вот здесь есть один интересный момент. Это использование функции anchor(). В принципе, она создает обычную ссылку, но при этом используются настройки из конфигурационного файла (system/application/config/config.php). А если конкретнее, используется переменная $config['base_url'], значение которой должно указывать на адрес сайта (например, http://www.my_site.domen/).

В первом параметре функции мы указываем вторую часть адреса, в данном случае это адрес страницы, которую мы хотим загрузить (в формате: имя_контроллера/имя_метода/параметры). Во втором – текст ссылки.

Таким образом, мы для каждой книги каталога создали ссылку на страницу с ее подробным описанием.

Использование anchor() позволяет упростить перенос сайта на другой домен. Если вы делаете все правильно, т.е. нигде, кроме файла config.php не прописываете ссылки на домен, то при переносе сайта вам потребуется только изменить значение $config['base_url'] в этом файле.

Перед использованием функции anchor() нужно подключить вспомогательную библиотеку, в которой она находится. Для этого, открываем файл system/application/config/autoload.php, ищем в нем массив вспомогательных библиотек, и добавляем в него библиотеку url.
$autoload['helper'] = array('url');

Чтобы получить представление о конечном результате, посмотрите на файлы header.php и footer.php.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ru">
<head>
<title><?php echo $title; ?></title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="<?php echo base_url(); ?>/css/styles.css" />
</head>
<body>
?
</body>
</html>

Как видите, в них находятся обычный заголовок и завершение страницы. Стоит обратить внимание на два момента в заголовке.

Во-первых, для создания заголовка мы используем переменную $title, которую устанавливаем в контроллере.

Во-вторых, при подключении таблицы стилей мы используем функцию base_url(). Как вы, наверное, догадались, она возвращает значение $config['base_url'] из config.php.
Примечание. Здесь предполагается, что файл styles.css размещен в папке css/, которая находится в DOCUMENT_ROOT, т.е. там же где и index.php.

Теперь взгляните на диаграмму. На ней показал порядок формирования главной страницы сайта.

Создание главной страницы каталога (миниатюра)
Запрос браузера передается контроллеру (catalog.php), который получает данные с помощью модели (catalogmodel.php) и загружает представление (main.php). Представление формирует страницу, которая отсылается назад браузеру.

В этом и заключается смысл архитектуры MVC. Модель выполняет работу с данными (чтение, запись в БД и т.п.), представление – формирует страницу, а контроллер – обрабатывает запросы и обеспечивает взаимодействие компонентов.

Главное преимущество такой архитектуры в том, что можно заменять отдельные компоненты, не затрагивая остальные. Например, если вы захотите хранить информацию о книгах в текстовом файле вместо БД. Вам нужно будет только переписать методы модели.

Мы подробно разобрали создание главной страницы каталога. Код создания страницы с подробным описанием книги практически идентичен. Поэтому я его приведу без описания.

В контроллере:
function bookdetails($bookid) {
    $pageData['bookdetails'] = $this->catalogmodel->getBookDetails($bookid);
    if ($pageData['bookdetails'] == false) {
        $pageData['errDescription'] = "Выбранная книга не найдена";
    }
    $pageData['title'] = $pageData['bookdetails']['title'];
    $this->load->view("bookdetails", $pageData);
}

Представление (файл bookdetails.php).
<?php
    $this->load->view('header');
?>
<?php
if (isset($errDescription)) {
    echo "<h1>".$errDescription."</h1>";
}
else {
    echo "<p><strong>Название:</strong> ".$bookdetails['title']."</p>";
    echo "<p><strong>Автор:</strong> ".$bookdetails['author']."</p>";
    echo "<p><strong>Жанр:</strong> ".$bookdetails['genre']."</p>";
    echo "<p><strong>Страниц:</strong> ".$bookdetails['pages']."</p>";
    echo "<p><strong>Аннотация:</strong> ".$bookdetails['annotation']."</p>";
}
?>
<?php
    echo "<p>".anchor("", "На главную")."</p>";
    $this->load->view('footer');
?>

Как видите, разница заключается только в том, что метод контроллера принимает в качестве параметра id книги и вызывает соответствующий метод модели. А в представлении отсутствует цикл, т.к. мы выводим информацию только об одной книге.

Если хотите посмотреть, как работает этот каталог, скачайте архив с исходным кодом. В нем находится дистрибутив CodeIgniter и исходники каталога. Кроме того, в нем вы найдете файл db_backup.sql, который можно импортировать с помощью phpMyAdmin и не заполнять базу данных самостоятельно.

Удачи!

Добавлено: 04 Мая 2018 08:35:47 Добавил: Андрей Ковальчук

Подключаем FCKeditor к CodeIgniter

FCKeditor, на мой взгляд, один из лучших online редакторов. И в теории его можно подключить практически к любому сайту, независимо от того какой движок/фреймворк/CMS используется.

Но, естественно, всегда существует несколько нюансов, которые немного усложняют жизнь :-)

В этой статье речь пойдет о том как подключить этот редактор к сайту использующему PHP фреймворк CodeIgniter. Вообще-то я нашел довольно много статей и рекомендаций на эту тему, но в большинстве из них предлагается скопировать файлы редактора в папки библиотек или плагинов, а, на мой взгляд, это не правильно.

Дело вот в чем. Плагины и библиотеки (пользовательские) обычно находятся в папке application, которая не обязательно должна находиться внутри DOCUMENT_ROOT. Точнее, с точки зрения безопасности, эту папку лучше убрать за пределы DOCUMENT_ROOT чтобы исключить любую возможность прямого доступа к скриптам сайта (т.е. скрипты будут доступны только через index.php).

Но FCKeditor содержит файлы картинок, стилей и т.п., к которым нужно обеспечить прямой доступ. Т.е. его нужно разместить внутри DOCUMENT_ROOT.

Как оказалось, обойти эту проблему совсем не сложно.

Прежде всего, рассмотрим структуру папок сайта.

index.php
system/
fckeditor/
images/
css/
libs/

Как видите, в корне сайта (DOCUMENT_ROOT) находятся главный контроллер (index.php), папки system, fckeditor (с редактором) и другие папки с картинками, CSS стилями, библиотеками и т.п.

Папка application по-умолчанию находится внутри system, но ее можно спокойно перенести.

Подключаем редактор

Прежде всего, создадим файл настроек (application/config/fckeditor.php)

<?php
//путь к FCKeditor относительно корня сайта (папки, в которой находится index.php)
$config['fckeditor_path'] = 'fckeditor/';
//URL FCKeditor относительно корня сайта (параметра $config['base_url'])
$config['fckeditor_url'] = 'fckeditor/';
//имя редактора
$config['fckeditor_name'] = 'MyFCKeditor';
//высота редактора
$config['fckeditor_height'] = 300;
?>

Объяснять тут в общем-то нечего. Главное правильно указать параметры fckeditor_path и fckeditor_url.

Теперь создадим файл библиотеки, который будет подключать редактор (/application/libraries/fcke.php).

<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * Эта библиотека подключает редактор FCKeditor
 *
 * @version 0.1
 * @link http://www.simplecoding.org
 * @author Стаценко Владимир <vova_33@gala.net>
 */
class FCKe {
     
    private $editor = null;
     
    function FCKe() {
        $CI = &get_instance();
        //читаем данные из конфига
        $CI->config->load('fckeditor');
        $fcke_url = $CI->config->item('base_url').$CI->config->item('fckeditor_url');
        $fcke_path = substr(FCPATH, 0, strrpos(FCPATH, DIRECTORY_SEPARATOR) + 1)
            .$CI->config->item('fckeditor_path');
        include_once($fcke_path.'fckeditor.php');
        $this->editor = new FCKeditor($CI->config->item('fckeditor_name'));
        $this->editor->BasePath = $fcke_url;
        $this->editor->Height = $CI->config->item('fckeditor_height');
    }
 
    function __call($method, $arguments) {
        return call_user_func_array(array($this->editor, $method), $arguments);
    }
}
/* End of file fckeditor.php */
/* Location: ./system/application/libraries/fckeditor/fckeditor.php */

Разберем этот код подробнее.

В конструкторе мы читаем параметры из конфига, загружаем файл fckeditor.php и создаем объект редактора (FCKeditor).

Параметр fckeditor_path используется при загрузке файла fckeditor.php (строка 21). А с помощью fckeditor_url задаем URL папки редактора (строка 23).

Доступ к методам редактора обеспечивает метод __call.

Проще говоря, мы написали оболочку, которая загружает редактор и обеспечивает доступ ко всем его методам.

Теперь использовать редактор не сложнее чем любую другую библиотеку CodeIgniter.

В контроллере загружаем библиотеку:

$this->load->library('fcke');

И сразу же можем создать редактор.

$this->fcke->Create();

Как видите, метод Create() редактора вызывается через объект fcke, т.е. нашу библиотеку.

Примечание. Редактор должен находится внутри формы. Атрибут action указывает какому скрипту будет отправлен текст, введенный в редактор.

Небольшое дополнение. Метод Create() сразу же отправляет код редактора браузеру, т.е. его нужно вызывать из представления. В общем-то, ничего страшного, но это нарушение MVC модели. Если хотите этого избежать используйте метод CreateHtml() в контроллере. Он возвращает HTML код редактора, который затем можно передать представлению. Например:

в контроллере:

$this->load->library('fcke');
$pageData['editor'] = $this->fcke->CreateHtml();
$this->load->view('my_view', $pageData);

в представлении:

<?php
echo $editor;
?>

В общем, подключить редактор не сложно.

Добавлено: 21 Апреля 2018 18:03:26 Добавил: Андрей Ковальчук