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

typeahead

Код примера:

<input type="text" data-provide="typeahead" data-items="4" 
data-source='["Alabama","Alaska","Arizona","Arkansas","California","Colorado","Connecticut",
"Delaware","Florida","Georgia","Hawaii","Idaho","Illinois","Indiana","Iowa","Kansas",
"Kentucky","Louisiana","Maine","Maryland","Massachusetts","Michigan","Minnesota",
"Mississippi","Missouri","Montana","Nebraska","Nevada","New Hampshire","New Jersey",
"New Mexico","New York","North Dakota","North Carolina","Ohio","Oklahoma","Oregon",
"Pennsylvania","Rhode Island","South Carolina","South Dakota","Tennessee","Texas",
"Utah","Vermont","Virginia","Washington","West Virginia","Wisconsin","Wyoming"]'>

Для работы с Twitter Bootstrap нам понадобиться подключить сам скрипт Twitter Bootstrap и файл стилей используемый этим скриптом:

<head>
   <link href="assets/css/bootstrap.css" rel="stylesheet">
   <script src="assets/js/bootstrap.js"></script>
</head>

Но в большинстве случаев нам необходимы данные из БД, например поиск пользователя по имени. В этом случае нам необходим запрос к БД при помощи ajax:

<!-- поле ввода имени -->
<input type="text" name="name">
<input type="text" name="email">
<input type="text" name="phone">
<!-- подключаем typeahead  -->
<script>
$('input[name=username]').typeahead({
        //источник данных
        source: function (query, process) {
           return $.post('getusername', {'name':query}, 
                 function (response) {
                      var data = new Array();
                      //преобразовываем данные из json в массив
                      $.each(response, function(i, name)
                      {
                        data.push(i+'_'+name);
                      })
                      return process(data);
                    },
                 'json'
                 );
          }
          //источник данных
          //вывод данных в выпадающем списке
          , highlighter: function(item) {
              var parts = item.split('_');
              parts.shift();
              return parts.join('_');
          }
          //вывод данных в выпадающем списке
          //действие, выполняемое при выборе елемента из списка
          , updater: function(item) {
                     var parts = item.split('_');
                     var userId = parts.shift();
                     $.post('getuserdata', {'user_id':userId},
                          function (user) {
                            $('input[name=email]').val(user.email);
                            $('input[name=phone]').val(user.phone);
                          },
                       'json'
                      );
                      return parts.join('_');
                   }
          //действие, выполняемое при выборе елемента из списка
          }
);
</script>

В этом примере производится 2 запроса к БД: 1й выводит имена пользователей и получает id выбранного пользователя, а второй на основании id – запрашивает и выводит в соответствующие поля email и номер телефона выбранного пользователя. При помощи использования разделителя “_” data.push(i+’_’+name); мы в одном запросе получаем два параметра, это оправдано при небольшом количестве данных, таких, как id и имя, остальные данные мы получаем во втором запросе var parts = item.split(‘_’); var userId = parts.shift();.

Ниже 2 экшена на примере фреймворка Kohana с подключенным и настроенным модулем БД и ORM, для чистого PHP необходимо произвести подключение к БД и написание запроса с последующим выводом данных.

public function action_getname() {
            $users = ORM::factory('user')
                     ->where('name', 'LIKE', '%' . $_POST['name'] . '%')
                     ->find_all()
                     ->as_array('id', 'name');
            echo json_encode($users);
}

public function action_getuserdata() {
            $user = ORM::factory('user', $_POST['usr_id']);
                     ->as_array('id', 'name');
            echo json_encode($user);
}

Всевозможные детализации и проверки в данном примере не приводятся для упрощения кода.

Пользуюсь Git, иногда при первом push в репозиторий можно встретить следующее сообщение об ошибке:

! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to ...

для устранения этого, идем на сервер и в папке проекта пишем следующую комманду:

git config receive.denyCurrentBranch ignore
Posted in Git.

Прежде всего столкнулся с вот такой вот ошибкой:

Fatal error: Undefined class constant 'Log::EMERGENCY' in /home/kuznya/wadya.pp.ua/shariki33/system/classes/Kohana/Kohana/Exception.php on line 140

