web-dev-qa-db-fra.com

Comment changer la longueur des réglages sur place?

J'ai fixé une fois à un site Web une limite de longueur à un champ. Et maintenant, le client veut mettre plus de caractères dans ce champ.

Je ne peux pas changer la taille maximale de Drupal car je reçois le message d'erreur suivant:

Il existe des données pour ce champ dans la base de données. Les réglages sur place ne peuvent plus être modifiés.

Cependant, il doit y avoir une solution. Dois-je le changer dans la base de données (le champ est celui implémenté par le module Field-collections )?

47
Ek Kosmos

La solution Dylan Tack est la plus simple, mais personnellement, j'aime explorer les quartiers intérieurs de la base de données de Drupal pour voir comment les choses sont gérées là-bas.

Donc, en supposant que vous ayez un champ de texte dont le nom de la machine est field_text de 10 caractères que vous souhaitez augmenter à 25:

  • les données seront stockées dans deux tables: field_data_field_text et field_revision_field_text
  • la définition est stockée dans field_config pour les données de stockage, et field_config_instance pour chaque instance de ce champ (des trucs comme label).

Faisons maintenant une petite chirurgie cardiaque.

  1. Modifiez les définitions des colonnes des tableaux de données:

    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. Modifiez la colonne de définition , celle-ci est très délicate car elle est stockée dans un blob [~ # ~] [~ # ~], mais ce n'est pas quelque chose qui vous empêchera de faire cela.

    • Disséquer les tripes de ce blob [~ # ~] [~ # ~] chose:
    SELECT CAST(`data` AS CHAR(10000) CHARACTER SET utf8) 
    FROM `field_config` WHERE field_name = 'field_text';
    
    • Cela vous donnera quelque chose comme:
    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...
    
    • Ceci est un tableau PHP sérialisé , la partie intéressante est s:10:"max_length";s:2:"10";, cela signifie que ce tableau a une propriété nommée max_length (dont le nom est une chaîne de 10 caractères - d'où le "s") dont la valeur est 10 (qui est une chaîne de 2 caractères). C'est assez simple, non?

    • Changer sa valeur est aussi simple que de remplacer le s:2:"10" pièce par s:2:"25". Attention: si votre nouvelle valeur est plus longue vous devez adapter la partie "s", par exemple mettre 100 sera s:3:"100" car 100 est égal à 3.

    • Remettons cette nouvelle valeur dans la base de données, n'oubliez pas de garder la chaîne entière.

    UPDATE `field_config` 
    SET data = 'a:7:{...a:2:{s:10:"max_length";s:2:"25";...}'
    WHERE `field_name` = 'field_text'
    
    • Videz vos caches.
  3. ???

  4. PROFIT!

Soit dit en passant, PhpMyAdmin a un paramètre pour permettre modification directe des colonnes BLOB , mais pourquoi opter pour la solution la plus simple?

PS: Cela peut également vous sauver la vie en mettant du code PHP dans les vues et en obtenant un WSOD en raison d'une erreur dans votre code.

89
tostinni
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));
}
20
Kevin Thompson

Cela semble être une limitation du module de texte actuel. text_field_settings_form () a ce commentaire: " @ todo : si $ has_data, ajoutez un gestionnaire de validation qui ne permet qu'à max_length d'augmenter . ".

Pour contourner le problème, vous pouvez commenter '#disabled' => $has_data dans modules/field/modules/text/text.module, autour de la ligne 77.

Je n'ai pas trouvé de problème existant pour ce cas spécifique, mais vous pouvez le mentionner sur # 3723 .

9
Dylan Tack

Drupal 7

Lorsque vous créez un champ de texte dans Drupal 7, vous devez choisir une longueur maximale pour vos données. Dès que vous créez des données pour ce champ, la longueur maximale devient immuable dans le Drupal.

Il est compréhensible que cela soit désactivé pour diminuer la longueur maximale car cela pourrait entraîner une perte de données, cependant, il devrait être possible d'augmenter la longueur maximale pour n'importe quel champ. Une tâche dans le code du module de texte Drupal 7 montre que cela était prévu mais jamais accompli.

Les 3 choses qui doivent arriver:

  1. Modifiez la longueur VARCHAR de la colonne de valeur dans la table field_data_ {fieldname}
  2. Modifiez la longueur VARCHAR de la colonne de valeur dans la table field_revision_ {fieldname}
  3. Mettre à jour la configuration du champ pour refléter le nouveau paramètre de longueur maximale La fonction suivante accomplit les 3 étapes et prend 2 paramètres simples, y compris le nom du champ et la nouvelle longueur maximale.
/**
 * 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();
}

Une fois que cette fonction est disponible dans votre fichier d'installation personnalisé, vous pouvez créer une nouvelle fonction de mise à jour de la base de données qui utilise cette nouvelle fonction pour effectuer les modifications requises.

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

Source: http://nathan.rambeck.org/blog/42-modify-drupal-7-text-field-maximum-length


Drupal 8

Voici la version de la même fonction proposée par @ 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
    );
  }
}
7
kenorb

Essayez ceci ... cela mettra à jour le type de données de champ de TEXT à LONG_TEXT et mettra à jour le max_length de 4000 à la longueur maximale du texte ... j'espère que cela vous aidera.

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
Harold

D8

  1. Mettez en commentaire les deux lignes dans core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchem‌​a.php qui lèvent des exceptions avec le texte "Le stockage SQL ne peut pas changer le schéma d'un champ existant". À propos des lignes 1312 et 1403.
  2. Dans votre navigateur, accédez à /admin/config/development/configuration/single/export. Le type de configuration est "Field Storage" et choisissez le champ en question. Copiez la configuration.
  3. Aller vers /admin/config/development/configuration/single/import. . Le type de configuration est "Field Storage". Collez la configuration. Modifiez la longueur.
  4. Soumettez le formulaire.

Remarque (comme vous le savez probablement déjà), si vous raccourcissez la longueur, les données existantes seront tronquées.

3
Dalin

Dans Drupal 7, j'ai apporté des modifications à 2 tables dans phpmyadmin et actualisé le cache.

  1. "field_data_field_lorem": changé "field_lorem_value" en "longtext"
  2. "field_config": changé "type" en "text_long"
1
Jill