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


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 из-за ошибки в вашем коде.


Это первое утверждение 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
    );
  }
}

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. Может быть, есть какая-то скрытая настройка поля?
Эк Космос
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.