Description
Concerns
I would really like you to reconsider the amount of structural conventions surrounding the use of ModuleInterface
. As you know, I have spent some time toying with adding IDE support to modular projects via a composer plugin and one of the things I couldn't quite solve is dealing with constructor arguments. (->The plugin currently only inspects the bare implementations of ModuleInterface
without respecting the loading pattern via module.php
.
So the natural thing would be to extend support to the broader spec laid out in the README, but I cannot stop complaining. Hence, this issue.
It feels to me as if this whole module.php
pattern was mostly born out of the inability to safely bootstrap a collection of modules based on the composer package type alone¹ I think the beauty of the interface itself is that it's just 2 methods + the dependency on service-provider. But here you are blowing it up with a large amount of outside requirements:
- the presence of a
module.php
file - a specific type of package
- a mechanism to install the package type to a specified folder
Technically, only the module.php
file is spelled out as a hard requirement that a module MUST fulfill, while the rest might serve as an "example implementation" without being declared as such.
But module.php
is such a weird (and weirdly specific) requirement to make, and it got criticised before: #16 (review)
It's also somewhat contradicted by the existence of ModuleAwareInterface
. Why add an interface that would allow modules to be retrieved from a class instance if you set in stone that it must be provided by module.php
. I don't think it makes sense to define two opposing approaches to retrieve a module instance here.
Another thing that bothers me is that - while it would absolutely be possible to support module.php
in the IDE helper- you still cannot be sure you can instantiate a module without having to satisfy dependencies that a composer plugin cannot provide.
In other words: I think the goal of requiring a module.php
file was to enforce a standard way of supplying module factories in order to steer around the requirements of any individual module's constructor arguments. But it does not and cannot enforce the factory function itself to be devoid of function parameters so this point falls flat a bit. I think requiring a factory at all is a pretty hefty part of the spec when this should ideally be each individual application's concern. And if you're gonna go there, I would really like to see a more flexible approach - ideally one that allows usage of the standard without a factory as well
Suggestions
I've been thinking of two things:
- Changing
ModuleAwareInterface
so thatgetModule
is static²:
/**
* Something that can have a module instance retrieved.
*
* @since 0.2
*/
interface ModuleAwareInterface
{
/**
* Retrieves the module that is associated with this instance.
*
* @since 0.2
*
* @return ModuleInterface|null The module, if applicable; otherwise, null.
*/
public static function getModule();
}
- Instead of requiring a
module.php
as part of the standard, suggest that implementing packages SHOULD contain an entry in thecomposer.json
like this:
{
"extra": {
"dhii": {
"module-factory": "MyModuleProvider"
},
}
}
"module-factory"
could be one of the three:
- The FQCN of a class implementing
ModuleAwareInterface
which can now be called statically (erasing the dependency problem in the safest manner) - The name of a function that returns a
ModuleInterface
- The filename of a php file containing/returning a function that provides a
ModuleInterface
- Absent - in which case we could still look at the implementation(s) of
ModuleInterface
themselves to see if they can be instantiated without constructor arguments. That, or search the package for anyModuleAwareInterface
² and use that. In these scenarios, specifying this composer config would practically serve just as an override if the default behaviour is undesirable. Another reason why it would make sense to make this an optional requirement to begin with
Doing this would allow trimming down the spec to its bare minimum again while still fully satisfying any existing workflows. AND you'd introduce a standardized way for composer plugins to integrate with the module packages. And this doesn't even require them to be of a specific package type any longer.
¹This is something the composer plugin could really help out with by simply dumping all modules found. Of course, this gets more complex as soon as you need to customize the load order, but maybe a solution can be found for that as well
² Maybe this should be renamed to ModuleProvider
or put into a new class after all. I have not thought too much about the anticipated use-cases of ModuleAwareInterface
and just more or less assumed it's currently just sitting there unused by anyone