Skip to content

feat(#3608361): pass field delta in token data for [file:delta] support#11

Open
Decipher wants to merge 1 commit into
8.x-1.xfrom
feature/3608361-field_delta
Open

feat(#3608361): pass field delta in token data for [file:delta] support#11
Decipher wants to merge 1 commit into
8.x-1.xfrom
feature/3608361-field_delta

Conversation

@Decipher

@Decipher Decipher commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Problem

The [file:delta] token (added in Field Tokens 2.0.x, #2386655) returns the zero-based position of a file within a multi-value field. However, File (Field) Paths iterates over files using ->referencedEntities() which discards position information, so [file:delta] always resolves to empty.

Changes

  • Replace referencedEntities() loop with direct field item iteration to expose the delta index
  • Pass 'delta' => in token data
  • Add instanceof File guard for safety
  • Add functional test with multi-value file field

Related

Summary by CodeRabbit

  • New Features

    • Added per-item file:delta token support for multi-value file upload path generation, assigning each uploaded file a deterministic zero-based delta suffix.
  • Bug Fixes

    • Improved file field path processing to only act on valid file entities and to skip items referencing missing files.
    • Ensured token replacement for filename patterns uses the correct delta per uploaded item.
  • Tests

    • Added functional coverage for file:delta on unlimited-cardinality multivalue fields.
    • Added token support for tests and updated multiple test suites to run in separate processes.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

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: 58dfdce1-bdcd-4f64-9ad3-64669d72009e

📥 Commits

Reviewing files that changed from the base of the PR and between 9fdaf10 and f14a625.

📒 Files selected for processing (21)
  • src/Hook/FieldConfigEditForm.php
  • src/Hook/FileFieldPathsProcessFileLegacy.php
  • src/Utility/FieldConfigEditFormHandler.php
  • tests/modules/filefield_paths_test/filefield_paths_test.module
  • tests/src/Functional/FileFieldPathsDrushCommandTest.php
  • tests/src/Functional/FileFieldPathsGeneralTest.php
  • tests/src/Functional/FileFieldPathsPathautoTest.php
  • tests/src/Functional/FileFieldPathsRedirectTest.php
  • tests/src/Functional/FileFieldPathsTokensTest.php
  • tests/src/Functional/FileFieldPathsTransliterationTest.php
  • tests/src/Functional/FileFieldPathsUpdateTest.php
  • tests/src/Kernel/BatchUpdaterTest.php
  • tests/src/Kernel/DrushCommandsTest.php
  • tests/src/Kernel/FieldConfigEditFormTest.php
  • tests/src/Kernel/FileFieldPathsProcessFileLegacyTest.php
  • tests/src/Kernel/InstallFunctionsTest.php
  • tests/src/Kernel/ModuleDeprecatedWrappersTest.php
  • tests/src/Kernel/ModuleLegacyHooksTest.php
  • tests/src/Kernel/PathProcessorTest.php
  • tests/src/Kernel/RedirectTest.php
  • tests/src/Kernel/SettingsFormTest.php
✅ Files skipped from review due to trivial changes (3)
  • tests/src/Kernel/ModuleDeprecatedWrappersTest.php
  • tests/src/Kernel/FileFieldPathsProcessFileLegacyTest.php
  • tests/src/Kernel/BatchUpdaterTest.php
🚧 Files skipped from review as they are similar to previous changes (18)
  • src/Utility/FieldConfigEditFormHandler.php
  • tests/src/Kernel/DrushCommandsTest.php
  • tests/src/Kernel/PathProcessorTest.php
  • tests/src/Functional/FileFieldPathsPathautoTest.php
  • tests/modules/filefield_paths_test/filefield_paths_test.module
  • tests/src/Functional/FileFieldPathsUpdateTest.php
  • tests/src/Kernel/SettingsFormTest.php
  • tests/src/Functional/FileFieldPathsDrushCommandTest.php
  • tests/src/Kernel/FieldConfigEditFormTest.php
  • tests/src/Functional/FileFieldPathsTokensTest.php
  • tests/src/Kernel/ModuleLegacyHooksTest.php
  • tests/src/Kernel/InstallFunctionsTest.php
  • tests/src/Functional/FileFieldPathsRedirectTest.php
  • tests/src/Functional/FileFieldPathsGeneralTest.php
  • tests/src/Functional/FileFieldPathsTransliterationTest.php
  • src/Hook/FileFieldPathsProcessFileLegacy.php
  • tests/src/Kernel/RedirectTest.php
  • src/Hook/FieldConfigEditForm.php

📝 Walkthrough

Walkthrough

The legacy file field path processor now iterates field items by delta, adds delta to token data, and skips non-file entities. Test support adds a file:delta token, verifies delta-based filenames, updates multiple test classes to run in separate processes, and rewrites a few guards into explicit boolean checks.

Changes

File Delta Token Support

Layer / File(s) Summary
Delta-aware file processing
src/Hook/FileFieldPathsProcessFileLegacy.php
The legacy processor now walks field items by delta, skips non-file entities, passes delta into token data, and rewrites the destination/missing-file early-continue check.
Delta token test support
tests/modules/filefield_paths_test/filefield_paths_test.module
The test support module registers a file:delta token and returns the delta replacement value when token lookup receives file data.
Delta filename coverage
tests/src/Functional/FileFieldPathsGeneralTest.php
The functional test adds coverage for an unlimited multivalue file field that renders uploaded filenames with zero-based delta suffixes.
Legacy skip coverage
tests/src/Kernel/FileFieldPathsProcessFileLegacyTest.php
The kernel legacy processor test adds a case that invokes fileFieldPathsProcessFile() with a missing file reference and asserts it completes without errors.

Separate-process Test Attributes

Layer / File(s) Summary
Functional test attributes
tests/src/Functional/*
Functional test classes add the PHPUnit separate-process attribute, with one class replacing the prior docblock annotation and others adding the attribute alongside existing metadata.
Kernel test attributes
tests/src/Kernel/*
Kernel test classes add the PHPUnit separate-process attribute to class declarations while keeping existing group metadata and test logic unchanged.

Explicit Guard Conditions

Layer / File(s) Summary
Explicit hook guards
src/Hook/FieldConfigEditForm.php
FieldConfigEditForm::formAlter() rewrites the unsupported-class guard and the settings-field form guard into explicit boolean expressions with the same control flow.
Explicit submit guard
src/Utility/FieldConfigEditFormHandler.php
FieldConfigEditFormHandler::submit() rewrites the retroactive-update early return into an explicit disjunction of negated conditions.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • Decipher/filefield_paths#7: Related legacy FileFieldPathsProcessFileLegacy test coverage and kernel behavior around the same processing path.
  • Decipher/filefield_paths#10: Related PHPUnit metadata migration across the test suite, including class-level separate-process attributes.
🚥 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 clearly matches the main change: passing field delta into token data to support [file:delta].
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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/3608361-field_delta

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.

🧹 Nitpick comments (1)
src/Hook/FileFieldPathsProcessFileLegacy.php (1)

16-16: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider checking against FileInterface instead of the concrete File class.

The new guard is functionally correct, but binding to the concrete Drupal\file\Entity\File class instead of Drupal\file\FileInterface is slightly less robust if a site swaps in a custom bundle class for the file entity type that doesn't extend File (though it would still implement FileInterface). Since this pattern is already used elsewhere in the file (e.g. the @var \Drupal\file\Entity\File $original_file docblock), this is a minor stylistic nit rather than a functional issue.

♻️ Optional refactor to check against the interface
-use Drupal\file\Entity\File;
+use Drupal\file\FileInterface;
...
-      $file = $field_item->entity;
-      if (!$file instanceof File) {
+      $file = $field_item->entity;
+      if (!$file instanceof FileInterface) {
         continue;
       }

Also applies to: 65-69

🤖 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 `@src/Hook/FileFieldPathsProcessFileLegacy.php` at line 16, The new file-type
guard is too tightly coupled to the concrete Drupal\file\Entity\File class;
switch the type check in FileFieldPathsProcessFileLegacy to use
Drupal\file\FileInterface instead. Update the relevant instanceof guard(s) in
this hook so they accept any file entity implementation, while leaving the
existing behavior unchanged. Refer to the FileFieldPathsProcessFileLegacy logic
and its current File import when making the replacement.
🤖 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.

Nitpick comments:
In `@src/Hook/FileFieldPathsProcessFileLegacy.php`:
- Line 16: The new file-type guard is too tightly coupled to the concrete
Drupal\file\Entity\File class; switch the type check in
FileFieldPathsProcessFileLegacy to use Drupal\file\FileInterface instead. Update
the relevant instanceof guard(s) in this hook so they accept any file entity
implementation, while leaving the existing behavior unchanged. Refer to the
FileFieldPathsProcessFileLegacy logic and its current File import when making
the replacement.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a5b77aa-d681-4303-9b33-fa13b34fdc1a

📥 Commits

Reviewing files that changed from the base of the PR and between b1c6eac and 79614db.

📒 Files selected for processing (3)
  • src/Hook/FileFieldPathsProcessFileLegacy.php
  • tests/modules/filefield_paths_test/filefield_paths_test.module
  • tests/src/Functional/FileFieldPathsGeneralTest.php

@codecov

codecov Bot commented Jul 4, 2026

Copy link
Copy Markdown

Codecov Report

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

Additional details and impacted files
@@             Coverage Diff             @@
##           8.x-1.x      #11      +/-   ##
===========================================
+ Coverage    79.72%   79.85%   +0.12%     
===========================================
  Files           17       17              
  Lines          666      670       +4     
===========================================
+ Hits           531      535       +4     
  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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@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.

🧹 Nitpick comments (1)
src/Hook/FieldConfigEditForm.php (1)

60-63: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add explicit parentheses for clarity.

The condition relies on && binding tighter than || (!class_exists($class) || ($class !== FileFieldItemList::class && !is_subclass_of(...))). Logic checks out against the test case for unsupported classes, but the implicit precedence is easy to misread as a bug at a glance.

♻️ Suggested clarification
-    if (!class_exists($class) || $class !== FileFieldItemList::class && !is_subclass_of($class, FileFieldItemList::class)) {
+    if (!class_exists($class) || ($class !== FileFieldItemList::class && !is_subclass_of($class, FileFieldItemList::class))) {
🤖 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 `@src/Hook/FieldConfigEditForm.php` around lines 60 - 63, The conditional in
FieldConfigEditForm’s class check is correct but hard to read because it relies
on implicit operator precedence. Update the if statement to use explicit
parentheses around the FileFieldItemList class comparison and is_subclass_of
check so the intended grouping is obvious when reading or reviewing the
Hook/FieldConfigEditForm logic.
🤖 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.

Nitpick comments:
In `@src/Hook/FieldConfigEditForm.php`:
- Around line 60-63: The conditional in FieldConfigEditForm’s class check is
correct but hard to read because it relies on implicit operator precedence.
Update the if statement to use explicit parentheses around the FileFieldItemList
class comparison and is_subclass_of check so the intended grouping is obvious
when reading or reviewing the Hook/FieldConfigEditForm logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6553f0c7-ca16-4440-8d2b-2a32d70f7704

📥 Commits

Reviewing files that changed from the base of the PR and between 0a9d613 and 9fdaf10.

📒 Files selected for processing (3)
  • src/Hook/FieldConfigEditForm.php
  • src/Hook/FileFieldPathsProcessFileLegacy.php
  • src/Utility/FieldConfigEditFormHandler.php
✅ Files skipped from review due to trivial changes (1)
  • src/Utility/FieldConfigEditFormHandler.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Hook/FileFieldPathsProcessFileLegacy.php

@Decipher
Decipher force-pushed the feature/3608361-field_delta branch from 9fdaf10 to f14a625 Compare July 6, 2026 04:41
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