ThemeRegistryLoader::findTemplate()
breaks \Twig_Loader_Filesystem
signature by NOT returning a strict FALSE in case of errors when throwing exceptions is disabled.
Looking in the \Twig_Loader_Chain
, you can see this code:
public function exists($name)
{
$name = (string) $name;
if (isset($this->hasSourceCache[$name])) {
return $this->hasSourceCache[$name];
}
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface) {
if ($loader->exists($name)) {
return $this->hasSourceCache[$name] = true;
}
continue;
}
try {
if ($loader instanceof Twig_SourceContextLoaderInterface) {
$loader->getSourceContext($name);
} else {
$loader->getSource($name);
}
return $this->hasSourceCache[$name] = true;
} catch (Twig_Error_Loader $e) {
}
}
return $this->hasSourceCache[$name] = false;
}
And in \Twig_Loader_Filesystem
this code:
public function exists($name)
{
$name = $this->normalizeName($name);
if (isset($this->cache[$name])) {
return true;
}
try {
return false !== $this->findTemplate($name, false);
} catch (Twig_Error_Loader $exception) {
@trigger_error(sprintf('In %s::findTemplate(), you must accept a second argument that when set to "false" returns "false" instead of throwing an exception. Not supporting this argument is deprecated since version 1.27.', get_class($this)), E_USER_DEPRECATED);
return false;
}
}
As you can see, it tests for a strict FALSE boolean, but the custom Drupal load does return NULL (no return statement) instead. This as a serious side effect: it creates a false positive for the exists()
method return.
I guess that no-one ever saw that coming because in core, there are no other loaders, but in my use case I do have a custom loader, and because we have a false positive here, it will always try to render via the theme registry instead of my custom loader.
I end up having exceptions were I should not. I'm doing the patch ASAP. Please note that it's a bug for both 8.3.x and 8.2.x but I'm going to solve this in 8.3.x.