5

In order to make a managed_file field permanent I did this in my module configuration form:

<?php

namespace Drupal\my_module\Form;

use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Class MymoduleSettings.
 */
class MymoduleSettings extends ConfigFormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'my_module_settings';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config                    = $this->config('my_module.settings');
    $form['my_module_title'] = [
      '#type'          => 'textfield',
      '#title'         => $this->t('Title'),
      '#description'   => $this->t("Enter the title"),
      '#maxlength'     => 64,
      '#size'          => 64,
      '#required'      => TRUE,
      '#default_value' => $config->get('my_module_title'),
    ];
    $form['mymodule_icon']   = [
      '#type'              => 'managed_file',
      '#title'             => $this->t('Icon'),
      '#description'       => $this->t("Upload the image file for the icon"),
      '#upload_location'   => 'public://',
      '#upload_validators' => [
        'file_validate_extensions' => ['gif png jpg jpeg'],
      ],
      '#default_value'     => $config->get('my_module_icon'),
    ];
    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    parent::submitForm($form, $form_state);

    $this->config('my_module.settings')
      ->set('my_module_title', $form_state->getValue('my_module_title'))
      ->set('my_module_icon', $form_state->getValue('my_module_icon'))
      ->save();

    // First we just grab the file ID for the icon we uploaded, if any.
    $icon_field = $form_state->getValue('my_module_icon');
    $file_id    = empty($icon_field) ? FALSE : reset($icon_field);

    if (!empty($file_id)) {
      // Make this a permanent file so that cron doesn't delete it later.
      $file         = File::load($file_id);
      $file->status = FILE_STATUS_PERMANENT;
      $file->save();
      $file_usage = \Drupal::service('file.usage');
      $file_usage->add($file, 'my_module', 'file', $file_id);
    }
  }

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return [
      'my_module.settings',
    ];
  }

}

but I'm getting warning to use dependency injection principle in this case:

File::load calls should be avoided in classes, use dependency injection instead

and

\Drupal calls should be avoided in classes, use dependency injection instead

I looked through Dependency Injection for a Form but still not sure that I really get it.

Can someone explain me what I need to do in this particular case so I can get a better view on this issue and figure it out?

2
  • You should put the "UPDATE" before everything. Like this, I was reading the issue, and I couldn't find the "File::" call you were complaining about. Also, I think it's a good practice to let the "buggy" code stay, so people can make comparisons.
    – ssibal
    Jul 31, 2017 at 9:15
  • I believe the OG post only had the submitForm method - I requested to see more so I could see if there were other issues.
    – Kevin
    Jul 31, 2017 at 14:51

1 Answer 1

11

If you are extending FormBase you can use create to inject dependencies. In this case what I think you want is the entity_type.manager service and file.usage.

  /**
   * Class constructor.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, FileUsageInterface $file_usage) {
    $this->entityTypeManager = $entity_type_manager;
    $this->fileUsage = $file_usage;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('file.usage')
    );
  }

See this docs page for more examples.

The create method sends arguments to the constructor, and then you set those to instance variables, and voila, there are your dependencies. Be sure to update your file with the necessary use statements and declare your protected members (entityTypeManager and fileUsage) at the top of the form class.

Therefore, you can remove the static ::service call and use:

$this->fileUsage->add()...

Also, the reason I am passing entity type manager service, is because you would replace File::load with:

$this->entityTypeManager->getStorage('file')->load($id);

If you need more than that object returns, you may need to use a different service but I don't know that off the top of my head.

19
  • 1
    Thank you very much. I changed to this $file = $this->entityTypeManager->getStorage('file')->load($file_id); and another line $this->fileUsage->add($file, 'my_module', 'file', $file_id);, but I'm getting Call to a member function getStorage() on null
    – mixerowsky
    Jul 29, 2017 at 20:08
  • Have you cleared cache?
    – Kevin
    Jul 29, 2017 at 20:11
  • Yes, I did...tried few times...
    – mixerowsky
    Jul 29, 2017 at 20:18
  • Can you update your post with all the form code?
    – Kevin
    Jul 29, 2017 at 20:18
  • Yes, I just updated it...
    – mixerowsky
    Jul 29, 2017 at 20:24

Your Answer

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

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