Route parameter upcasting and route access? 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.

mymodule.routing.yml:

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


mymodule.tasks.yml:

entity.file.import_data:
  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.
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) {


with:

 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

options:
  parameters:
    my_slug_name:
      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.