Skip to content

Commit f7e881c

Browse files
committed
Allow modules to live outside of app/code directory
1 parent 57ab446 commit f7e881c

File tree

5 files changed

+126
-5
lines changed

5 files changed

+126
-5
lines changed

app/etc/di.xml

100755100644
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<preference for="Magento\Framework\Config\CacheInterface" type="Magento\Framework\App\Cache\Type\Config" />
4545
<preference for="Magento\Framework\Config\ValidationStateInterface" type="Magento\Framework\App\Arguments\ValidationState" />
4646
<preference for="Magento\Framework\Module\ModuleListInterface" type="Magento\Framework\Module\ModuleList" />
47+
<preference for="Magento\Framework\Module\Dir\ResolverInterface" type="Magento\Framework\Module\Dir\Resolver" />
4748
<preference for="Magento\Framework\Event\ConfigInterface" type="Magento\Framework\Event\Config" />
4849
<preference for="Magento\Framework\Event\InvokerInterface" type="Magento\Framework\Event\Invoker\InvokerDefault" />
4950
<preference for="Magento\Framework\Interception\PluginListInterface" type="Magento\Framework\Interception\PluginList\PluginList" />

lib/internal/Magento/Framework/Module/Dir.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use Magento\Framework\App\Filesystem\DirectoryList;
1111
use Magento\Framework\Filesystem;
1212
use Magento\Framework\Filesystem\Directory\ReadInterface;
13+
use Magento\Framework\Stdlib\String as StringHelper;
14+
use Magento\Framework\Module\Dir\ResolverInterface;
1315

