Большие цены в Drupal Commerce

В Drupal Commerce имеется одна неприятная особенность, с которой может столкнуться каждый. Проблема заключается в том, что в базе данных у цен размер равен int(11). Но существует ряд стран, например Беларусь, где цена 30 000 000.00 и больше - вполне нормальное явление. И тут начинаются проблемы, при попытке оформить заказ с такой ценой - система безотказно будет информировать нас о том, что цена выходит за границы размера поля.

Чтобы исправить эту проблему, имплементируем хук hook_field_create_field():

<?php

/**
 * Implements hook_field_create_field().
 */
function example_field_create_field($field) {
  if ($field['module'] == 'commerce_price'
    && $field['type'] == 'commerce_price'
    && isset($field['columns']['amount']['type'])
    && $field['columns']['amount']['type'] == 'int'
    && (!isset($field['columns']['amount']['type']) || $field['columns']['amount']['type'] != 'big')) {

    $spec = $field['columns']['amount'];
    $spec['size'] = 'big';
    foreach (array('field_data_', 'field_revision_') as $prefix) {
      $table = $prefix . $field['field_name'];
      $column = $field['field_name'] . '_amount';
      db_change_field($table, $column, $column, $spec);
    }
  }
}

Теперь при создании новых "commerce_price" полей, их размер будет изменен на big. Модуль с этим хуком необходимо включить до того, как будет установлен Drupal Commerce.

Для обновления всех существующих полей, необходимо открыть консоль и воспользоваться командой:

drush eval 'foreach (field_info_fields() as $field) { example_field_create_field($field); }'

Update

С момента написания урока, прошло немало времени и код, который работал в момент написания вдруг перестал работать. Вооружившись дебагером я посмотрел, что же пошло не так и как оказалось, что каждый раз, когда мы сохраняем настройки поля, вызвается функция field_update_field(), которая обновляет схему поля на дефолтную. Что ж, немного модифицируем наш модуль.

Для начала напишем новую функцию, которая будет изменять схему поля:

/**
 * Updates a size of "amount" column for commerce_price field.
 *
 * @param array $field
 *   A field structure. $field['field_name'] must provided; it identifies the
 *   field that will be updated to match this structure. Any other properties
 *   of the field that are not specified in $field will be left unchanged,
 *   so it is not necessary to pass in a fully populated $field structure.
 */
function _example_commerce_price_update_field($field) {
  if ($field['module'] == 'commerce_price'
    && $field['type'] == 'commerce_price'
    && isset($field['columns']['amount']['type'])
    && $field['columns']['amount']['type'] == 'int'
    && (!isset($field['columns']['amount']['type']) || $field['columns']['amount']['type'] != 'big')) {

    $spec = $field['columns']['amount'];
    $spec['size'] = 'big';
    foreach (array('field_data_', 'field_revision_') as $prefix) {
      $table = $prefix . $field['field_name'];
      if (db_table_exists($table)) {
        $column = $field['field_name'] . '_amount';
        db_change_field($table, $column, $column, $spec);
      }
    }
  }
}

Далее имплементируем хуки hook_field_create_field() и hook_field_update_field():

/**
 * Implements hook_field_create_field().
 */
function example_field_create_field($field) {
  _example_commerce_price_update_field($field);
}

/**
 * Implements hook_field_update_field().
 */
function example_field_update_field($field, $prior_field, $has_data) {
  _example_commerce_price_update_field($field);
}

Комментарии (8)

Аватар пользователя oleg.steba
oleg.steba

Я создал модуль, прописал там одну эту функцию, и при вызове функции все работает, а вот при создании нового поля типом commerce_price в базу все равно пишется int(11) может я чего-то не понимаю, но подскажите пожалуйста, что нужно еще прописать чтобы все работало на автомате.

Аватар пользователя Benya
Benya

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

Аватар пользователя oleg.steba
oleg.steba

Извините меня если мой вопрос покажется вам глупым, написание собственных модулей я начал недавно. Из данной статьи я понял что если создать свой модуль к примеру cm_price_sql_type и в нем переопределить данный hook (на function cmprice_sql_type_field_create_field($field)) то при создании нового поля цена в базе для поля будет установлен тип bigint. Но когда я создаю данное поле в базе все равно для него пишется тип int. Может подскажите какой hook прописать чтобы данная функция срабатывала так как если ее запустить отдельно она выполняется.

Аватар пользователя Benya
Benya

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

Аватар пользователя oleg.steba
oleg.steba

Спасибо, за помощь. Буду изучать API. Если решите данную проблему то напишите о ее решении.

Аватар пользователя Benya
Benya

Обновил урок, теперь все должно работать

Аватар пользователя oleg.steba
oleg.steba

Спасибо, все работает. Вы могли бы подсказать литературу ссылки или уроки по написанию модулей для drupal 7. Я только начинаю изучать API функции и написание своих модулей, и хотел бы совет специалиста.
Зарание благодарен.

Аватар пользователя Benya
Benya

Как таковой литературы не подскажу. Сам изучал с помощью модуля Examples for Developers, в нем представленны модули почти на любую тематику с комментариями по коду. Ну и само сабой Drupal API, здесь вы найдете всю документацию.