Вот ссылка на комметарий разработчика: http://dev.kohanaframework.org/issues/4631
там указано, что данное сообщение сигнализирует о том, что версия PHP на хостинге ниже 5.3, необходимо самостоятельно изменить настройки хостинга либо обратиться за помощью к хостмастеру.
Если переносили проект с 3.2 на 3.3 не забываем о том, что на локальном сервере все как правило работают в системах, которым не особо важен регистр имен файлов и папок, но вот когда выкладываешь проект, то хостинг как правило из семейства Linux и тут уж регистер играет важную роль. Поэтому, если при переносе проекта на хостинг у вас не стартует проект и выкидывает 404 Exception проверьте, что основные папки Controller, Model и файлы контроллеров начинаються с заглавных букв. Ко всему прочему, модули для kohana 3.2 требуют похожей модификации, т.е. замена названий на такие же, но с заглавными символами в начале.

Для проекта выбрал модуль https://github.com/evopix/orm-mptt
Описанный в readme функционал – работает без проблем, а вот с остальным пришлось помучиться.
Но обо всем – по порядку.
Многие проекты имеют сложную структуру категорий товаров либо информации.
Часто требуется не фиксированная глубина вложенности.
Для этих целей, как нельзя лучше, подойдет модель хранения данных Nested set и ее реализация посредством модуля для Kohana MPTT.
Более детально о nested set
Есть несколько различных реализаций, но я остановился на модуле от evopix.
Ниже приведу описание основных методов модуля.
Нам потребуется таблица БД, вот ее упрощенная структура:

  • id – уникальный идентификатор-счетчик
  • parent_id – родительский id (для рутов – значение = 0)
  • lvl – уровень (для рутовых категорий он равен 1)
  • lft
  • rgt
  • scope – № ветви
  • name – наименование категории
  • url – url категории

Модель наследуем от ORM_MPTT

 class Model_Category extends ORM_MPTT { }

Создание корневого узла:

$cat = ORM::factory('category');
$cat->name = 'Каталог';
$cat->insert_as_new_root();

Создание последнего дочернего узла:

$parent_cat = ORM::factory('category')->where('name', '=', 'Каталог')->find();
$cat->name = 'Мобильные телефоны';
$cat->insert_as_last_child($parent_cat);
$cat->name = 'Планшеты';
$cat->insert_as_last_child($parent_cat);
$cat->name = 'Аксессуары для планшетов';
$cat->insert_as_last_child($parent_cat);
$cat->name = 'Литература о планшетах';
$cat->insert_as_last_child($parent_cat);

По аналогии создается дочерний узел, но вставляется перед всеми существующими:

$parent_cat = ORM::factory('category')->where('name', '=', 'Каталог')->find();

$cat->name = 'Бытовая техника';

$cat->insert_as_first_child($parent_cat);

Создание братского узла (узла того же уровня вложенности) перед указанным узлом:

$sibling_cat = ORM::factory('category')->where('name', '=', 'Планшеты')->find();

$cat->name = 'Комплектующие';

$cat->insert_as_prev_sibling($sibling_cat);

Создание братского узла (узла того же уровня вложенности) после указанного узла:

$sibling_cat = ORM::factory('category')->where('name', '=', 'Планшеты')->find();
$cat->name = 'Ноутбуки';
$cat->insert_as_next_sibling($sibling_cat);

Перемещение произвольного узла с подузлами в выбранный узел (в нашем случае перемещаем категорию "Аксессуары для планшетов" в категорию "Планшеты" перед всеми имеющимися узлами):

$source_cat = ORM::factory('category')
->where('name', '=', 'Аксессуары для планшетов')->find();

$destination_cat = ORM::factory('category')
->where('name', '=', 'Планшеты')->find();

$cat->move_to_first_child($destination_cat); 
//Перемещаем на место первого дочернего узла

То же самое, но теперь вставляем категорию после всех имеющихся узлов:

$source_cat = ORM::factory('category')
->where('name', '=', 'Литература о планшетах')->find();

$destination_cat = ORM::factory('category')
->where('name', '=', 'Планшеты')->find();

