Skip to content

Commit ea57b46

Browse files
MAGETWO-68928: Fatal error after disabling module
1 parent 938313e commit ea57b46

File tree

4 files changed

+128
-92
lines changed

4 files changed

+128
-92
lines changed

lib/internal/Magento/Framework/Console/Cli.php

Lines changed: 12 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use Magento\Framework\App\ProductMetadata;
1212
use Magento\Framework\App\State;
1313
use Magento\Framework\Composer\ComposerJsonFinder;
14-
use Magento\Framework\Exception\FileSystemException;
14+
use Magento\Framework\Console\Exception\GenerationDirectoryAccessException;
1515
use Magento\Framework\Filesystem\Driver\File;
1616
use Magento\Framework\ObjectManagerInterface;
1717
use Magento\Framework\Shell\ComplexParameter;
@@ -91,20 +91,13 @@ public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
9191
/**
9292
* {@inheritdoc}
9393
*
94-
* @throws \Exception the exception in case of unexpected error
94+
* @throws \Exception The exception in case of unexpected error
9595
*/
9696
public function doRun(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
9797
{
9898
$exitCode = parent::doRun($input, $output);
9999

100100
if ($this->initException) {
101-
$output->writeln(
102-
"<error>We're sorry, an error occurred. Try clearing the cache and code generation directories. "
103-
. "By default, they are: " . $this->getDefaultDirectoryPath(DirectoryList::CACHE) . ", "
104-
. $this->getDefaultDirectoryPath(DirectoryList::GENERATED_METADATA) . ", "
105-
. $this->getDefaultDirectoryPath(DirectoryList::GENERATED_CODE) . ", and var/page_cache.</error>"
106-
);
107-
108101
throw $this->initException;
109102
}
110103

@@ -154,24 +147,17 @@ protected function getApplicationCommands()
154147
* Object Manager initialization.
155148
*
156149
* @return void
157-
* @SuppressWarnings(PHPMD.ExitExpression)
158150
*/
159151
private function initObjectManager()
160152
{
161-
try {
162-
$params = (new ComplexParameter(self::INPUT_KEY_BOOTSTRAP))->mergeFromArgv($_SERVER, $_SERVER);
163-
$params[Bootstrap::PARAM_REQUIRE_MAINTENANCE] = null;
164-
165-
$this->objectManager = Bootstrap::create(BP, $params)->getObjectManager();
153+
$params = (new ComplexParameter(self::INPUT_KEY_BOOTSTRAP))->mergeFromArgv($_SERVER, $_SERVER);
154+
$params[Bootstrap::PARAM_REQUIRE_MAINTENANCE] = null;
166155

167-
/** @var ObjectManagerProvider $omProvider */
168-
$omProvider = $this->serviceManager->get(ObjectManagerProvider::class);
169-
$omProvider->setObjectManager($this->objectManager);
170-
} catch (FileSystemException $exception) {
171-
$this->writeGenerationDirectoryReadError();
156+
$this->objectManager = Bootstrap::create(BP, $params)->getObjectManager();
172157

173-
exit(static::RETURN_FAILURE);
174-
}
158+
/** @var ObjectManagerProvider $omProvider */
159+
$omProvider = $this->serviceManager->get(ObjectManagerProvider::class);
160+
$omProvider->setObjectManager($this->objectManager);
175161
}
176162

177163
/**
@@ -182,7 +168,7 @@ private function initObjectManager()
182168
* developer - application will be terminated
183169
*
184170
* @return void
185-
* @SuppressWarnings(PHPMD.ExitExpression)
171+
* @throws GenerationDirectoryAccessException If generation directory is read-only in developer mode
186172
*/
187173
private function assertGenerationPermissions()
188174
{
@@ -197,17 +183,15 @@ private function assertGenerationPermissions()
197183
if ($state->getMode() !== State::MODE_PRODUCTION
198184
&& !$generationDirectoryAccess->check()
199185
) {
200-
$this->writeGenerationDirectoryReadError();
201-
202-
exit(static::RETURN_FAILURE);
186+
throw new GenerationDirectoryAccessException();
203187
}
204188
}
205189

206190
/**
207191
* Checks whether compiler is being prepared.
208192
*
209193
* @return void
210-
* @SuppressWarnings(PHPMD.ExitExpression)
194+
* @throws GenerationDirectoryAccessException If generation directory is read-only
211195
*/
212196
private function assertCompilerPreparation()
213197
{
@@ -222,33 +206,10 @@ private function assertCompilerPreparation()
222206
new File()
223207
);
224208

225-
try {
226-
$compilerPreparation->handleCompilerEnvironment();
227-
} catch (FileSystemException $e) {
228-
$this->writeGenerationDirectoryReadError();
229-
230-
exit(static::RETURN_FAILURE);
231-
}
209+
$compilerPreparation->handleCompilerEnvironment();
232210
}
233211
}
234212

