7

I have a custom module with a form class, where I am trying to inject a custom service to use within it's submit method:

namespace Drupal\my_module\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\my_module\CustomManager;
use Symfony\Component\DependencyInjection\ContainerInterface;

class CustomForm extends FormBase{

  private $custom_manager;

  function __construct(CustomManager $custom_manager) {
    $this->custom_manager = $custom_manager;
  }

  public static function create(ContainerInterface $container) {
    return new static(
    // Load the service required to construct this class.
      $container->get('my_module.manager')
    );
  }

  .....

  public function submitForm(array &$form, FormStateInterface $form_state) {          
      // Test service.
      $this->custom_manager->test();
  }

} 

When I submit the form, I get the following error:

Fatal error: Call to a member function test() on null

It seems like my custom service hasn't been instantiated as expected, since the $custom_manager property is null.

Strange thing is when I debug the constructor, the service IS being instantiated properly.

Has anyone had this issue before? I can instantiate the service via the global Drupal class, but apparently doing the dependency injection is best practice.

Thanks in advance!

2 Answers 2

12

I accidentally declared the $custom_manager property of my class as private instead of protected, and that's why I was unable to access the custom manager object in the form submission method. Whoops!

MPD's answer is theoretically correct though, as class requiring to access services do need to implement the ContainerInjectionInterface class.

Worth noting though that the class FormBase which we're extending, already implements ContainerInjectionInterface, so we don't need to explicitly do so when creating a custom form.

3
  • 2
    Yes, we had this recently in a project too. This is actually related to serialization, because the DependencySerializationTrait doesn't see your property and can therefore not restore it.
    – Berdir
    Commented May 12, 2016 at 11:42
  • ah interesting! thanks for sharing, I wouldn't have had the first clue why the private property wasn't being assigned otherwise Commented May 12, 2016 at 12:15
  • I had the same issue, thank you very much! you save my day
    – jorgetutor
    Commented Sep 27, 2017 at 15:12
3

Not 100% sure this is the problem, but anything with dependencies needs to implement ContainerInjectionInterface in one way or another (directly or inherited via the parent class). So, your problem is likely that you need to do

use Drupal\Core\DependencyInjection\ContainerInjectionInterface;

class CustomForm extends FormBase implements ContainerInjectionInterface {
  // ...
}

That way it will be picked up via discovery by the ClassResolver and have the ::create() method called. Just make sure you do a drush cr (or equivalent) to make sure everything gets wired up properly.

3
  • 2
    Yes. ContainerInjectionInterface for controllers and forms, ContainerFactoryPluginInterface for plugins.
    – mradcliffe
    Commented May 12, 2016 at 0:40
  • Thanks for the help, but unfortunately this doesn't seem to change the results of my issue. Further investigation it seems like FormBase (which we're extending) already implements ContainerInjectionInterface anyway. Commented May 12, 2016 at 9:34
  • After your answer I spotted my specific syntax error. Upvoted your answer since it's theoretically correct. Thanks again! :) Commented May 12, 2016 at 9:46

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.