Can Virtual Types be used as controllers?
-
06-01-2021 - |
Question
This is more of a curiosity than a "need".
I have a few controller actions that do exactly the same thing, just some parameters differ.
I'm trying to reduce the amount of code I write and have one single controller class and via di.xml
configure that class using virtual types.
I know I can just create empty classes for each controller that extend a main controller action and configure them via di.xml, but I want to skip those too if possible.
I got from here that virtual types can be used as source models because they are instantiated via object manager.
Controllers are also instantiated via Object Manager, but I think things happen a little different.
I'm expecting an answer like:
- this is not possible because...
- yes, it's possible, here is how you can do it...
- not sure it is possible but here is how you can test....
Solution
This isn't possible because the core routers build the action list using \Magento\Framework\Module\Dir\Reader::getActionFiles
source, which loads the available actions by reading files contained in each module's Controller
directory. Below is the function as it currently exists in 2.3-develop:
public function getActionFiles()
{
$actions = [];
foreach ($this->modulesList->getNames() as $moduleName) {
$actionDir = $this->getModuleDir(Dir::MODULE_CONTROLLER_DIR, $moduleName);
if (!file_exists($actionDir)) {
continue;
}
$dirIterator = new \RecursiveDirectoryIterator($actionDir, \RecursiveDirectoryIterator::SKIP_DOTS);
$recursiveIterator = new \RecursiveIteratorIterator($dirIterator, \RecursiveIteratorIterator::LEAVES_ONLY);
$namespace = str_replace('_', '\\', $moduleName);
/** @var \SplFileInfo $actionFile */
foreach ($recursiveIterator as $actionFile) {
$actionName = str_replace('/', '\\', str_replace($actionDir, '', $actionFile->getPathname()));
$action = $namespace . "\\" . Dir::MODULE_CONTROLLER_DIR . substr($actionName, 0, -4);
$actions[strtolower($action)] = $action;
}
}
return $actions;
}
It may be possible to do this using custom router and action list classes, but it is not possible out of the box.