What to do when developing a Drupal 8 module and a class file just isn't being autoloaded even though it is definitely there
Short answer: Restart apache or disable the APC classloader in your local.settings.php (see settings.php).
While working on the Give module, which follows the same pattern for donation forms as Drupal 8 core's Contact module uses for contact forms, an access control handler was not being found even though i quadruple checked that my handler annotation described the handler correctly for the name and location of its file.
The ConfigEntityType annotation for the access handler, with most other annotations removed:
<?php
/**
* Defines the give form entity.
*
* @ConfigEntityType(
* id = "give_form",
* handlers = {
* "access" = "Drupal\give\GiveFormAccessControlHandler",
* },
* )
*/
class GiveForm extends ConfigEntityBundleBase implements GiveFormInterface {
?>
The location of the file with the GiveFormAccessControlHandler() class, relative to the give module:
src/GiveFormAccessControlHandler.php
That is correct. Why was i getting an error that the "entity type did not specify a access handler", despite cache reloads and very earnest wishing it would find it?
My debugger told me that EntityType's implementation of getHandlerClasses returned the handler as defined in the ConfigEntityType annotation. So far so good; Drupal's reading the annotation correctly.
Yet it continued to "throw new InvalidPluginDefinitionException($entity_type, sprintf('The "%s" entity type did not specify a %s handler.', $entity_type, $handler_type));", as line 228 of EntityTypeManager.php put it so eloquently.
Where things fell apart is that it doesn't find the file which the class is in. Why it can't find a file that is clearly there is explained in the issue that caused this possibility:
Use APC Classloader by default (when available), which made the setting class_loader_auto_detect default to TRUE. Setting it to FALSE disables automatic enablement of the APC class loader.
In that issue, Berdir warned that when using APC Classloader "sometimes when you update code and move classes around, really weird stuff can happen. I know that I have to restart apache if that happens, others might not know or even able to do that". His proposed fallback solution of making sure there's an easy way to make rebuilding clear stale information was apparently not implemented.
So if your handlers or other classes aren't being found while you're developing, the explanation for why is in settings.php:
<?php
/**
* Class Loader.
*
* If the APC extension is detected, the Symfony APC class loader is used for
* performance reasons. Detection can be prevented by setting
* class_loader_auto_detect to false, as in the example below.
*/
# $settings['class_loader_auto_detect'] = FALSE;
/*
* If the APC extension is not detected, either because APC is missing or
* because auto-detection has been disabled, auto-loading falls back to
* Composer's ClassLoader, which is good for development as it does not break
* when code is moved in the file system. You can also decorate the base class
* loader with another cached solution than the Symfony APC class loader, as
* all production sites should have a cached class loader of some sort enabled.
?>
And you can fix it in local.settings.php with one line:
<?php
$settings['class_loader_auto_detect'] = FALSE;
?>
Comments
Post new comment