Problem/Motivation

Part of #3221796: [META] Modernise file upload logic we identified that we are duplicating the code to find the file upload location in the following places:

  • \Drupal\file\Plugin\Field\FieldType\FileItem::getUploadLocation()
  • \Drupal\file\Plugin\rest\resource\FileUploadResource::getUploadLocation()
  • \Drupal\jsonapi\Controller\TemporaryJsonapiFileFieldUploader::getUploadLocation()

We can't really create a base class and use inheritance for this, as they use different methods of uploading files (ie. UploadedFile vs input stream).

Steps to reproduce

Proposed resolution

Add a trait that gets the upload destination from the field definition, and deprecate the duplication.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Issue fork drupal-3389688

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

kim.pepper created an issue. See original summary.

kim.pepper’s picture

Status: Active » Needs review

Looks like it's going to be problematic replacing the code in method \Drupal\file\Plugin\Field\FieldType\FileItem::doGetUploadLocation() with a trait because it is static.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs change record

For the new trait could we get a CR

kim.pepper’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record

Fixed merge conflicts and added a change record.

shweta__sharma’s picture

@kim.pepper Need to rebase the branch.
Thanks!

smustgrave’s picture

Status: Needs review » Needs work

For the rebase.

kim.pepper’s picture

Status: Needs work » Needs review

Merged with 11.x

prashant.c’s picture

The trait seem to be functioning well for the file fields. I was considering whether it might be sensible to maintain consistency in the function names within the trait as well. For instance, changing getFileUploadLocation to getUploadLocation(). Just a suggestion.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Thanks for fixing that @kim.pepper!

quietone’s picture

Status: Reviewed & tested by the community » Needs work

I'm triaging RTBC issues. I read the IS, the comments, the change record and the MR. I do like a bit of tidying up!

The question raised in #9 has not been answered. Why the name change? And how will this effect any contrib usages of getUploadLocation?

The change record also needs to be updated, it is referring to changes that have not been made. Also, the first sentence is difficult to read, and English is my first language. Also, instead of mentioning a usage in a contrib project it would be more helpful to explain what must be done in contrib to update modules for this change, such as a before and after example.

Setting to needs work for the above.

kim.pepper’s picture

Issue summary: View changes
Status: Needs work » Needs review
  • Rebased on 11.x
  • Renamed to getUploadLocation() as per the suggestion in #9
  • Updated the IS and CR
kim.pepper’s picture

I really wanted to replace \Drupal\file\Plugin\Field\FieldType\FileItem::getUploadLocation() with the trait but not sure how to work around deprecating a static method with a class method.

smustgrave’s picture

thoughts on handling that replacement in a follow up?

kim.pepper’s picture

smustgrave’s picture

Oh cool. Then in that case rest seems fine to me.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
kim.pepper’s picture

Status: Reviewed & tested by the community » Needs review

I thought I would have a go at replacing FileItem::doGetUploadLocation() with the trait method.

Unfortunately, generateSampleValue() calls it and is a static method, so we have to call the trait method statically too. I added a @phpstan-ignore-next-line but I'm not sure what the alternative is?

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new4.26 KB

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

kim.pepper’s picture

Title: Provide a trait to get file upload location from field settings » Add a service to get file upload location from field settings
Issue summary: View changes
Status: Needs work » Needs review

Updated IS

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Needs Review Queue Initiative

Reviewed the deprecation and link to CR appears correct https://www.drupal.org/node/3406099

Reviewing actual CR and all the details are there.

Believe this is good.

quietone’s picture

This is my second visit here for triage. I didn't find any unanswered questions or other work to do.

Leaving at RTBC;

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

I wonder if we don't have to add the service. Can we use the same approach as \Drupal\media_library\Form\FileUploadForm::createMediaFromValue and create a FileItem to do this.

Otherwise if we're going to go with the current approach I think we should be accepting a field definition object instead of settings and validating that it is a fiie item that we're generating a location for. Otherwise it's all a bit mushing random arrays together.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new90 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

kim.pepper’s picture

Status: Needs work » Needs review

