Problem/Motivation

Ctools insists on using Drupal's registry for plugin classes, even if the class can already be loaded. Ctools' own class placement convention is terribly outdated, and developers are moving to PSR-4 even for Drupal 7 projects.

Proposed resolution

Do not use the registry when a plugin class can already be loaded.

Remaining tasks

None.

User interface changes

None.

API changes

None.

Data model changes

None.

Comments

Xano created an issue. See original summary.

xano’s picture

Status: Active » Needs review
StatusFileSize
new1.31 KB
donquixote’s picture

Status: Needs review » Needs work

I imagine there could be cases where the class_exists() is not reliable.
E.g. it can happen that the class file was already included for the current request, but maybe this was because it was previously in the registry.

I propose instead to check for namespace separators in the class name.
Currently the registry does not detect such classes anyway. So there is no point in adding the class file in hook_registry_files_alter().

(The Registry autoload module does in fact use the core registry for namespaced classes. But it does not use hook_registry_files_alter(). Instead it writes the mappings directly into the database.)

This aside, I do support the direction of this change.

donquixote’s picture

This would mean the second more verbose structure with ['class'], ['file'] and ['path'] does not make much sense if ['class'] has namespaces. Maybe we want to warn the user? But maybe for a start it is good enough to just ignore the file and path in this case.

xano’s picture

The reason I went for this particular solution, is that it not only solves my particular problem (using PSR-4 through xautoload), but generally prevents Ctools from enforcing its own approach if that's not actually needed for whatever reason.

I imagine there could be cases where the class_exists() is not reliable.
E.g. it can happen that the class file was already included for the current request, but maybe this was because it was previously in the registry.

Is it possible for a class to be loaded by the registry and then disappear from that same registry during a single request?

This would mean the second more verbose structure with ['class'], ['file'] and ['path'] does not make much sense if ['class'] has namespaces.

Why not? One can use namespaces, but not follow PSR-0 or PSR-4.

donquixote’s picture

Is it possible for a class to be loaded by the registry and then disappear from that same registry during a single request?

No.
What I imagine can happen is the following:

  1. You install a module that introduces some regular old-school ctools plugin class files.
  2. Registry is rebuilt. class_exists() for these classes returns FALSE, because they are not in the registry yet and cannot be autoloaded.
  3. Because class_exists() returned FALSE, the classes files are now added to the list of files to scan.
  4. So the classes provided by the module do end up in the registry.
  5. Later for some reason you rebuild the registry.
  6. class_exists() now returns TRUE for these classes because they are still loadable with the old registry.
  7. Because class_exists() returned TRUE, the class files are not added to the list of files to scan.
  8. So in the new registry the classes are not added.

So the class files flip-flop between being in the registry and not being in the registry.
I assume not what you intended :)

Using class_exists while building a new registry is bound to be fragile, because it depends on the old registry.

donquixote’s picture

This would mean the second more verbose structure with ['class'], ['file'] and ['path'] does not make much sense if ['class'] has namespaces.

Why not? One can use namespaces, but not follow PSR-0 or PSR-4.

Because adding a file with namespaces to the list of files to scan does not really do anything.
Drupal just fails to detect the classes in these files.

Modules with namespaced plugin classes, even if they don't use PSR-0 or PSR-4, already now need their own technique of having these classes autoloaded. They cannot rely on the registry class discovery.

(And again, registry_autoload works in a different way)

xano’s picture

Status: Needs work » Needs review
StatusFileSize
new1.33 KB

I understand, and I think I just ran into this issue.

I'm not sure if this is the best way to check for namespaces in FQNs, but this patch does not seem to collide with the registry, and it prevents namespaced classes from being added to the registry by Ctools itself. It does not fix the problem for non-namespaced classes that do not want to use Ctools registry magic, though. This includes plugin class files that are defined in *.info files.

donquixote’s picture

I'm not sure if this is the best way to check for namespaces in FQNs

strpos() === FALSE seems fine to me.

It does not fix the problem for non-namespaced classes that do not want to use Ctools registry magic, though.

What about checking for $plugin_definition[$class_key]['file'] === FALSE ?
So developers can set this to FALSE to suppress the magic.

b-prod’s picture

This patch is a mix between the one in comment #8 and the comment of donquixote.

So:

  • if the class is a single string using namespace, it is not added to the registry;
  • if the class is an array definition, it may be intentionally skipped from the registry if specifying FALSE for the file key.

This patch should not cause trouble neither with existing code nor with plugin declared by contributed modules, so it is safe to use.

chris matthews’s picture

The 2 year old patch in #10 to registry.inc applied cleanly to the latest ctools 7.x-1.x-dev, but still needs to be reviewed and tested.

japerry’s picture

Status: Needs review » Closed (outdated)

Drupal 7 is no longer supported, closing.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.