Skip to content

feat(#2072237): allow disabling File (Field) Paths processing site-wide and per entity#8

Open
Decipher wants to merge 1 commit into
8.x-1.xfrom
feature/2072237-disable
Open

feat(#2072237): allow disabling File (Field) Paths processing site-wide and per entity#8
Decipher wants to merge 1 commit into
8.x-1.xfrom
feature/2072237-disable

Conversation

@Decipher

@Decipher Decipher commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Summary

Adds three independent ways to suppress File (Field) Paths processing, addressing
#2072237 ("Add option to
disable filefield paths when programmatically saving a node"), open since 2013:

  1. Global toggle -- a new enabled setting on the module's settings form, persisted in
    filefield_paths.settings:enabled.
  2. Per-field toggle -- unchanged, already existed on each field's instance settings form.
  3. Entity-level transient override -- a new filefield_paths_settings runtime property on
    the entity, read once per save and merged into the settings passed to
    hook_filefield_paths_process_file(). Never persisted (a plain non-field entity property), so
    it only affects the single save it's set on -- no config save, no cache invalidation.

Closes #2072237

Background

The issue's 13-year comment thread contains many shaped attempts at a per-save override, none
committed, plus two recent unmerged attempts by the same contributor: an uploaded patch file
(per-field-item-value override, read at delta 0 only) and
MR !62 (a global config
toggle, currently conflicting against 8.x-1.x). Mapping the real migration scenarios this issue
is meant to solve (disable one field across thousands of nodes, disable everything on one node,
disable the whole module temporarily, or some mixture) showed a single mechanism wasn't enough.

The entity-level override's shape generalizes an older idea from the thread
($entity->fielfield_paths_override_settings, a single property merged into the field's settings)
rather than the unmerged per-field-item-value patch:

$entity->filefield_paths_settings = ['enabled' => FALSE]; // every file field, this save
$entity->filefield_paths_settings = ['field_image' => ['enabled' => FALSE]]; // just this field
$entity->filefield_paths_settings = ['redirect' => FALSE]; // still move files, skip redirects

A field-name key scopes the override to that field and takes precedence; any other key applies to
every field. The enabled key is still checked inside the existing
FieldItem::hasConfigurationEnabled() gate, so the override can only suppress processing that's
already enabled at the field-config level, never enable it on an unconfigured field.

Credit to jose reyero, geek-merlin, nwom, herved, hussainweb, trebormc, and feng-shui for the
years of patches and workarounds this design draws on, and to rudolfbyker (dolf) for the two
recent attempts that prompted re-examining the whole thread. MR !62 remains open separately; it
solves a narrower problem (global switch only) and still has its own merge conflicts, so it isn't
superseded by this PR.

Changes

File Type Purpose
src/Hook/EntityWithFileField.php Modified Global toggle check, entity-level override merge
src/Form/SettingsForm.php Modified enabled checkbox
config/schema/filefield_paths.schema.yml, config/install/filefield_paths.settings.yml Modified enabled config key
filefield_paths.install Modified filefield_paths_update_9002(), requirements warning when disabled site-wide
tests/src/Unit/EntityWithFileFieldTest.php Modified Unit coverage: non-content entity skip, global toggle off, no-override regression guard
tests/src/Kernel/EntityWithFileFieldOverrideTest.php New Kernel coverage for the entity-level override against real entities (no override, whole-entity, field-specific, field-specific precedence)
tests/src/Kernel/InstallFunctionsTest.php Modified Requirements warning on/off/unset, update hook behavior
tests/src/Kernel/SettingsFormTest.php Modified New enabled checkbox default and persistence
filefield_paths.api.php, README.md Modified Documentation for all three tiers
phpstan.neon Modified Scoped ignore for a PHPStan false positive (its Drupal extension assumes every property on a ContentEntityInterface is a field access)

Test plan

  • DRUPAL_VERSION=10 make test-unit -- 35/35 pass
  • DRUPAL_VERSION=10 make test-kernel -- 79/79 pass (2 pre-existing skips, unrelated)
  • DRUPAL_VERSION=10 make lint -- PHPCS and PHPStan clean. Rector flags missing
    #[\Override] attributes on 5 files including src/Form/SettingsForm.php; confirmed via
    git stash against the clean 8.x-1.x checkout that this is pre-existing tech debt, not
    introduced by this PR, so left untouched as out of scope.
  • Manual: file field with FFP enabled, set $entity->filefield_paths_settings before save,
    confirm the file is not moved; disable the global toggle and confirm
    /admin/reports/status warns and no field is processed site-wide until re-enabled

Summary by CodeRabbit

  • New Features
    • Added a site-wide Enabled toggle to globally enable/disable File (Field) Paths processing.
    • Added three-level control: module-wide, per-field, and per-save overrides (with clear precedence).
  • Configuration
    • Introduced a new boolean enabled setting (defaulting to true when unset).
  • Documentation
    • Updated README with an FAQ and expanded API guidance on disabling behavior at each level.
  • Bug Fixes / Behavior Changes
    • Upload destination staging and processing now respect the global Enabled setting.
  • Tests
    • Added/updated kernel and unit coverage for the enable/disable and override precedence rules.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 961ff8ec-8978-43ca-b393-4b64b4949161

📥 Commits

Reviewing files that changed from the base of the PR and between 1d1831c and 9d5a84c.

📒 Files selected for processing (14)
  • README.md
  • config/install/filefield_paths.settings.yml
  • config/schema/filefield_paths.schema.yml
  • filefield_paths.api.php
  • filefield_paths.install
  • phpstan.neon
  • src/Form/SettingsForm.php
  • src/Hook/EntityWithFileField.php
  • src/Hook/FieldWidgetSingleElementForm.php
  • tests/src/Kernel/EntityWithFileFieldOverrideTest.php
  • tests/src/Kernel/InstallFunctionsTest.php
  • tests/src/Kernel/SettingsFormTest.php
  • tests/src/Unit/EntityWithFileFieldTest.php
  • tests/src/Unit/FieldWidgetSingleElementFormTest.php
✅ Files skipped from review due to trivial changes (3)
  • filefield_paths.api.php
  • README.md
  • phpstan.neon
🚧 Files skipped from review as they are similar to previous changes (11)
  • config/schema/filefield_paths.schema.yml
  • src/Hook/FieldWidgetSingleElementForm.php
  • config/install/filefield_paths.settings.yml
  • tests/src/Kernel/InstallFunctionsTest.php
  • src/Form/SettingsForm.php
  • filefield_paths.install
  • tests/src/Kernel/SettingsFormTest.php
  • src/Hook/EntityWithFileField.php
  • tests/src/Unit/EntityWithFileFieldTest.php
  • tests/src/Kernel/EntityWithFileFieldOverrideTest.php
  • tests/src/Unit/FieldWidgetSingleElementFormTest.php

📝 Walkthrough

Walkthrough

Adds a site-wide enabled boolean toggle to the filefield_paths module configuration. The flag is exposed in the settings form, checked in EntityWithFileField::handleProcessFile() and FieldWidgetSingleElementForm::formAlter(), and surfaced as a requirements warning when FALSE. A transient per-entity/per-field filefield_paths_settings runtime override mechanism is also introduced. An update hook migrates existing installations.

Changes

Site-wide enabled toggle and per-entity override support

Layer / File(s) Summary
Config schema and install defaults
config/schema/filefield_paths.schema.yml, config/install/filefield_paths.settings.yml
Adds filefield_paths.settings.enabled as a boolean schema field and sets its install default to true.
Settings form enabled checkbox
src/Form/SettingsForm.php, tests/src/Kernel/SettingsFormTest.php
buildForm() adds an enabled checkbox defaulting to TRUE from config; submitForm() persists it. #[\Override] added to all overridden methods. Tests verify default is TRUE and that FALSE persists correctly.
EntityWithFileField hook with global and per-entity override
src/Hook/EntityWithFileField.php, phpstan.neon, tests/src/Unit/EntityWithFileFieldTest.php, tests/src/Kernel/EntityWithFileFieldOverrideTest.php
Injects a config factory closure, adds getSettings(), and rewrites handleProcessFile() to gate on the global flag, read entity-level filefield_paths_settings overrides, flatten and merge per-field configurations with precedence, and skip disabled fields. PHPStan suppression added for the dynamic-property type mismatch. Unit tests cover globally-enabled and globally-disabled behavior; kernel tests assert five override scenarios: no override processes, non-array ignored, whole-entity disable suppresses all, field-specific suppress suppresses one, field-specific re-enable overrides flat disable.
FieldWidgetSingleElementForm global enabled check
src/Hook/FieldWidgetSingleElementForm.php, tests/src/Unit/FieldWidgetSingleElementFormTest.php
Adds an early-return guard in formAlter() that skips upload-location staging when the site-wide enabled setting is falsy. Tests refactored to use a shared createHook() helper centralizing config mocking, and testGloballyDisabledIsUntouched() verifies upload-location is not set when globally disabled.
Install requirements and update hook
filefield_paths.install, tests/src/Kernel/InstallFunctionsTest.php
filefield_paths_requirements() adds a Warning requirement when enabled is explicitly FALSE. filefield_paths_update_9002() sets enabled to TRUE for existing installations where it is unset. Tests cover both requirement states and both update-hook branches.
API and README documentation
filefield_paths.api.php, README.md
api.php adds sec_disabling docblock covering three suppression granularities with precedence rules and examples. README reorganizes the Configuration section and adds a FAQ entry on disabling at field, site-wide, and per-save levels.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Hop, hop, enabled by default!
A toggle appears, no need to halt.
Per-field, per-site, or per-save day,
The rabbit decides which files may stay.
Config merges with a gentle grace,
Tests confirm each overriding case. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: adding site-wide and per-entity disable capabilities for File (Field) Paths processing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/2072237-disable

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Hook/EntityWithFileField.php`:
- Around line 58-62: The variable $override assigned from the untyped property
$entity->filefield_paths_settings may not be an array, which will cause
array_diff_key() to throw a TypeError. Add a type guard check using is_array()
on $override before calling array_diff_key($override, $fields) to ensure it
contains a valid array, and fall back to an empty array if the type check fails.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3a9fa764-277c-45ea-baf4-fd95b6901b7d

📥 Commits

Reviewing files that changed from the base of the PR and between 302c2c2 and 74bfaaf.

📒 Files selected for processing (12)
  • README.md
  • config/install/filefield_paths.settings.yml
  • config/schema/filefield_paths.schema.yml
  • filefield_paths.api.php
  • filefield_paths.install
  • phpstan.neon
  • src/Form/SettingsForm.php
  • src/Hook/EntityWithFileField.php
  • tests/src/Kernel/EntityWithFileFieldOverrideTest.php
  • tests/src/Kernel/InstallFunctionsTest.php
  • tests/src/Kernel/SettingsFormTest.php
  • tests/src/Unit/EntityWithFileFieldTest.php

Comment thread src/Hook/EntityWithFileField.php
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.37%. Comparing base (b1c6eac) to head (9d5a84c).

Additional details and impacted files
@@             Coverage Diff             @@
##           8.x-1.x       #8      +/-   ##
===========================================
+ Coverage    79.72%   80.37%   +0.64%     
===========================================
  Files           17       17              
  Lines          666      688      +22     
===========================================
+ Hits           531      553      +22     
  Misses         135      135              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Decipher
Decipher force-pushed the feature/2072237-disable branch 4 times, most recently from 8ccee2b to 7ed493c Compare June 22, 2026 05:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
filefield_paths.module (1)

151-163: ⚠️ Potential issue | 🟠 Major

Deprecation messages reference non-existent method.

The deprecation attribute and @trigger_error() both reference recommendedFileScheme(), which does not exist on MoveFileProcessorInterface. The implementation correctly calls recommendedTemporaryScheme() (the actual method defined in the interface). Update the deprecation message and attribute to reference the correct method name.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@filefield_paths.module` around lines 151 - 163, The deprecation messages in
both the #[\Deprecated()] attribute and the `@trigger_error`() call within the
filefield_paths_recommended_temporary_scheme() function incorrectly reference
recommendedFileScheme() as the replacement method, but this method does not
exist on MoveFileProcessorInterface. Update both deprecation messages to
correctly reference recommendedTemporaryScheme() instead, which is the actual
method being called in the function implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@filefield_paths.module`:
- Around line 151-163: The deprecation messages in both the #[\Deprecated()]
attribute and the `@trigger_error`() call within the
filefield_paths_recommended_temporary_scheme() function incorrectly reference
recommendedFileScheme() as the replacement method, but this method does not
exist on MoveFileProcessorInterface. Update both deprecation messages to
correctly reference recommendedTemporaryScheme() instead, which is the actual
method being called in the function implementation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 60ff2f2e-6d85-4003-8d51-924efda45fb9

📥 Commits

Reviewing files that changed from the base of the PR and between 74bfaaf and 7ed493c.

📒 Files selected for processing (18)
  • README.md
  • config/install/filefield_paths.settings.yml
  • config/schema/filefield_paths.schema.yml
  • filefield_paths.api.php
  • filefield_paths.install
  • filefield_paths.module
  • phpstan.neon
  • src/Form/SettingsForm.php
  • src/Hook/EntityWithFileField.php
  • src/Hook/FieldWidgetSingleElementForm.php
  • tests/modules/filefield_paths_test/src/StreamWrapper/FileFieldPathsDummyReadOnlyStreamWrapper.php
  • tests/src/Functional/FileFieldPathsTestBase.php
  • tests/src/Kernel/EntityWithFileFieldOverrideTest.php
  • tests/src/Kernel/InstallFunctionsTest.php
  • tests/src/Kernel/RedirectTest.php
  • tests/src/Kernel/SettingsFormTest.php
  • tests/src/Unit/EntityWithFileFieldTest.php
  • tests/src/Unit/FieldWidgetSingleElementFormTest.php
✅ Files skipped from review due to trivial changes (6)
  • filefield_paths.api.php
  • config/install/filefield_paths.settings.yml
  • config/schema/filefield_paths.schema.yml
  • README.md
  • tests/src/Kernel/RedirectTest.php
  • tests/modules/filefield_paths_test/src/StreamWrapper/FileFieldPathsDummyReadOnlyStreamWrapper.php
🚧 Files skipped from review as they are similar to previous changes (8)
  • phpstan.neon
  • tests/src/Kernel/SettingsFormTest.php
  • src/Form/SettingsForm.php
  • tests/src/Kernel/InstallFunctionsTest.php
  • filefield_paths.install
  • tests/src/Kernel/EntityWithFileFieldOverrideTest.php
  • tests/src/Unit/EntityWithFileFieldTest.php
  • src/Hook/EntityWithFileField.php

@Decipher
Decipher force-pushed the feature/2072237-disable branch 2 times, most recently from 0010b35 to 1d1831c Compare June 22, 2026 11:31
…de and per entity

Add a site-wide "enabled" setting (config + settings form) and a
transient `filefield_paths_settings` entity property so migrations and
other programmatic saves can suppress or override processing for a
single save without touching field configuration. Includes an update
hook to default existing sites to enabled and a runtime requirements
warning when disabled site-wide.

Issue #2072237 by jose reyero, herved, trebormc, feng-shui, rudolfbyker,
geek-merlin, vistree, deciphered.
@Decipher
Decipher force-pushed the feature/2072237-disable branch from 1d1831c to 9d5a84c Compare June 23, 2026 00:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant