Completely module based Flow application

I’m building a module based application, where a user can activate (buy) modules. Instead of creating subrequest in the way Neos CMS does it, I’m looking into one of the following approaches

1. RoutePartHandler

Create a routeparthandler that does something.

Not very well thought through yet… I will be overriding a @action and @controller at some point - I’m not really a fan of it.

2. HTTP Chain component

Imagine a request to the path www.application.tld/billing or www.application.tld/email/vacation

In Routes.yaml all requests go into a ModuleController - but before it reaches this I will have my own Http component that does the following:

Take the URI, ex. billing or email/vacation and split it by the first /.

The first argument will be module name. The second will be a @controller and a third would be a @action.

I register my module in a module manager, via a YAML syntax (nevermind that at the moment) and inside my Component i will do something like this (pure pseudo code)

if ($this->moduleManager->isModuleAvailable($module)) {
  $module = $this->moduleManager->getModule($module);
  $routingMatchResults = $componentContext->getParameter(Routing\RoutingComponent::class, 'matchResults');
  $routingMatchResults['@controller'] = $module->getController();
  $routingMatchResults['@action'] = $module->getAction();
  $componentContext->setParameter(RoutingComponent::class, 'matchResults', $routingMatchResults);
}

This will be before the “dispatchComponent” that takes care of the request and security etc.

Am I looking into any troubles, going the HTTP Component way, in terms of speed, compiling in production context or anything?

Mainly looking for some inside knowledge by the core team or anyone who have been doing anything similar.

We a feature that have the same requirements.

We end up with a Feature switcher, basically we have a registry of feature, and we protect the controller with an aspect. Every user has a subscription to some feature, and that work. A little Viewhelper help use to build the navigation based on the available feature.

So no hacking in the routing :wink:

The only limitation of our solution, is that we have one dedicated route per feature (we don’t share a single route to different module). But you can solve this with specific route:

Thanks @dfeyer for that :slight_smile: Some questions

  1. How do you protect the controller with a Aspect?
  2. Do you create seperate packages for each feature?

What I’ve gotten around of thought so far:

I don’t want the module to think about routing - that part is given according to a “namespace” that the module register in it’s configuration. Currently my yaml configuration syntax looks like this

    namespace: 'uri-namespace'
    mandatory: false
    package: 'Vendor.App.Module'
    icon: 'resource://Vendor.App.Module/Public/Icons/reporting.png'
    sidebar:
    submodules:
      report:
        route:
          '@controller': 'Report'

I think’s that where I rely only “routing hacking” (which, by the way, is a fairly clean task)

An around aspect for the controller action that throw an Exception if the current context (domain, user, account, …) as the current feature disabled.

It does not matter, up to you. The feature switcher is a dedicated package, and we use redis to cache the configuration of the allowed feature, like this have an API to enable feature without redeploying the application.

Okay :slight_smile: In terms of the programmatically API (DDD-wise), how do enable a feature?

Is it the purpose of a ModuleManager or is it done in the context of a user?

$moduleManager->enableModuleForUser($module, $user);

or would you go for

$user->enableModule($module);

In our case the FeatureSwitcher is a micro service, he know nothing about the application, just feature identifier (like Billing/Advanced/1.0) and the context identifier (can be anything unique, account identifier, domain name, …). You ask the API is this feature enable for this context, the answer is yes and no, and some logging to know who use feature X or Y.