Generally, in Moodle, we like different plugins to be completely independent and self contained. This is nice and simple, but not always possible, and there are various ways plugins can depend on other things. For example:
Well, to start with, no plugin is independent, becuase they all depend on Moodle core, and this is completely fine.
Then, again, when you have sub-plugins, like Quiz access rules, or Assignment submission types, which necessarily depend on the parent plugins like Quiz or Assignment module. Again, this is to be expected.
Now we start to get to more messy scenarios
Sometimes, you have an add-on that only makes sense if another add-on in installed. For example
- Two of my add-ons. Report workflow is only useful if Block workflow is installed.
- auth_cas requires auth_ldap to be installed, becase CAS extends the functionality provided by LDAP.
- filter_glossary requires mod_glossary, again this makes sense.
A few years ago we introduced $plugin->dependencies in plugin version.php files, to make this explicit, and so that the Moodle install system could make sure that you did not install an add-on without the other required add-ons. This case is now pretty well supported.
- The final scenario is in the other directly. What if other plugins need to provide some code to work with this plug-in, if it is present. The topical example is Report builder, which they are planning to add to Moodle 2.8. The rest of this post is about this case, which is not currently well supported by Moodle.
Further summary of the problem
So here are some examples of the problem:
- The new report-builder tool requires each plugin to describe its data, if data from that plugin is to be included in Report-builder reports. This is done by a class in mod_choice that makes the required information available. This class has to extend a base class in tool_reportbuilder.
- I have an add-on, report_editdates, which lets you edit all the date settings in your course on a single page. This requires a class for each activity that we want to support, like report_editdates_mod_forum_date_extractor. At the moment we store all those classes inside report/editdates, but that is not extensible. It would be more flexible those classes could be stored inside each separate module. (Though we might still want to keep the classes for core mods inside
- Another similar example is the Combined question type, one of the OU question-type add-ons. This lets you build one question out of several other, like qtype_multianswer/Cloze, but better. One way that it is better is that it is extensible. Another qtype can make itself addable to qtype_combined by defining some classes in a folder like question/type/myqtype/combinable, for example in pattern-match.
That last issues shows, that really we don't need anything special in Moodle core. You can just get on and do this, by making up your own rules. The point is that it is better for Moodle if we can come up with a standard way to do this for all similar situations.
The other point is, we now have a system of automatic class-loading, and we want to work with that. There were recently some rules defined about that, and we should fit in with those rules. I don't think the integrators have written up what was agreed in MDLSITE-2549 yet, so let me summarise.
- Classes go in a path/to/my/plugin/classes folder. (For plugin with Frankenstyle name type_plugin.)
- Classes can just go in the root of that folder, in which case the auto-loader will try to find the class type_plugn_class_name in the file path/to/my/plugin/classes/class_name.php.
- Alternatively, you can use PHP namespaces, in which case the class \type_plugin\sub1\sub2\class_name is looked for in path/to/my/plugin/sub1/sub2/class_name.php.
- In the name-space case, there are rules about what is allowed for sub1. Basically, you are only allowed to use the names of core components like event, backup, ... there, plus you can have sub1 == local, and inside local you can do whatever you like (so it is like the locallib.php file that a lot of plugins use).
So, my proposed solution for the case where other add-ons want to optionally integrate with other plugins, is to extend the rules for what is allowed at leave sub1. Extend the rules so that you can use the frankenstyle name of another plugin there, just like you can refer to core APIs. So, the examples above the classes you would need to create to make the integration work are, for example
- \mod_choice\tool_reportbuilder\data_description (in mod/choice/classes/tool_reportbuilder/data_description.php)
- \qtype_pmatch\qtype_combined\renderer.php and \qtype_pmatch\qtype_combined\combinable.php
The plugin that looks for these classes would just find whether another plugin supports it with a class_exists call, and we already have ancore_component::get_plugin_list_with_class() API.
Rather than doing this at the sub1 level of namspacing, we could instead declare a new sub1=plugin, and then put the name of the other plugin at sub2 level, like \mod_choice\plugin\tool_reportbuilder\data_description, but I think it is impossible for the Frankenstyle name of an add-on to be the same as the name of a core component, so I prefer the flatter structure.
The other proposed solution
The reason I make this long boring post now, is that earlier, the Integration team had a secret meeting and came up with their own proposed solution, which so far they have only publised in a comment on a tracker issue https://tracker.moodle.org/browse/MDL-30193?focusedCommentId=293371&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-293371.
In short their solution is to define a new core API 'reporting' just for the use of plugin tool_reportbuilder. That is all very well for something like report-builder, which is going in to core, but it does not work for add-ons like Edit dates or Combined question types.
One of the good trends in Moodle in recent years has been increase the power of what add-ons can do without requiring changes ot Moodle core. The decision the integrators just took seems like a backwards step to me. Please reconsider.