Как изменить длину поля настроек?

46

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

Я не могу изменить максимальный размер с Drupal, потому что я получаю следующее сообщение об ошибке:

В базе данных есть данные для этого поля. Настройки поля больше не могут быть изменены.

Однако должно быть решение. Должен ли я изменить его в базе данных (поле реализовано модулем Field-collection )?

Эк Космос
источник
Можете ли вы сказать нам, какая версия Drupal и CCK? Также есть какие-нибудь модули CCK contrib?
Патрик
Версия Drupal - 7.
Эк Космос
И вы не можете изменить его в разделе управления типами контента? Вы должны иметь возможность изменить его в любой момент. Это может дать вам предупреждение, но все же должно позволить. Это может быть ошибка / ограничение в модуле сбора полей.
Патрик
Вы пробовали использовать группы полей? Теперь вы можете делать такие вещи, как групповое дублирование, что вы не могли раньше.
Патрик
Я не могу изменить его в разделе управления типами контента! Это главное. Drupal не дай мне сделать это.
Эк Космос

Ответы:

89

Решение Dylan Tack - самое простое, но лично мне нравится изучать внутреннюю защиту базы данных Drupal, чтобы увидеть, как там все управляется.

Итак, если у вас есть текстовое поле с именем машины field_text из 10 символов, которое вы хотите увеличить до 25:

  • данные будут храниться в двух таблицах: field_data_field_text и field_revision_field_text
  • определение хранится в field_config для данных хранения и field_config_instance для каждого экземпляра этого поля (например, метка).

