Comment changer la longueur des paramètres de champ?

46

J'ai défini une fois sur un site Web une limite de longueur pour 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 paramètres de champ 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 Collections de champs )?

Ek Kosmos
la source
Pouvez-vous nous dire quelle version de Drupal et de CCK? Aussi des modules contrib CCK?
Patrick
La version Drupal est 7.
Ek Kosmos Le
Et vous ne pouvez pas le modifier dans la section des champs de gestion du type de contenu? Vous devriez pouvoir le modifier à tout moment. Cela peut vous donner un avertissement, mais il devrait quand même le permettre. Cela peut être un bug / une limitation dans le module de collections de champs.
Patrick
Avez-vous essayé d'utiliser des groupes de terrain? Vous pouvez maintenant faire des choses comme la duplication de groupe que vous ne pouviez pas auparavant.
Patrick
Je ne peux pas le modifier dans la section des champs de gestion du type de contenu! C'est le point. Drupal ne me laisse pas le faire.
Ek Kosmos

Réponses:

89

La solution Dylan Tack est la plus simple, mais personnellement, j'aime explorer les bases internes de la base de données de Drupal pour voir comment les choses se gèrent.

Donc, en supposant que vous ayez un champ de texte dont le nom d'ordinateur est field_text de 10 caractères, vous voulez passer à 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 éléments tels que label).

Faisons maintenant une petite opération du coeur.

  1. Modifiez les définitions de colonnes des tables 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. Changez 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 arrêtera pour cela.

    • Disséquer les entrailles de cette chose BLOB :

    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 longue de 2 caractères). C'est assez facile, n'est-ce pas?

    • Changer sa valeur est aussi simple que de remplacer la 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 égal s:3:"100"à 100, longueur 3.

    • Remettons cette nouvelle valeur dans la base de données, n'oubliez pas de conserver 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!

Au fait, PhpMyAdmin a quelques réglages pour permettre la modification directe des colonnes de BLOB , mais pourquoi aller facilement?

PS: Cela peut aussi vous sauver la vie lorsque vous insérez du code PHP dans des vues et obtenez un WSOD à cause d’une erreur dans votre code.

tostinni
la source
Cette première instruction SQL devrait dire ALTER TABLEnon SELECT TABLE. En outre, vous pouvez le rendre plus propre comme: ALTER TABLE field_data_field_text MODIFY field_text_value... (ACTUALISATION est comme le changement quand vous ne voulez pas changer le nom et vous ne..)
artfulrobot
4
Merci pour cela. J'aimerais avoir plus d'un vote positif à donner.
BC01
1
Ce message utilise l'API de schéma de Drupal pour réaliser la même approche: up2technology.com/blog/converting-drupal-fields
Juampy NR
2
Si vous ne vous dérange pas d'envoyer vos données sérialisées aux internets, j'ai trouvé cet outil, idéal pour l'édition: pines.sourceforge.net/phpserialeditor.php
Pete
Si vous obtenez une erreur à propos de 'CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL', vous pouvez utiliser 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));
}
Kevin Thompson
la source
Comme cela corrige le plus, car il ne repose pas sur le piratage manuel de bases de données ... Il est essentiel d’avoir une solution réplicable via un hook_update_N!
areynolds
9

Cela semble être une limitation du module de texte actuel. text_field_settings_form () a ce commentaire: " @todo : Si $ has_data, ajoute un gestionnaire de validation qui autorise uniquement l'augmentation de max_length.".

En guise de solution de contournement temporaire, vous pouvez commenter '#disabled' => $has_datadans 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 # 372330 .

