Skip to content

Reconsider structural requirements #21

Open
@Biont

Description

@Biont

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:

  1. Changing ModuleAwareInterface so that getModule 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();
}
  1. Instead of requiring a module.php as part of the standard, suggest that implementing packages SHOULD contain an entry in the composer.json like this:
{
    "extra": {
        "dhii": {
            "module-factory": "MyModuleProvider"
        },
    }
}

"module-factory" could be one of the three:

  1. The FQCN of a class implementing ModuleAwareInterface which can now be called statically (erasing the dependency problem in the safest manner)
  2. The name of a function that returns a ModuleInterface
  3. The filename of a php file containing/returning a function that provides a ModuleInterface
  4. 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 any ModuleAwareInterface² 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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions