Skip to content

Commit

Permalink
Merge pull request #7405 from magento-arcticfoxes/B2B-2148
Browse files Browse the repository at this point in the history
B2B-2148: Can no longer install when my database name has a dash in it
  • Loading branch information
joanhe authored Jan 19, 2022
2 parents 67fbf08 + eb3a969 commit 5d2f685
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 13 deletions.
62 changes: 52 additions & 10 deletions lib/internal/Magento/Framework/App/Router/ActionList.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\State;
use Magento\Framework\App\Utility\ReflectionClassFactory;
use Magento\Framework\Config\CacheInterface;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Module\Dir\Reader as ModuleReader;
use Magento\Framework\Serialize\Serializer\Serialize;
use Magento\Framework\Serialize\SerializerInterface;
use ReflectionClass;
use ReflectionException;

/**
* Class to retrieve action class.
Expand All @@ -23,7 +27,7 @@ class ActionList
/**
* Not allowed string in route's action path to avoid disclosing admin url
*/
const NOT_ALLOWED_IN_NAMESPACE_PATH = 'adminhtml';
public const NOT_ALLOWED_IN_NAMESPACE_PATH = 'adminhtml';

/**
* List of application actions
Expand Down Expand Up @@ -55,30 +59,43 @@ class ActionList
*/
private $actionInterface;

/**
* @var ReflectionClassFactory|null
*/
private $reflectionClassFactory;