Dylan Tack
la source
2
Merci pour votre réponse. J'ai commenter la ligne et maintenant je peux modifier la valeur du champ, mais l'erreur suivante après sumbit est générée:Attempt to update field Serial No failed: field_sql_storage cannot change the schema for an existing field with data..
Ek Kosmos
Concernant l’engagement de la question drupal, allez-y, faites-le.
Ek Kosmos
1
Je ne pouvais pas faire fonctionner ça. Après avoir commenté cette ligne, j'ai toujours une erreur MYSQL qui ALTER TABLE a échoué.
Jchwebdev
Si vous obtenez un, FieldUpdateForbiddenException: cannot change the schema for an existing field with datavous devez également commenter L282 modules/field/modules/field_sql_storage/field_sql_storage.module.
mardi
Le commentaire de @ dieuwe est faux. Ce fichier n'existe pas dans les versions récentes de D8 (si cela a déjà été le cas). Vous devez commenter les deux lignes de core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.phpcette exception avec le texte "Le stockage SQL ne peut pas changer le schéma d'un champ existant". À propos des lignes 1312 et 1403.
Dalin
6

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 les paramètres du champ Drupal.

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

Les 3 choses qui doivent arriver:

  1. Changez la longueur de VARCHAR de la colonne de valeur dans la table field_data_ {fieldname}
  2. Changez la longueur de VARCHAR de la colonne de valeur dans la table field_revision_ {fieldname}
  3. Mettez à jour la configuration du champ pour refléter le nouveau paramètre de longueur maximale La fonction suivante effectue ces 3 étapes et prend 2 paramètres simples, notamment 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 apporter 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
    );
  }
}
Kenorb
la source
1
Nous avons utilisé cette méthode drupal 8 sur un projet et drush updb --entity-updatesnous avons rencontré des problèmes: lorsque vous exécutiez les champs que nous avons gérés via cette fonction, ils étaient marqués comme nécessitant une mise à jour. Il essaierait alors de mettre à jour le schéma de champ à nouveau dans mysql. Pour nous, cela échouerait car il y avait déjà des données de terrain. Cela empêchait l'exécution d'autres tâches de mise à jour.
leon.nk
En résumé, il est probablement plus sûr de créer de nouveaux champs et de migrer des données.
leon.nk
3

Essayez ceci ... cela mettra à jour le type de données de champ de TEXT à LONG_TEXT et mettra à jour la max_lengthlongueur de texte allant de 4000 à la longueur maximale ... espérons 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);    
  }
}
Harold
la source
3

D8

  1. Mettez en commentaire les deux lignes de core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchem‌​a.phpcette exception 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 "Stockage sur le terrain" et choisissez le champ en question. Copiez la configuration.
  3. Accédez à /admin/config/development/configuration/single/import. . Le type de configuration est "Stockage sur le terrain". Collez la configuration. Changer la longueur.
  4. Soumettez le formulaire.

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

Dalin
la source
Cela a fonctionné comme un charme. Depuis Drupal 8.5.3, les lignes sont 1505-1507 dans la fonction protégée updateDedicatedTableSchema et 1596-1598 dans la fonction protégée updateSharedTableSchema. Assurez-vous de changer quand c'est fait! Je vous remercie.
HongPong
J'ai d'abord essayé cette approche. J'essaie de modifier un champ de paragraphe. Cela fonctionne, mais il est quand même indispensable de modifier les tables correspondantes.
Yaazkal
@Yaazkal Hmmm, ce n'était pas mon expérience. Essayez-vous d'allonger ou de raccourcir le champ?
Dalin
@Dalin s'allonge, de 255 à 510. Utilisation de D 8.5.5 et des paragraphes 1.3
Yaazkal le
1

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

  1. "field_data_field_lorem": changé "field_lorem_value" en "longtext"
  2. "field_config": changé de "type" en "text_long"
Jill
la source
L'avez-vous soumis comme correctif à D7? Si tel est vraiment le problème, vous devriez lui envoyer un correctif pour résoudre ce problème dans le code principal.
Patrick
J'ai changé ma valeur de taille de champ de phpmyadmin (de 10 à 25 de type VARCHAR), et j'ai actualisé le cache, mais cela ne fonctionne pas. Dans la base de données VARCHAR (25) contenue dans la base de données, mais dans Drupal, le champ a la même valeur de taille maximale qu'avant 10. Peut-être existe-t-il un paramètre de champ masqué?
Ek Kosmos