It would be nice if I could put a flag in a file object that would prevent filefield paths from altering the path.

This is needed when porting data that already has a predefined path and I dont want filefield paths to touch it.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Deciphered’s picture

Two simple solutions (IMO):

  1. Before you programatically import the data, stick a module_disable(array('filefield_paths'));, and a module_enable(array('filefield_paths')) at the end.
  2. Similarly, before and after each node/entity_save() programatically change the settings for filefield_paths() in the field instance settings in question.

Not the greatest options, but doable. I'm sure there's even easier solutions, but I'm not putting much thought into it right at this second.

With that said, I think it's a valid request, and I will try to look at it in the near future. Patches welcome of course.

Cheers,
Deciphered.

Deciphered’s picture

Issue summary: View changes
Priority: Normal » Minor
Status: Active » Postponed

I may still consider this after the 1.0 release, but it's very low priority.

emi_bcn’s picture

Title: Add option to disable filefeild paths when programmatically saving a node » Add option to disable filefield paths when programmatically saving a node

Hi there,
I'm creating programmatically lots of nodes from a migration. I would like FilePaths to work correctly, but to disable _filefield_paths_replace_path on node content. I mean, I need FileField to generate the final alias for the files, but I will be doing preg_replace on content on a later phase of the migration. Any simple solution (IMO) for this? Is it acceptable the petition?

Thanks a lot for the great work you do here!!
emi

jonhattan’s picture

Version: 7.x-1.x-dev » 8.x-1.x-dev
Status: Postponed » Active

Alternatives exposed in #1 are valid ones for Drupal 7. Even in Drupal 8 I managed to temporarily disable the filefield_path config while migrations are running. FYI I used this snippet:

/**
 * Implements drush_HOOK_pre_COMMAND().
 *
 * Disable filefield_paths of affected fields before running migrations.
 */
function drush_migrate_hco_pre_migrate_import($migration_names) {
  if (!is_array($migration_names)) {
    $migration_names = [$migration_names];
  }
  if (in_array('hco_media__media_entity_files', $migration_names)) {
    $field_config = \Drupal\field\Entity\FieldConfig::loadByName('media', 'image', 'field_media_image');
    $field_config->setThirdPartySetting('filefield_paths', 'enabled', FALSE);
    $field_config->save();
  }
}

/**
 * Implements drush_HOOK_post_COMMAND().
 *
 * Re-enable filefield_paths of affected fields after running migrations.
 */
function drush_migrate_hco_post_migrate_import($migration_names) {
  if (!is_array($migration_names)) {
    $migration_names = [$migration_names];
  }
  if (in_array('hco_media__media_entity_files', $migration_names)) {
    $field_config = \Drupal\field\Entity\FieldConfig::loadByName('media', 'image', 'field_media_image');
    $field_config->setThirdPartySetting('filefield_paths', 'enabled', TRUE);
    $field_config->save();
  }
}

Problem is that updating a field config this way invalidates this cache tags: token_info, config:field.field.media.image.field_media_image, entity_field_info, media_view, views_data....

Those tags are generic enough to purge caches of almost all site pages. In our case, because the way we use migrations, we're purging caches at a high frecuency on a daily basis.

jonhattan’s picture

Ok, there's another way to do this: alter the settings after loading the config entity, by implementing hook_field_config_load(). This requires a module, and is trickier to check if a migration is running.


/**
 * Implements hook_ENTITY_TYPE_load().
 *
 * Disable filefield_paths on media.image.field_media_image when running migrations.
 */
function MODULENAME_field_config_load(&$entities) {
  if (function_exists('drush_main')) {
    $command = drush_get_command();
    if ($command['command'] == 'migrate-import') {
      if (!empty($entities['media.image.field_media_image'])) {
        $entities['media.image.field_media_image']
          ->setThirdPartySetting('filefield_paths', 'enabled', FALSE);
      }
    }
  }
}

Jose Reyero’s picture

Status: Active » Needs review
FileSize
1.76 KB

Here's a patch, an ugly workaround, yes, but...

geek-merlin’s picture

I think it's not that ugly and the code is nice and straightforward. I'd give green lights.

NWOM’s picture

A port of #6 to D7 would be great as well for those of us on D7.

geek-merlin’s picture