/**
* @param CacheInterface $cache
* @param ModuleReader $moduleReader
* @param string $actionInterface
* @param string $cacheKey
* @param array $reservedWords
* @param SerializerInterface|null $serializer
* @param State|null $state
* @param DirectoryList|null $directoryList
* @param ReflectionClassFactory|null $reflectionClassFactory
* @throws FileSystemException
*/
public function __construct(
CacheInterface $cache,
ModuleReader $moduleReader,
$actionInterface = ActionInterface::class,
$cacheKey = 'app_action_list',
$reservedWords = [],
SerializerInterface $serializer = null
SerializerInterface $serializer = null,
State $state = null,
DirectoryList $directoryList = null,
ReflectionClassFactory $reflectionClassFactory = null
) {
$this->reservedWords = array_merge($reservedWords, $this->reservedWords);
$this->actionInterface = $actionInterface;
$objectManager = ObjectManager::getInstance();
$this->serializer = $serializer ?: $objectManager->get(Serialize::class);
$state = $objectManager->get(State::class);
$this->serializer = $serializer ?: ObjectManager::getInstance()->get(Serialize::class);
$state = $state ?: ObjectManager::getInstance()->get(State::class);
$this->reflectionClassFactory = $reflectionClassFactory
?: ObjectManager::getInstance()->get(ReflectionClassFactory::class);

if ($state->getMode() === State::MODE_PRODUCTION) {
$directoryList = $objectManager->get(DirectoryList::class);
$directoryList = $directoryList ?: ObjectManager::getInstance()->get(DirectoryList::class);
$file = $directoryList->getPath(DirectoryList::GENERATED_METADATA)
. '/' . $cacheKey . '.' . 'php';

Expand Down Expand Up @@ -106,6 +123,7 @@ public function __construct(
* @param string $namespace
* @param string $action
* @return null|string
* @throws ReflectionException
*/
public function get($module, $area, $namespace, $action)
{
Expand All @@ -126,11 +144,35 @@ public function get($module, $area, $namespace, $action)
$module . '\\controller' . $area . '\\' . $namespace . '\\' . $action
)
);
if (isset($this->actions[$fullPath])) {
return is_subclass_of($this->actions[$fullPath], $this->actionInterface)
? $this->actions[$fullPath]
: null;
try {
if ($this->validateActionClass($fullPath)) {
return $this->actions[$fullPath];
}
} catch (ReflectionException $e) {
return null;
}

return null;
}

/**
* Validate Action Class
*
* @param string $fullPath
* @return bool
* @throws ReflectionException
*/
private function validateActionClass(string $fullPath): bool
{
if (isset($this->actions[$fullPath])) {
if (!is_subclass_of($this->actions[$fullPath], $this->actionInterface)) {
return false;
}
$reflectionClass = $this->reflectionClassFactory->create($this->actions[$fullPath]);
if ($reflectionClass->isInstantiable()) {
return true;
}
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@

use Magento\Framework\App\ActionInterface;
use Magento\Framework\App\Router\ActionList;
use Magento\Framework\App\Utility\ReflectionClassFactory;
use Magento\Framework\Config\CacheInterface;
use Magento\Framework\Module\Dir\Reader;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use ReflectionClass;

class ActionListTest extends TestCase
{
Expand Down Expand Up @@ -43,12 +45,27 @@ class ActionListTest extends TestCase
*/
private $serializerMock;

/**
* @var MockObject|ReflectionClass
*/
private $reflectionClass;

/**
* @var ReflectionClassFactory|MockObject
*/
private $reflectionClassFactory;

protected function setUp(): void
{
$this->objectManager = new ObjectManager($this);
$this->cacheMock = $this->getMockForAbstractClass(CacheInterface::class);
$this->readerMock = $this->createMock(Reader::class);
$this->serializerMock = $this->getMockForAbstractClass(SerializerInterface::class);
$this->reflectionClass = $this->createStub(ReflectionClass::class);
$this->reflectionClassFactory = $this->getMockBuilder(ReflectionClassFactory::class)
->disableOriginalConstructor()
->getMock();
$this->reflectionClassFactory->method('create')->willReturn($this->reflectionClass);
}

public function testConstructActionsCached()
Expand Down Expand Up @@ -89,8 +106,10 @@ public function testConstructActionsNoCached()
* @param string|null $expected
* @dataProvider getDataProvider
*/
public function testGet($module, $area, $namespace, $action, $data, $expected)
public function testGet($module, $area, $namespace, $action, $data, $isInstantiable, $expected)
{
$this->reflectionClass->method('isInstantiable')->willReturn($isInstantiable);

$this->cacheMock->expects($this->once())
->method('load')
->willReturn(false);
Expand All @@ -100,7 +119,12 @@ public function testGet($module, $area, $namespace, $action, $data, $expected)
->method('getActionFiles')
->willReturn($data);
$this->createActionListInstance();
$this->assertEquals($expected, $this->actionList->get($module, $area, $namespace, $action));
$this->assertEquals($expected, $this->actionList->get(
$module,
$area,
$namespace,
$action
));
}

/**
Expand All @@ -123,6 +147,7 @@ public function getDataProvider()
'Namespace',
'Index',
['magento\module\controller\area\namespace\index' => $mockClassName],
true,
$actionClass
],
[
Expand All @@ -131,6 +156,7 @@ public function getDataProvider()
'Namespace',
'Index',
['magento\module\controller\namespace\index' => $mockClassName],
true,
$actionClass
],
[
Expand All @@ -139,6 +165,7 @@ public function getDataProvider()
'Namespace',
'Catch',
['magento\module\controller\area\namespace\catchaction' => $mockClassName],
true,
$actionClass
],
[
Expand All @@ -147,6 +174,7 @@ public function getDataProvider()
'Namespace',
'Index',
['magento\module\controller\area\namespace\index' => 'Not_Exist_Class'],
false,
null
],
[
Expand All @@ -155,6 +183,7 @@ public function getDataProvider()
'Namespace',
'Index',
[],
false,
null
],
[
Expand All @@ -163,6 +192,7 @@ public function getDataProvider()
'adminhtml_product',
'index',
'magento\module\controller\adminhtml\product\index' => '$mockClassName',
false,
null
],
];
Expand All @@ -176,6 +206,7 @@ private function createActionListInstance()
'cache' => $this->cacheMock,
'moduleReader' => $this->readerMock,
'serializer' => $this->serializerMock,
'reflectionClassFactory' => $this->reflectionClassFactory
]
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

declare(strict_types=1);

namespace Magento\Framework\App\Utility;

use ReflectionClass;
use ReflectionException;

/**
* Factory for \ReflectionClass
*/
class ReflectionClassFactory
{
/**
* Create a reflection class object
*
* @param object|string $objectOrClass
*
* @return ReflectionClass
* @throws ReflectionException
*/
public function create($objectOrClass): ReflectionClass
{
return new ReflectionClass($objectOrClass);
}
}
3 changes: 2 additions & 1 deletion setup/src/Magento/Setup/Validator/DbValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ public function checkDatabaseConnectionWithDriverOptions(
private function checkDatabaseName(\Magento\Framework\DB\Adapter\AdapterInterface $connection, $dbName)
{
try {
$connection->query("SHOW TABLES FROM $dbName")->fetchAll(\PDO::FETCH_COLUMN, 0);
$query = sprintf("SHOW TABLES FROM `%s`", $dbName);
$connection->query($query)->fetchAll(\PDO::FETCH_COLUMN, 0);
return true;
} catch (\Exception $e) {
throw new \Magento\Setup\Exception(
Expand Down

0 comments on commit 5d2f685

Please sign in to comment.