235-
/**
236-
* Writes read error to console.
237-
*
238-
* @return void
239-
*/
240-
private function writeGenerationDirectoryReadError()
241-
{
242-
$output = new \Symfony\Component\Console\Output\ConsoleOutput();
243-
$output->writeln(
244-
'<error>'
245-
. 'Command line user does not have read and write permissions on '
246-
. $this->getDefaultDirectoryPath(DirectoryList::GENERATED_CODE) . ' directory. '
247-
. 'Please address this issue before using Magento command line.'
248-
. '</error>'
249-
);
250-
}
251-
252213
/**
253214
* Retrieves vendor commands.
254215
*
@@ -270,22 +231,4 @@ protected function getVendorCommands($objectManager)
270231

271232
return $commands;
272233
}
273-
274-
/**
275-
* Get default directory path by code
276-
*
277-
* @param string $code
278-
* @return string
279-
*/
280-
private function getDefaultDirectoryPath($code)
281-
{
282-
$config = DirectoryList::getDefaultConfig();
283-
$result = '';
284-
285-
if (isset($config[$code][DirectoryList::PATH])) {
286-
$result = $config[$code][DirectoryList::PATH];
287-
}
288-
289-
return $result;
290-
}
291234
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Framework\Console\Exception;
7+
8+
use Magento\Framework\App\Filesystem\DirectoryList;
9+
use Magento\Framework\Exception\FileSystemException;
10+
use Magento\Framework\Phrase;
11+
12+
class GenerationDirectoryAccessException extends FileSystemException
13+
{
14+
/**
15+
* @inheritdoc
16+
*/
17+
public function __construct(Phrase $phrase = null, \Exception $cause = null, $code = 0)
18+
{
19+
$phrase = $phrase ?: new Phrase(
20+
'Command line user does not have read and write permissions on '
21+
. $this->getDefaultDirectoryPath(DirectoryList::GENERATED_CODE) . ' directory. '
22+
. 'Please address this issue before using Magento command line.'
23+
);
24+
25+
parent::__construct($phrase, $cause, $code);
26+
}
27+
28+
/**
29+
* Get default directory path by code
30+
*
31+
* @param string $code
32+
* @return string
33+
*/
34+
private function getDefaultDirectoryPath($code)
35+
{
36+
$config = DirectoryList::getDefaultConfig();
37+
$result = '';
38+
39+
if (isset($config[$code][DirectoryList::PATH])) {
40+
$result = $config[$code][DirectoryList::PATH];
41+
}
42+
43+
return $result;
44+
}
45+
}

lib/internal/Magento/Framework/Console/GenerationDirectoryAccess.php

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use Magento\Framework\App\Bootstrap;
99
use Magento\Framework\App\Filesystem\DirectoryList;
10+
use Magento\Framework\Filesystem\DriverInterface;
1011
use Magento\Framework\Filesystem\DriverPool;
1112
use Magento\Framework\Filesystem\File\WriteFactory;
1213
use Magento\Framework\Filesystem\Directory\Write;
@@ -44,33 +45,63 @@ public function check()
4445
? $initParams[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS]
4546
: [];
4647
$directoryList = new DirectoryList(BP, $filesystemDirPaths);
47-
$generationDirectoryPath = $directoryList->getPath(DirectoryList::GENERATED_CODE);
4848
$driverPool = new DriverPool();
4949
$fileWriteFactory = new WriteFactory($driverPool);
5050
/** @var \Magento\Framework\Filesystem\DriverInterface $driver */
5151
$driver = $driverPool->getDriver(DriverPool::FILE);
52-
$directoryWrite = new Write($fileWriteFactory, $driver, $generationDirectoryPath);
53-
if ($directoryWrite->isExist()) {
54-
if ($directoryWrite->isDirectory()
55-
|| $directoryWrite->isReadable()
56-
) {
57-
try {
58-
$probeFilePath = $generationDirectoryPath . DIRECTORY_SEPARATOR . uniqid(mt_rand()).'tmp';
59-
$fileWriteFactory->create($probeFilePath, DriverPool::FILE, 'w');
60-
$driver->deleteFile($probeFilePath);
61-
} catch (\Exception $e) {
62-
return false;
63-
}
64-
} else {
52+
53+
$generationDirs = [
54+
DirectoryList::GENERATED,
55+
DirectoryList::GENERATED_CODE,
56+
DirectoryList::GENERATED_METADATA
57+
];
58+
59+
foreach ($generationDirs as $generationDirectory) {
60+
$directoryPath = $directoryList->getPath($generationDirectory);
61+
62+
if (!$this->checkDirectory($fileWriteFactory, $driver, $directoryPath)) {
6563
return false;
6664
}
67-
} else {
65+
}
66+
67+
return true;
68+
}
69+
70+
/**
71+
* Checks the permissions to specific directory
72+
*
73+
* @param WriteFactory $fileWriteFactory The factory of file writers
74+
* @param DriverInterface $driver The driver
75+
* @param string $directoryPath The directory path
76+
* @return bool
77+
*/
78+
private function checkDirectory(
79+
WriteFactory $fileWriteFactory,
80+
DriverInterface $driver,
81+
$directoryPath
82+
) {
83+
$directoryWrite = new Write($fileWriteFactory, $driver, $directoryPath);
84+
85+
if (!$directoryWrite->isExist()) {
6886
try {
6987
$directoryWrite->create();
7088
} catch (\Exception $e) {
7189
return false;
7290
}
7391
}
92+
93+
if (!$directoryWrite->isDirectory() || !$directoryWrite->isReadable()) {
94+
return false;
95+
}
96+
97+
try {
98+
$probeFilePath = $directoryPath . DIRECTORY_SEPARATOR . uniqid(mt_rand()) . 'tmp';
99+
$fileWriteFactory->create($probeFilePath, DriverPool::FILE, 'w');
100+
$driver->deleteFile($probeFilePath);
101+
} catch (\Exception $e) {
102+
return false;
103+
}
104+
74105
return true;
75106
}
76107
}

