4

In an entity type, I need to replace a field by another with a more complexe behavior. This new behavior can reproduce the old field and add new. Like this behavior have an impact on the design, I need to update all entities with this new field to keep the data of the old field before delete it.

This import is done with a hook update. My problem is, in my hook_update is executed before I import my configuration. But I can't migrate my data in my new field like it doesn't exist yet. So, my question is, what's the best practice to do that:

  • Should I create programmatically my new field on my entity type in a hook_update and migrate my datas in the new field before import my configuration. This possibility allow me to delete the old field with configuration and everything will be over. But, if I create my field programmatically, I can do some errors or difference between what I have in my configuration. And, additionally, I want be lazy and don't reproduce a code which exist elsewhere. It's a little problem and I see I can improve this workflow.
  • Can I import configurations which concern only (and only that) the new field, do my migration of datas and import the rest of my configuration as usually? This seems be the best practice but I don't know if it's possible.
  • An other solution?

I thought about import all configurations before do the hook_update but this solution seems the worst thing to do: I can have update of contrib modules in my release and configurations could be apply only after these updates (I never met this case, but it's could be possible). Additionally, I will keep my old field until the next deploy.

I suppose my first solution is the only I can do but, maybe I don't thought about another.

5

I would recommend that you create the field programatically. In your update function. You could also create multiple update functions, just create the field in one, then migrate the data then remove the old field.

If you have a lot of data, then your update function should be done as a batch, so it doesn't run in any PHP timeouts or memory limits. In that case, having the update functions separate makes it easier to implement them.

To avoid duplicating code, you could read the config from the config sync storage and create it through the config entity storage, something like this:

$config_record = \Drupal::service('config.storage.sync')->read('field.storage....');
$storage = \Drupal::entityTypeManager()->getStorage($entity_type);
$entity = $storage->createFromStorageRecord($config_record);
$entity->save();

This is usually fine for custom update functions in projects because it will only be executed once. This approach is risky for core/contrib/reused modules (which usually import it from their default config) because you don't know when the update will be executed. Maybe you have to make another change to that config next week and add another update function to deal with that change, but if someone didn't execute the first yet, this initial update will already create the field based on the latest schema and then your update logic might get very confused about that.

  • Thanks for your response, I succeeded create my fields with configuration files. Just a precision if you don't use the default config directory "sync", you can do something like: global $config_directories; $file_storage = new \Drupal\Core\Config\FileStorage($config_directories['my-config-directory']); $field_storage = $file_storage ->read('field.storage....'); – Claire D Mar 16 '18 at 20:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.