#23 @alexpott I'd prefer to use a service, as we depend on 'token' and that has about 5 other dependencies.

I've changed \Drupal\file\Upload\UploadDestinationResolver::getUploadDestination() from accepting array $settings to FieldDefinitionInterface and I think that works better.

alexpott’s picture

I've looked at both this and \Drupal\file\Validation\FileValidatorSettingsTrait::getFileUploadValidators() and I think that they both should be / have been part of the file field API. If we put them on \Drupal\file\Plugin\Field\FieldType\FileFieldItemList then we'd be able to call this methods from the field definition we already have.

I don't think our API should be decided by the fact that our field system struggles with container injection (only because it was updated before the container was truly available in the D8 cycle). Both getFileUploadValidators() and getUploadDestination() are extremely intimate to the internals of the file field type.

kim.pepper’s picture

Status: Needs review » Needs work

#26 hmm, not sure exactly how that would work 🤔

I'm a bit lost on how FieldDefinitionInterface and FieldItemList are related.

kim.pepper’s picture

@alexpott re: #26 I added the method to\Drupal\file\Plugin\Field\FieldType\FileFieldItemList::getUploadLocation() but not sure how to access that from a $field_definition.

kim.pepper’s picture

@alexpott thanks for the review, but we still need to work out how to do this. See #28

alexpott’s picture

Yeah having this on the field item list doesn't work out :( I can't see how to get back to the list item either...

$field_definition->getClass() returns \Drupal\file\Plugin\Field\FieldType\FileFieldItemList but $field_defintion is actually a FieldItemDataDefinition.

How about not deprecating the stuff on the FileItem and use that - as suggested in #23.

kim.pepper’s picture

Status: Needs work » Needs review

I took the approach suggested in #30 of creating a file item from the field definition. I put it in a trait so it could get used by both REST and JSON API.

@alexpott Do we still want to postpone the deprecation to 12.x? It seems much less disruptive now.

kim.pepper’s picture

Title: Add a service to get file upload location from field settings » Add a trait to get file upload location from a field definition
Issue summary: View changes

Updated title and IS

alexpott’s picture

Given they are both controllers I think 11.x is fine

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Appears feedback has been addressed.

CR still appears fine, not sure if it was updated or mention removed in 12 before.

alexpott’s picture

Version: 11.x-dev » 10.3.x-dev
Status: Reviewed & tested by the community » Fixed

Committed and pushed 7a12710863 to 11.x and e9c7c01bc8 to 10.3.x. Thanks!

  • alexpott committed e9c7c01b on 10.3.x
    Issue #3389688 by kim.pepper, smustgrave, alexpott, quietone: Add a...

  • alexpott committed 7a127108 on 11.x
    Issue #3389688 by kim.pepper, smustgrave, alexpott, quietone: Add a...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

mattew’s picture

I've encountered a significant issue with the implementation of this change that affects the deprecation mechanism and backward compatibility.

The problem is that the current implementation uses a trait alias in FileUploadResource:

use FileUploadLocationTrait {
    getUploadLocation as getUploadDestination;
}

This creates several problems:

1. Deprecation warnings are bypassed: When a class extends FileUploadResource and overrides `getUploadLocation()`, the overridden method is never called because the core code now calls `getUploadDestination()` instead. This means the deprecation warning in the original `getUploadLocation()` method is never triggered.

2. Silent breakage: Existing code that extends FileUploadResource and overrides `getUploadLocation()` silently stops working without any indication to developers that their code needs updating.

3. Counter-intuitive override mechanism: Currently, if developers want to override the upload location logic, they must create a `getUploadDestination()` method instead of overriding `getUploadLocation()`, which is very counter-intuitive.

4. Misleading documentation: The deprecation message says "Use \Drupal\file\Upload\FileUploadLocationTrait::getUploadLocation() instead" but in practice, developers need to implement `getUploadDestination()`.

I've created a separate issue to address this: https://www.drupal.org/project/drupal/issues/3540037

This implementation effectively breaks the standard PHP inheritance model for the deprecation period, which could cause significant confusion and silent failures in contrib/custom modules that extend FileUploadResource.