setup/src/Magento/Setup/Console/CompilerPreparation.php

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use Magento\Framework\App\Bootstrap;
99
use Magento\Framework\App\Filesystem\DirectoryList;
10+
use Magento\Framework\Console\Exception\GenerationDirectoryAccessException;
1011
use Magento\Framework\Console\GenerationDirectoryAccess;
1112
use Magento\Framework\Exception\FileSystemException;
1213
use Magento\Framework\Filesystem\Driver\File;
@@ -59,30 +60,30 @@ public function __construct(
5960
/**
6061
* Determine whether a CLI command is for compilation, and if so, clear the directory.
6162
*
62-
* @throws FileSystemException if generation directory is read-only
63+
* @throws GenerationDirectoryAccessException If generation directory is read-only
6364
* @return void
6465
*/
6566
public function handleCompilerEnvironment()
6667
{
67-
$compilationCommands = [DiCompileCommand::NAME];
68+
$compilationCommands = $this->getCompilerInvalidationCommands();
6869
$cmdName = $this->input->getFirstArgument();
6970
$isHelpOption = $this->input->hasParameterOption('--help') || $this->input->hasParameterOption('-h');
7071
if (!in_array($cmdName, $compilationCommands) || $isHelpOption) {
7172
return;
7273
}
73-
$compileDirList = [];
74+
7475
$mageInitParams = $this->serviceManager->get(InitParamListener::BOOTSTRAP_PARAM);
7576
$mageDirs = isset($mageInitParams[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS])
7677
? $mageInitParams[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS]
7778
: [];
7879
$directoryList = new DirectoryList(BP, $mageDirs);
79-
$compileDirList[] = $directoryList->getPath(DirectoryList::GENERATED_CODE);
80-
$compileDirList[] = $directoryList->getPath(DirectoryList::GENERATED_METADATA);
80+
$compileDirList = [
81+
$directoryList->getPath(DirectoryList::GENERATED_CODE),
82+
$directoryList->getPath(DirectoryList::GENERATED_METADATA),
83+
];
8184

8285
if (!$this->getGenerationDirectoryAccess()->check()) {
83-
throw new FileSystemException(
84-
new Phrase('Generation directory can not be written.')
85-
);
86+
throw new GenerationDirectoryAccessException();
8687
}
8788

8889
foreach ($compileDirList as $compileDir) {
@@ -92,6 +93,22 @@ public function handleCompilerEnvironment()
9293
}
9394
}
9495

96+
/**
97+
* Retrieves command list with commands which invalidates compiler
98+
*
99+
* @return array
100+
*/
101+
private function getCompilerInvalidationCommands()
102+
{
103+
return [
104+
DiCompileCommand::NAME,
105+
'module:disable',
106+
'module:enable',
107+
'module:uninstall',
108+
'deploy:mode:set'
109+
];
110+
}
111+
95112
/**
96113
* Retrieves generation directory access checker.
97114
*

0 commit comments

Comments
 (0)