$cat->move_to_last_child($destination_cat); 
//Вставляем последним дочерним узлом

По аналогии возможны перемещения братских узлов:

$sibling_cat = ORM::factory('category')
->where('name', '=', 'Мобильные телефоны')->find();

$cat = ORM::factory('category')
->where('name', '=', 'Планшеты')->find();

$cat->move_to_prev_sibling($sibling_cat); 
//Перемещаем на позицию перед братским узлом
$sibling_cat = ORM::factory('category')
->where('name', '=', 'Мобильные телефоны')->find();

$cat = ORM::factory('category')
->where('name', '=', 'Планшеты')->find();

$cat->move_to_next_sibling($sibling_cat);
//Перемещаем на позицию после братского узла

В этом месте лично меня ожидал неприятный сюрприз.
Никаким образом категории не желали перемещаться.
Для решения данной проблемы необходимо изменить код в модуле modules\orm-mptt\classes\kohana\orm\mptt.php в методе lock(), на следующий:

protected function lock()
{
    $q = 'LOCK TABLE '.$this->_db->quote_table($this->_table_name).' WRITE';

    if ($this->_object_name)
    {
        $q.= ', '.$this->_db->quote_table($this->_table_name);
        $q.= ' AS '.$this->_db->quote_column($this->_object_name).' WRITE';
    }

    $this->_db->query(NULL, $q, TRUE);
}

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

Некоторые задачи для сайта необходимо выполнять при помощи планировщика crontab
Например, рассылки писем, формирование и отправка отчетов администраторам и т.д.
В этом случае нам необходимо запускать наши скрипты из командной строки.
Для этого подготовим контроллер, например, stat.php,
разместим его в /kohana/application/classes/controller/
Continue reading

Как и у большинства фреймворков, у kohana есть модуль для работы с базой данных на основе объектов – ORM. Полезность и удобство этого модуля сейчас никто не ставит под сомнение. Многие задачи программирования решаются с помощью ORM. ORM это не только удобство, но и универсальность кода, другими словами: любому программисту использующему ORM будет достаточно просто понять код другого разработчика.

Основные методы и приемы использования ORM.

  • Получение данных из таблицы
    //получаем все записи из таблицы "users".
    $users = ORM::factory('user')
    ->find_all(); 
    
    //получаем все записи из таблицы "users"
    //с условием-фильтром по слову "victor" в поле "name".
    $users = ORM::factory('user')
    ->where('name', 'LIKE', "%victor%")->find_all();
    
    //получаем одну запись со значением поля "name"="victor".
    $user = ORM::factory('user')
    ->where('name', '=', "victor")->find();
    еще вариант:
    $user = ORM::factory('user', $user_id); 
    что соответствует такому варианту синтаксиса
    $user = ORM::factory('user')->where('id', '=', $user_id)->find();

    Continue reading

Иногда возникает необходимость воспользоваться функцией SQL в Query Builder или в ORM, это можно сделать при помощи:
$users = ORM::factory('user')->where(DB::expr('LOWER(`name`)), 'like', "%$searchdata%")->find_all();
Т.е. в данном примере мы средствами SQL переводим данные из поля name таблицы users в нижний регистр и производим по ним поиск.

Традиционно нашел этот модуль на Git https://github.com/ThePixelDeveloper/kohana-sitemap.
Я качал модуль до его модификации под kohana 3.2, правки делал сам,
поэтому у кого не пойдет модуль с Git – можно воспользоваться модифицированным мною:
sitemap.zip

Небольшое поянение, как использовать (прежде всего модуль необходимо
распаковать в папку modules, подключить в bootstrap.php), далее все
что написанно ниже ложим в свой контроллер-экшн:

Continue reading

Русскоязычный проект http://www.captcha.ru/kcaptcha/ пользуется популярностью не только у русскоязычных программистов.
Немного дополнив код от https://github.com/kolanos/kohana-captcha (ниже я писал как допилить его к Kohana 3.2) я получил возможность использовать алгоритм от KCAPTCHA 2.0
Ссылка на готовый модуль: http://wadya.pp.ua/files/captcha_khapcha.zip