Теперь давайте сделаем небольшую операцию на сердце.

  1. Измените определения столбцов таблиц данных:

    ALTER TABLE `field_data_field_text` 
    CHANGE `field_text_value` `field_text_value` VARCHAR( 25 ) 
    CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
    
    ALTER TABLE `field_revision_field_text` 
    CHANGE `field_text_value` `field_text_value` VARCHAR( 25 ) 
    CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
    
  2. Измените определение столбца, это очень сложно, потому что он хранится в BLOB , но это не остановит вас в этом.

    • Рассеките внутренности этой BLOB- вещи:

    SELECT CAST(`data` AS CHAR(10000) CHARACTER SET utf8) 
    FROM `field_config` WHERE field_name = 'field_text';
    
    • Это даст вам что-то вроде:

    a:7:{s:12:"translatable";s:1:"1";s:12:"entity_types";a:0:{}s:8:"settings";a:2:
        {s:10:"max_length";s:2:"10";s:17:"field_permissions";a:5:
        //a lot more stuff...
    
    • Это сериализованный массив PHP , интересная часть в том s:10:"max_length";s:2:"10";, что этот массив имеет свойство с именем max_length(имя которого представляет собой строку из 10 символов - отсюда и "s"), значение которого равно 10 (это строка длиной в 2 символа). Это довольно легко, не правда ли?

    • Изменить его так же просто, как заменить s:2:"10"деталь на s:2:"25". Будьте осторожны: если ваше новое значение длиннее, вы должны адаптировать часть "s", например, если положить 100, то будет 100, s:3:"100"а длина - 3.

    • Давайте поместим это новое значение обратно в БД, не забудьте сохранить всю строку.

    UPDATE `field_config` 
    SET data = 'a:7:{...a:2:{s:10:"max_length";s:2:"25";...}'
    WHERE `field_name` = 'field_text'
    
    • Сбрось свои тайники.
  3. ???

  4. PROFIT!

Кстати, в PhpMyAdmin есть некоторые настройки, позволяющие напрямую изменять столбцы BLOB , но зачем идти простым путем?

PS: Это также может спасти вам жизнь, когда вы помещаете некоторый PHP-код в представления и получаете WSOD из-за ошибки в вашем коде.

tostinni
источник
Это первое утверждение SQL должно сказать ALTER TABLEнет SELECT TABLE. Кроме того, вы можете сделать его чище, например: ALTER TABLE field_data_field_text MODIFY field_text_value... (MODIFY - это как CHANGE, когда вы не хотите менять имя . И вы этого не делаете.)
artfulrobot
4
Спасибо за это. Я бы хотел, чтобы у меня было больше одного голоса.
BC01
1
Этот пост использует API схемы Drupal для достижения того же подхода: up2technology.com/blog/converting-drupal-fields
Juampy NR
2
Если вы не против отправить ваши сериализованные данные в интернет, я нашел этот инструмент, отлично подходящий
Пит
Если вы получаете сообщение об ошибке «CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL», вы можете использовать PhpMyAdmin.
tog22
19
function mymodule_update_7100() {
  $items = array();
  _field_maxlength_fix('field_name');
  return $items;
}

function _field_maxlength_fix($field_name, $maxlength = 255) {
  _alter_field_table($field_name, $maxlength);
  $data = _get_field_data($field_name);
  $data = _fix_field_data($data, $maxlength);
  _update_field_config($data, $field_name);
}

function _alter_field_table($field_name, $maxlength) {
  db_query("ALTER TABLE field_data_".$field_name." CHANGE ".$field_name."_value ".$field_name."_value VARCHAR( ".$maxlength." ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL");
  db_query("ALTER TABLE field_revision_".$field_name." CHANGE ".$field_name."_value ".$field_name."_value VARCHAR( ".$maxlength." ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL");
}

function _get_field_data($field_name) {
  $qry = "SELECT data FROM field_config WHERE field_name = :field_name";
  $result = db_query($qry, array(':field_name' => $field_name))->fetchObject();
  return unserialize($result->data);
}

function _fix_field_data($data, $maxlength) {
  $data['settings']['max_length'] = (string)$maxlength;
  return serialize($data);
}

function _update_field_config($data, $field_name) {
  $qry = "UPDATE field_config SET data = :data WHERE field_name = :field_name";
  db_query($qry, array(':data' => $data, ':field_name' => $field_name));
}
Кевин Томпсон
источник
Как это исправление больше всего, поскольку оно не зависит от ручного взлома БД ... важно иметь реплицируемое решение через hook_update_N!
Арейнольдс
9

Похоже, что это ограничение текущего текстового модуля. text_field_settings_form () содержит следующий комментарий: « @todo : Если $ has_data, добавьте обработчик проверки, который позволяет увеличивать только max_length.».

В качестве временного решения вы можете закомментировать '#disabled' => $has_dataв файле modules / field / modules / text / text.module в строке 77.

Я не смог найти существующую проблему для этого конкретного случая, но вы могли бы упомянуть об этом на # 372330 .

Дилан Тэк
источник
2
Спасибо за Ваш ответ. У меня есть комментарий к строке, и теперь я могу изменить значение из поля, однако после сумбита я получаю следующую ошибку:Attempt to update field Serial No failed: field_sql_storage cannot change the schema for an existing field with data..
Ek Kosmos
Что касается совершения проблемы с друпалом, пожалуйста, сделайте это.
Эк Космос
1
Я не мог заставить это работать. После того, как я прокомментировал эту строку, я все еще получил ошибку MYSQL, из-за которой не удалось выполнить ALTER TABLE.
jchwebdev
Если вы получили, FieldUpdateForbiddenException: cannot change the schema for an existing field with dataвам также нужно прокомментировать L282 modules/field/modules/field_sql_storage/field_sql_storage.module.
Dieuwe
Комментарий @ dieuwe неверен. Этот файл не существует в последних версиях D8 (если он когда-либо существовал). Вам необходимо закомментировать две строки в core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.phpэтом исключении с текстом «Хранилище SQL не может изменить схему для существующего поля». О строках 1312 и 1403.
Далин
6

Drupal 7

При создании текстового поля в Drupal 7 вы должны выбрать максимальную длину для ваших данных. Как только вы создадите какие-либо данные для этого поля, максимальная длина станет неизменной в настройках поля Drupal.

Понятно, что это будет отключено для уменьшения максимальной длины, поскольку это может привести к потере данных, однако должна быть возможность увеличить максимальную длину для любого поля. Тодо в коде модуля Drupal 7 Text показывает, что это было задумано, но никогда не было выполнено.

3 вещи, которые должны произойти:

  1. Измените длину VARCHAR столбца значения в таблице field_data_ {fieldname}
  2. Измените длину VARCHAR столбца значений в таблице field_revision_ {fieldname}
  3. Обновите конфигурацию поля, чтобы отразить новую настройку максимальной длины Следующая функция выполняет все 3 из этих шагов и принимает 2 простых параметра, включая имя поля и новую максимальную длину.
/**
 * Helper function to change the max length of a text field.
 */
function MYMODULE_change_text_field_max_length($field_name, $new_length) {
  $field_table = 'field_data_' . $field_name;
  $field_revision_table = 'field_revision_' . $field_name;
  $field_column = $field_name . '_value';

  // Alter value field length in fields table.
  db_query("UPDATE `{$field_table}` SET `{$field_column}`=SUBSTR(`{$field_column}`, 0, {$new_length})");
  db_query("ALTER TABLE `{$field_table}` CHANGE `{$field_column}` `{$field_column}` VARCHAR( {$new_length} )");
  // Alter value field length in fields revision table.
  db_query("UPDATE `{$field_revision_table}` SET `{$field_column}`=SUBSTR(`{$field_column}`, 0, {$new_length})");
  db_query("ALTER TABLE `{$field_revision_table}` CHANGE `{$field_column}` `{$field_column}` VARCHAR( {$new_length} )");

  // Update field config with new max length.
  $result = db_query("SELECT CAST(`data` AS CHAR(10000) CHARACTER SET utf8) FROM `field_config` WHERE field_name = '{$field_name}'");
  $config = $result->fetchField();
  $config_array = unserialize($config);
  $config_array['settings']['max_length'] = $new_length;
  $config = serialize($config_array);
  db_update('field_config')
    ->fields(array('data' => $config))
    ->condition('field_name', $field_name)
    ->execute();
}

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

/**
 * Change max_length of Name field
 */
function mymodule_update_7002() {
  MYMODULE_change_text_field_max_length('field_name', 50);
}

Источник: http://nathan.rambeck.org/blog/42-modify-drupal-7-text-field-maximum-length


Drupal 8

Вот версия той же функции, предложенной @Christopher :

/**
 * Utility to change the max length of a text field.
 *
 * @param string $field_name
 *   Field name. 
 * @param int $new_length
 *   Field length in characters. 
 *
 * @throws \DrupalUpdateException
 */
function MYMODULE_change_text_field_max_length($field_name, $new_length) {
  // The transaction opens here. 
  $txn = db_transaction();

  try {
    // Update field content tables with new max length.
    foreach (['field_data_', 'field_revision_'] as $prefix) {
      db_query('
      ALTER TABLE {' . $prefix . $field_name . '} 
        MODIFY ' . $field_name . '_value VARCHAR( ' . $new_length . ' )
      ');
    }

    // Update field config record with new max length.
    $result = db_query("
        SELECT CAST(data AS CHAR(10000) CHARACTER SET utf8) 
        FROM {field_config} 
        WHERE field_name = :field_name
      ", [':field_name' => $field_name]
    );
    $config = $result->fetchField();
    if ($config) {
      $config_array = unserialize($config);
      $config_array['settings']['max_length'] = $new_length;
      $new_config = serialize($config_array);
      db_update('field_config')
        ->fields(['data' => $new_config])
        ->condition('field_name', $field_name)
        ->execute();
    }
  }
  catch (Exception $e) {
    // Something went wrong somewhere, so roll back now.
    $txn->rollback();
    // Allow update to be re-run when errors are fixed.
    throw new \DrupalUpdateException(
      "Failed to change $field_name field max length: " . $e->getMessage(),
      $e->getCode(), $e
    );
  }
}
kenorb
источник
1
Мы использовали этот метод drupal 8 в проекте и столкнулись с проблемами, из-за которых при запуске drush updb --entity-updatesполей, которые мы выполняли с помощью этой функции, была помечена как требующая обновления. Затем он попытается обновить схему поля снова в MySQL. Для нас это потерпит неудачу, поскольку там уже есть полевые данные. Это препятствовало запуску других задач обновления.
leon.nk
Короче говоря, вероятно, безопаснее создавать новые поля и переносить данные между ними.
leon.nk
3

Попробуйте это ... это обновит тип данных поля с TEXT до LONG_TEXT и обновит max_lengthтекст с 4000 до максимальной длины текста ... надеюсь, это поможет.

function my_module_update_1001(&$sandbox) {
  // Check if our field is already created.
  if (field_info_field('sample_text_field')) {
    db_query('ALTER TABLE field_data_sample_text_field CHANGE sample_text_field_value sample_text_field_value LONGTEXT');
    db_query('ALTER TABLE field_revision_sample_text_field CHANGE sample_text_field_value sample_text_field_value LONGTEXT');
    db_query("UPDATE field_config SET type = 'text_long' WHERE field_name = 'sample_text_field' ");

    $field = array(
      'field_name' => 'sample_text_field',
      'type' => 'text_long',
      'cardinality' => 1,
      'settings' => array(
         'max_length' => 0,
      ),
    );
    field_update_field($field);    
  }
}
Гарольд
источник
3

D8

  1. Закомментируйте две строки в core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchem‌​a.phpэтом исключении с текстом «Хранилище SQL не может изменить схему для существующего поля». О строках 1312 и 1403.
  2. В вашем браузере перейдите к /admin/config/development/configuration/single/export. Тип конфигурации - «Хранение полей», и выберите соответствующее поле. Скопируйте конфигурацию.
  3. Перейдите к /admin/config/development/configuration/single/import. , Тип конфигурации - «Полевое хранилище». Вставьте конфигурацию. Измените длину.
  4. Отправьте форму.

Обратите внимание (как вы, вероятно, уже знаете), если вы укоротите длину, то существующие данные будут усечены.

Далин
источник
Это работает как шарм. Начиная с Drupal 8.5.3, в защищенной функции updateDedicatedTableSchema используются строки 1505-1507 и 1596-1598 в защищенной функции updateSharedTableSchema. Обязательно вернитесь назад, когда это будет сделано! Спасибо.
Гонконг
Я впервые попробовал этот подход. Я пытаюсь изменить поле абзаца. Это работает, но в любом случае обязательно изменить соответствующие таблицы.
Яазкал
@ Яазкал Хммм, это был не мой опыт. Вы пытаетесь удлинить или укоротить поле?
Далин
@Dalin удлиняется, с 255 до 510. Используя D 8.5.5 и параграфы 1.3
Yaazkal
1

В Drupal 7 я внес изменения в 2 таблицы в phpmyadmin и обновил кеш.

  1. «field_data_field_lorem»: изменено «field_lorem_value» на «longtext»
  2. «field_config»: изменено «type» на «text_long»
Джил
источник
Вы отправили это как патч для D7? Если это действительно проблема, то вам следует выпустить для них патч, чтобы решить эту проблему в основном коде.
Патрик
Я изменил значение размера поля с phpmyadmin (с 10 до 25 типа VARCHAR) и обновил кеш, однако не работает. В базе данных ramained VARCHAR (25), но в Drupal, поле имеет то же значение максимального размера, что и раньше 10. Может быть, есть какая-то скрытая настройка поля?
Эк Космос