Status: Needs review » Needs work
+++ b/docroot/modules/contrib/filefield_paths/filefield_paths.module
@@ -344,16 +344,25 @@ function filefield_paths_entity_insert(EntityInterface $entity) {
+    // Check for temporary settings overrides in this entity.
+    $override_settings = isset($entity->fielfield_paths_override_settings) ? $entity->fielfield_paths_override_settings : array();
...
-          $settings = $definition->getThirdPartySettings('filefield_paths');
+          $settings = $override_settings + $definition->getThirdPartySettings('filefield_paths');
           if (isset($settings['enabled']) && $settings['enabled']) {

Hmm, if $entity->fielfield_paths_override_settings is NOT an array, this will give hard to track results. We should check for that and throw something meaningfurl (imho preferred) or silently ignore.

herved’s picture

Hello,

Here is a D7 version.

mrgoodfellow’s picture

Hey guys! I'm needing the same functionality only I would like to simply alter the way the file is re-written ONLY and not effect any other options.

In my configuration I have: [file:ffp-name-only-original][random:hash:crc32].[file:ffp-extension-original]
which adds a random hash to my file name.

essentially I would like to create a hook that will redefine this value to:

$form['instance']['settings']['filefield_paths']['file_name']['value'] = '[file:ffp-name-only-original].[file:ffp-extension-original]';

currently my function looks like:

This would remove the random hash on published files but allow it to remain on drafted files.

function MYMODULE_workbench_moderation_transition($node, $old_state, $new_state) {
if ($node->type == 'document' && $new_state == "published") {
$form['instance']['settings']['filefield_paths']['file_name']['value'] = '[file:ffp-name-only-original].[file:ffp-extension-original]';
}

When I use this function I get an error Is there a better way to accomplish this in MYMODULE?
Basically I want to modify the way the file name is re-written, not disable the functionality of the module completely.

hussainweb’s picture

The code snippets in comments #4 and #5 don't work anymore (Drupal 8.6, Drush 9.4). I adapted the code in an event subscriber instead. Here's the snippet:

<?php

namespace Drupal\zi_migrate_support\EventSubscriber;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\migrate\Event\MigrateEvents;
use Drupal\migrate\Event\MigrateImportEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Class MigrateSubscriber.
 */
class MigrateSubscriber implements EventSubscriberInterface {

  protected $entityTypeManager;
  protected $fieldConfigStorage;

  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
    $this->fieldConfigStorage = $entity_type_manager->getStorage('field_config');
  }

  public function preImport(MigrateImportEvent $event) {
    $this->setFilefieldPathsStatus('node.article.field_photos', FALSE);
    $this->setFilefieldPathsStatus('node.article.field_videos', FALSE);
    $this->setFilefieldPathsStatus('node.announcement.field_image', FALSE);
    $this->setGeocodeStatus('node.article.field_location_coordinates', FALSE);
  }

  public function postImport(MigrateImportEvent $event) {
    $this->setFilefieldPathsStatus('node.article.field_photos', TRUE);
    $this->setFilefieldPathsStatus('node.article.field_videos', TRUE);
    $this->setFilefieldPathsStatus('node.announcement.field_image', TRUE);
    $this->setGeocodeStatus('node.article.field_location_coordinates', TRUE);
  }

  protected function setFilefieldPathsStatus($field_name, $enabled) {
    $field_config = $this->fieldConfigStorage->load($field_name);
    $field_config->setThirdPartySetting('filefield_paths', 'enabled', $enabled);
    $field_config->save();
  }

  protected function setGeocodeStatus($field_name, $enabled) {
    $field_config = $this->fieldConfigStorage->load($field_name);
    $field_config->setThirdPartySetting('geocoder_field', 'method', $enabled ? 'source' : 'none');
    $field_config->save();
  }

  public static function getSubscribedEvents() {
    $events = [];
    $events[MigrateEvents::PRE_IMPORT][] = ['preImport'];
    $events[MigrateEvents::POST_IMPORT][] = ['postImport'];

    return $events;
  }


}

The code should be self explanatory. It's a little beyond scope of this issue but this also shows how to disable geocoding during migrations.

To register the event subscribed, here is the snippet from the services.yml file.

services:
  zi_migrate_support.migrate_event_subscriber:
    class: Drupal\zi_migrate_support\EventSubscriber\MigrateSubscriber
    arguments: ['@entity_type.manager']
    tags:
      - { name: event_subscriber }
trebormc’s picture

I created a patch similar to # 6. Thanks @Jose

Now for each field in the migration you can overwrite. For example:

  #disable filefield_paths_settings for this field
  'field_media_image/filefield_paths_settings/enabled':
    plugin: default_value
    default_value: FALSE
ultimike’s picture

@hussainweb's code above in #12 is +1!

Saved me a bunch of time - thank you!

-mike

Feng-Shui’s picture

Re-roll of #13 against 8.x-1.x.

Feng-Shui’s picture

Updated to apply against 8.x-1.x again.

Feng-Shui’s picture

Fix PHP notice with previous patch.