1416
class Dir
1517
{
@@ -25,14 +27,23 @@ class Dir
2527
*/
2628
protected $_string;
2729

30+
/**
31+
* Module directory resolver
32+
*
33+
* @var ResolverInterface
34+
*/
35+
private $dirResolver;
36+
2837
/**
2938
* @param Filesystem $filesystem
30-
* @param \Magento\Framework\Stdlib\String $string
39+
* @param StringHelper $string
40+
* @param ResolverInterface $resolver
3141
*/
32-
public function __construct(Filesystem $filesystem, \Magento\Framework\Stdlib\String $string)
42+
public function __construct(Filesystem $filesystem, StringHelper $string, ResolverInterface $resolver)
3343
{
3444
$this->_modulesDirectory = $filesystem->getDirectoryRead(DirectoryList::MODULES);
3545
$this->_string = $string;
46+
$this->dirResolver = $resolver;
3647
}
3748

3849
/**
@@ -45,7 +56,10 @@ public function __construct(Filesystem $filesystem, \Magento\Framework\Stdlib\St
4556
*/
4657
public function getDir($moduleName, $type = '')
4758
{
48-
$path = $this->_string->upperCaseWords($moduleName, '_', '/');
59+
if (null === $path = $this->dirResolver->getModulePath($moduleName)) {
60+
$path = $this->_string->upperCaseWords($moduleName, '_', '/');
61+
}
62+
4963
if ($type) {
5064
if (!in_array($type, ['etc', 'i18n', 'view', 'Controller'])) {
5165
throw new \InvalidArgumentException("Directory type '{$type}' is not recognized.");
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
/**
3+
* Copyright © 2015 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Framework\Module\Dir;
8+
9+
/**
10+
* Provides ability to statically register modules which do not reside in the modules directory
11+
*
12+
* @author Josh Di Fabio <joshdifabio@gmail.com>
13+
*/
14+
final class Resolver implements ResolverInterface
15+
{
16+
/**
17+
* Paths to modules
18+
*
19+
* @var string[]
20+
*/
21+
private static $modulePaths = [];
22+
23+
/**
24+
* Sets the location of a module. Necessary for modules which do not reside in modules directory
25+
*
26+
* @param string $moduleName Fully-qualified module name
27+
* @param string $path Absolute file path to the module
28+
*/
29+
public static function setModulePath($moduleName, $path)
30+
{
31+
self::$modulePaths[$moduleName] = $path;
32+
}
33+
34+
/**
35+
* {@inheritdoc}
36+
*/
37+
public function getModulePaths()
38+
{
39+
return self::$modulePaths;
40+
}
41+
42+
/**
43+
* {@inheritdoc}
44+
*/
45+
public function getModulePath($moduleName)
46+
{
47+
return isset(self::$modulePaths[$moduleName]) ? self::$modulePaths[$moduleName] : null;
48+
}
49+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
/**
3+
* List of active application modules.
4+
*
5+
* Copyright © 2015 Magento. All rights reserved.
6+
* See COPYING.txt for license details.
7+
*/
8+
namespace Magento\Framework\Module\Dir;
9+
10+
/**
11+
* @author Josh Di Fabio <joshdifabio@gmail.com>
12+
*/
13+
interface ResolverInterface
14+
{
15+
/**
16+
* Get list of Magento module paths
17+
*
18+
* Returns an array where key is fully-qualified module name and value is absolute path to module
19+
*
20+
* @return array
21+
*/
22+
public function getModulePaths();
23+
24+
/**
25+
*
26+
* @param string $moduleName
27+
*/
28+
public function getModulePath($moduleName);
29+
}

lib/internal/Magento/Framework/Module/ModuleList/Loader.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use Magento\Framework\Filesystem;
1111
use Magento\Framework\Module\Declaration\Converter\Dom;
1212
use Magento\Framework\Xml\Parser;
13+
use Magento\Framework\Module\Dir\ResolverInterface;
14+
use Magento\Framework\Filesystem\Directory\ReadInterface;
1315

1416
/**
1517
* Loader of module list information from the filesystem
@@ -37,19 +39,28 @@ class Loader
3739
*/
3840
private $parser;
3941

42+
/**
43+
* Module directory resolver
44+
*
45+
* @var ResolverInterface
46+
*/
47+
private $dirResolver;
48+
4049
/**
4150
* Constructor
4251
*
4352
* @param Filesystem $filesystem
4453
* @param Dom $converter
4554
* @param Parser $parser
55+
* @param ResolverInterface $resolver
4656
*/
47-
public function __construct(Filesystem $filesystem, Dom $converter, Parser $parser)
57+
public function __construct(Filesystem $filesystem, Dom $converter, Parser $parser, ResolverInterface $resolver)
4858
{
4959
$this->filesystem = $filesystem;
5060
$this->converter = $converter;
5161
$this->parser = $parser;
5262
$this->parser->initErrorHandler();
63+
$this->dirResolver = $resolver;
5364
}
5465

5566
/**
@@ -62,7 +73,7 @@ public function load()
6273
{
6374
$result = [];
6475
$dir = $this->filesystem->getDirectoryRead(DirectoryList::MODULES);
65-
foreach ($dir->search('*/*/etc/module.xml') as $file) {
76+
foreach ($this->getModuleConfigPaths($dir) as $file) {
6677
$contents = $dir->readFile($file);
6778

6879
try {
@@ -84,6 +95,23 @@ public function load()
8495
return $this->sortBySequence($result);
8596
}
8697

98+
/**
99+
* Get an array containing the absolute file paths to all known module.xml files
100+
*
101+
* @param ReadInterface $modulesDir
102+
* @return array
103+
*/
104+
private function getModuleConfigPaths(ReadInterface $modulesDir)
105+
{
106+
$moduleConfigPaths = $modulesDir->search('*/*/etc/module.xml');
107+
108+
foreach ($this->dirResolver->getModulePaths() as $modulePath) {
109+
$moduleConfigPaths[] = $modulesDir->getAbsolutePath("$modulePath/etc/modules.xml");
110+
}
111+
112+
return array_unique($moduleConfigPaths);
113+
}
114+
87115
/**
88116
* Sort the list of modules using "sequence" key in meta-information
89117
*

0 commit comments

Comments
 (0)