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.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

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
StatusFileSize
new1.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

StatusFileSize
new1.48 KB

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

feng-shui’s picture

StatusFileSize
new1.14 KB

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

feng-shui’s picture

StatusFileSize
new1.14 KB

Fix PHP notice with previous patch.

vistree’s picture

@feng-shui,
should your patch still work for Drupal 10.4 and filefield_paths 8.x-1.0-beta8?
The patch still applies - but it seems to be ignored on my media migrations.
I tried to debug and it seems that function filefield_paths_entity_update() from filefield_paths.module is not called?!

rudolfbyker made their first commit to this issue’s fork.

rudolfbyker’s picture

StatusFileSize
new665 bytes

Re-rolled the patch for 1.0-rc1

rudolfbyker’s picture

Status: Needs work » Needs review

Opened a merge request to solve this properly. Please review :)

rudolfbyker’s picture

The tests seem to pass for the current and previous major versions of Drupal. They did not run for the "next major version", because composer install failed, which is not within the scope of this issue to fix.

liam morland’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

deciphered changed the visibility of the branch 2072237-disable to hidden.

deciphered’s picture

Status: Needs work » Needs review
StatusFileSize
new46.03 KB

Implemented a hybrid of the two approaches already on this issue, plus the older idea from comment #9, rather than picking one.

Three levels of control now exist:

  • Site-wide: a new "Enable File (Field) Paths" checkbox on the module's settings form, backed by a new enabled key in filefield_paths.settings config (same idea as MR !62, rebased onto current 8.x-1.x). Shows a status report warning if left disabled, so it doesn't get forgotten about.
  • Per field: unchanged, the existing checkbox on each field's settings form.
  • Per save, transient: a new filefield_paths_settings property on the entity, read once per save and merged into the settings passed to hook_filefield_paths_process_file(). Never persisted, so no config save and no cache invalidation.

Examples of the per-save override:

// Suppress every file field on this entity for this save only.
$entity->filefield_paths_settings = ['enabled' => FALSE];

// Suppress just one field, leaving others on the entity untouched.
$entity->filefield_paths_settings = ['field_image' => ['enabled' => FALSE]];

// Override any other settings key the same way, not just 'enabled'.
$entity->filefield_paths_settings = ['redirect' => FALSE];

This generalises comment #9's $entity->fielfield_paths_override_settings idea rather than the per-field-item-value approach from the more recent patch, since it doesn't require touching every field separately to disable more than one.

MR: !70. Patch also attached for anyone who prefers to review/test that way.

Credit to jose reyero, geek-merlin, nwom, herved, hussainweb, trebormc and feng-shui for the patches this builds on, and to rudolfbyker for the two recent attempts.