Original problem:

I am trying to do a couple of (seemingly) simple things to convert a module I made in Drupal 7 to Drupal 8 (RC1).

First I will note I am using the File Entity module in Drupal 8, which may or may not be stable/complete.

I want to add a tab on a File entity (much like Edit or Archive) that lets me trigger processes, related to the data contained in the file (its a spreadsheet).

So far, I have been able to stumble through getting a route defined and a tab to appear.


  path: '/file/{file}/import-data'
    _form: '\Drupal\datacenter\Form\ImportDataForm'
    _title: 'Import Data'
    _permission: 'access content'
    _admin_route: TRUE


  route_name: entity.file.import_data
  title: 'Import Data'
  base_route: entity.file.canonical
  weight: 3

Well okay. So far so good. Not the most robust thing in the world, but I am still working my way through unfinished docs and such. From here, I have a new tab on a File entity form, right next to Edit.

First, how can I change the permissions to not be access content, but to check access to see if the current user has access to edit the file in question? If I change _permission to _entity_access: file.update (as I have seen in File Entity) the tab vanishes, and direct URL access returns Access Denied (even as user 1). Do I have to implement something extra to make that work?

Second, I don't seem to be receiving the {file} argument or file entity object in my form builder.

Form class:

namespace Drupal\datacenter\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class ImportDataForm extends FormBase {
   * {@inheritdoc}.
  public function getFormId() {
    return 'datacenter_import_data_form';

   * {@inheritdoc}.
  public function buildForm(array $form, FormStateInterface $form_state, FileInterface $file = NULL) {
    // fields to be defined

    return $form;

 // extra code removed

buildForm doesn't have an entity (file) argument. What am I missing? I thought upcasting basically happened if the object ID was in the route (like node, user, etc).

Also, is this even the way to go about it? Basically this screen will do a few things, it will inspect the file object, check to make sure the mime is right, parse the csv or excel data, and read it back on the screen in the form of options. Whatever the user ticks off, will kick off a series of batches. Where would those batch functions go? In this class? In another file? I also see other classes like ContentEntityForm, EntityForm, etc.. which one should I be using?

I have all of this working great in Drupal 7, I am just having trouble getting momentum converting it over and finding what I need.

  • Permission: yes, UID1 won't work with entity access if you don't have permissions set. Form: you have to use one of the entity form. I am not sure if file is config entity or content entity but basedo n that you have to use entity form for config entity or contententityform for ocntent entity(just check form for Node and NodeType). Batches: in submit handler add batch config and you can call batch worker form wherever you like, it can be method(static preferably) on the form class itself.
    – user21641
    Commented Oct 14, 2015 at 19:48
  • Administrator has all permissions set, but still gets access denied
    – Kevin
    Commented Oct 14, 2015 at 20:49
  • 1
    First you need: public function buildForm(array $form, FormStateInterface $form_state, FileInterface $file = NULL) { That will solve at least some of the problems. Commented Oct 15, 2015 at 1:38
  • Well I debugged it and no additional args are passed to the function, so in this case $file will always be null. Actually error is: "Argument 3 passed to Drupal\datacenter\Form\ImportDataForm::buildForm() must be an instance of Drupal\file\FileInterface, string given"
    – Kevin
    Commented Oct 15, 2015 at 12:59
  • 1
    Paths should be wrapped in single quotes. That is not a solution of your problem. I think it was just you clearing caches and DI picking up on the additional argument that you have added to the form(it is DI because it checks the data it has and the data that is expected). Try to add the quotes back, CC and see what happens.
    – user21641
    Commented Oct 15, 2015 at 14:38

1 Answer 1


Entities can be upcasted with these methods:

Note: to use _entity_access requirement, you must implement one of these options this information. See \Drupal\Core\Entity\EntityAccessCheck for internals.

Controller reflection

Type cast the entity object as a parameter of the controller.

For your form controller, replace:

 buildForm(array $form, FormStateInterface $form_state, $file = NULL) {


 buildForm(array $form, FormStateInterface $form_state, \Drupal\file\FileInterface $file = NULL) {

This works with any entity type, not just files.

See EntityResolverManager:setParametersFromReflection.

Using _entity_view or _entity_form controllers

Entity types found in the path are upcasted automatically if the route definition has _entity_view or _entity_form as a default.

See EntityResolverManager:setParametersFromEntityInformation.

Add upcasting info to your route

Add the following to your route YAML

      type: 'entity:my_entity_type_id'

Replace my_slug_name with whichever text you used in your route within the {}. Usually this is exacly the same as the entity type Id.

Then replace my_entity_type_id text with the entity type Id.

I have written something similar for Views Advanced Routing in its README.

  • I thought the default upcasting works for any controller as long as that also has a type hint on entityinterface/nodeinterface/... ?
    – Berdir
    Commented Oct 15, 2015 at 19:48
  • I see @tim.plunkett made that suggestion. Looks like I omitted the reflection upcast.
    – Daniel
    Commented Oct 16, 2015 at 6:06
  • Okay... interesting... wading through school of hard knocks at the moment with D8.
    – Kevin
    Commented Oct 19, 2015 at 15:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.