Completed
Push — develop ( 079422...666963 )
by Tom
14:33 queued 07:36
created

MagentoHelper::splitPathFolders()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 14
rs 9.4286
cc 3
eloc 8
nc 3
nop 1
1
<?php
2
3
namespace N98\Util\Console\Helper;
4
5
use N98\Magento\Application;
6
use N98\Util\BinaryString;
7
use RuntimeException;
8
use Symfony\Component\Console\Helper\Helper as AbstractHelper;
9
use Symfony\Component\Console\Input\ArgvInput;
10
use Symfony\Component\Console\Output\ConsoleOutput;
11
use Symfony\Component\Finder\Finder;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Symfony\Component\Console\Input\InputInterface;
14
15
/**
16
 * Class MagentoHelper
17
 *
18
 * @package N98\Util\Console\Helper
19
 */
20
class MagentoHelper extends AbstractHelper
21
{
22
    /**
23
     * @var string
24
     */
25
    protected $_magentoRootFolder = null;
26
27
    /**
28
     * @var int
29
     */
30
    protected $_magentoMajorVersion = \N98\Magento\Application::MAGENTO_MAJOR_VERSION_1;
31
32
    /**
33
     * @var bool
34
     */
35
    protected $_magentoEnterprise = false;
36
37
    /**
38
     * @var bool
39
     */
40
    protected $_magerunStopFileFound = false;
41
42
    /**
43
     * @var string
44
     */
45
    protected $_magerunStopFileFolder = null;
46
47
    /**
48
     * @var InputInterface
49
     */
50
    protected $input;
51
52
    /**
53
     * @var OutputInterface
54
     */
55
    protected $output;
56
57
    /**
58
     * @var array
59
     */
60
    protected $baseConfig = array();
61
62
    /**
63
     * @var string
64
     */
65
    protected $_customConfigFilename = 'n98-magerun2.yaml';
66
67
    /**
68
     * Returns the canonical name of this helper.
69
     *
70
     * @return string The canonical name
71
     *
72
     * @api
73
     */
74
    public function getName()
75
    {
76
        return 'magento';
77
    }
78
79
    /**
80
     * @param InputInterface $input
1 ignored issue
show
Documentation introduced by
Should the type for parameter $input not be null|InputInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
81
     * @param OutputInterface $output
0 ignored issues
show
Documentation introduced by
Should the type for parameter $output not be null|OutputInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
82
     */
83
    public function __construct(InputInterface $input = null, OutputInterface $output = null)
84
    {
85
        if (null === $input) {
86
            $input = new ArgvInput();
87
        }
88
89
        if (null === $output) {
90
            $output = new ConsoleOutput();
91
        }
92
93
        $this->input = $input;
94
        $this->output = $output;
95
    }
96
97
    /**
98
     * Start Magento detection
99
     *
100
     * @param string $folder
101
     * @param array $subFolders [optional] sub-folders to check
102
     * @return bool
103
     */
104
    public function detect($folder, array $subFolders = array())
105
    {
106
        $folders = $this->splitPathFolders($folder);
107
        $folders = $this->checkMagerunFile($folders);
108
        $folders = $this->checkModman($folders);
109
        $folders = array_merge($folders, $subFolders);
110
111
        foreach (array_reverse($folders) as $searchFolder) {
112
            if (!is_dir($searchFolder) || !is_readable($searchFolder)) {
113
                continue;
114
            }
115
116
            $found = $this->_search($searchFolder);
117
            if ($found) {
118
                return true;
119
            }
120
        }
121
122
        return false;
123
    }
124
125
126
    /**
127
     * @return string
128
     */
129
    public function getRootFolder()
130
    {
131
        return $this->_magentoRootFolder;
132
    }
133
134
    public function getEdition()
135
    {
136
        return $this->_magentoMajorVersion;
137
    }
138
139
    /**
140
     * @return bool
141
     */
142
    public function isEnterpriseEdition()
143
    {
144
        return $this->_magentoEnterprise;
145
    }
146
147
    /**
148
     * @return int
149
     */
150
    public function getMajorVersion()
151
    {
152
        return $this->_magentoMajorVersion;
153
    }
154
155
    /**
156
     * @return boolean
157
     */
158
    public function isMagerunStopFileFound()
159
    {
160
        return $this->_magerunStopFileFound;
161
    }
162
163
    /**
164
     * @return string
165
     */
166
    public function getMagerunStopFileFolder()
167
    {
168
        return $this->_magerunStopFileFolder;
169
    }
170
171
    /**
172
     * @param string $folder
173
     *
174
     * @return array
175
     */
176
    protected function splitPathFolders($folder)
177
    {
178
        $folders = array();
179
180
        $folderParts = explode(DIRECTORY_SEPARATOR, $folder);
181
        foreach ($folderParts as $key => $part) {
182
            $explodedFolder = implode(DIRECTORY_SEPARATOR, array_slice($folderParts, 0, $key + 1));
183
            if ($explodedFolder !== '') {
184
                $folders[] = $explodedFolder;
185
            }
186
        }
187
188
        return $folders;
189
    }
190
191
    /**
192
     * Check for modman file and .basedir
193
     *
194
     * @param array $folders
195
     *
196
     * @return array
197
     */
198
    protected function checkModman(array $folders)
199
    {
200
        foreach (array_reverse($folders) as $searchFolder) {
201 View Code Duplication
            if (!is_readable($searchFolder)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
202
                if (OutputInterface::VERBOSITY_DEBUG <= $this->output->getVerbosity()) {
203
                    $this->output->writeln(
204
                        '<debug>Folder <info>' . $searchFolder . '</info> is not readable. Skip.</debug>'
205
                    );
206
                }
207
                continue;
208
            }
209
210
            $finder = Finder::create();
211
            $finder
212
                ->files()
213
                ->ignoreUnreadableDirs(true)
214
                ->depth(0)
215
                ->followLinks()
216
                ->ignoreDotFiles(false)
217
                ->name('.basedir')
218
                ->in($searchFolder);
219
220
            $count = $finder->count();
221
            if ($count > 0) {
222
                $baseFolderContent = trim(file_get_contents($searchFolder . DIRECTORY_SEPARATOR . '.basedir'));
223
                if (OutputInterface::VERBOSITY_DEBUG <= $this->output->getVerbosity()) {
224
                    $this->output->writeln(
225
                        '<debug>Found modman .basedir file with content <info>' . $baseFolderContent . '</info></debug>'
226
                    );
227
                }
228
229
                if (!empty($baseFolderContent)) {
230
                    array_push(
231
                        $folders, $searchFolder . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . $baseFolderContent
232
                    );
233
                }
234
            }
235
        }
236
237
        return $folders;
238
    }
239
240
    /**
241
     * Check for .n98-magerun file
242
     *
243
     * @param array $folders
244
     *
245
     * @return array
246
     */
247
    protected function checkMagerunFile(array $folders)
248
    {
249
        foreach (array_reverse($folders) as $searchFolder) {
250 View Code Duplication
            if (!is_readable($searchFolder)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
251
                if (OutputInterface::VERBOSITY_DEBUG <= $this->output->getVerbosity()) {
252
                    $this->output->writeln(
253
                        '<debug>Folder <info>' . $searchFolder . '</info> is not readable. Skip.</debug>'
254
                    );
255
                }
256
                continue;
257
            }
258
            $finder = Finder::create();
259
            $finder
260
                ->files()
261
                ->ignoreUnreadableDirs(true)
262
                ->depth(0)
263
                ->followLinks()
264
                ->ignoreDotFiles(false)
265
                ->name('.' . $this->_customConfigFilename)
266
                ->in($searchFolder);
267
268
            $count = $finder->count();
269
            if ($count > 0) {
270
                $this->_magerunStopFileFound = true;
271
                $this->_magerunStopFileFolder = $searchFolder;
272
                $magerunFileContent = trim(file_get_contents($searchFolder . DIRECTORY_SEPARATOR . '.n98-magerun2'));
273
                if (OutputInterface::VERBOSITY_DEBUG <= $this->output->getVerbosity()) {
274
                    $this->output->writeln(
275
                        '<debug>Found .n98-magerun2 file with content <info>' . $magerunFileContent . '</info></debug>'
276
                    );
277
                }
278
279
                array_push($folders, $searchFolder . DIRECTORY_SEPARATOR . $magerunFileContent);
280
            }
281
        }
282
283
        return $folders;
284
    }
285
286
    /**
287
     * @param string $searchFolder
288
     *
289
     * @return bool
290
     */
291
    protected function _search($searchFolder)
292
    {
293
        if (OutputInterface::VERBOSITY_DEBUG <= $this->output->getVerbosity()) {
294
            $this->output->writeln('<debug>Search for Magento in folder <info>' . $searchFolder . '</info></debug>');
295
        }
296
297
        if (!is_dir($searchFolder . '/app')) {
298
            return false;
299
        }
300
301
        $finder = Finder::create();
302
        $finder
303
            ->ignoreUnreadableDirs(true)
304
            ->depth(0)
305
            ->followLinks()
306
            ->name('Mage.php')
307
            ->name('bootstrap.php')
308
            ->name('autoload.php')
309
            ->in($searchFolder . '/app');
310
311
        if ($finder->count() > 0) {
312
            $files = iterator_to_array($finder, false);
313
            /* @var $file \SplFileInfo */
314
315
            $hasMageFile = false;
316
            foreach ($files as $file) {
317
                if ($file->getFilename() == 'Mage.php') {
318
                    $hasMageFile = true;
319
                }
320
            }
321
322
            $this->_magentoRootFolder = $searchFolder;
323
324
            // Magento 2 does not have a god class and thus if this file is not there it is version 2
325
            if ($hasMageFile == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
326
                $this->_magentoMajorVersion = Application::MAGENTO_MAJOR_VERSION_2;
327
            } else {
328
                $this->_magentoMajorVersion = Application::MAGENTO_MAJOR_VERSION_1;
329
            }
330
331
            if (OutputInterface::VERBOSITY_DEBUG <= $this->output->getVerbosity()) {
332
                $this->output->writeln(
333
                    '<debug>Found Magento in folder <info>' . $this->_magentoRootFolder . '</info></debug>'
334
                );
335
            }
336
337
            return true;
338
        }
339
340
        return false;
341
    }
342
343
    /**
344
     * @return array
345
     * @throws RuntimeException
346
     */
347
    public function getBaseConfig()
348
    {
349
        if (!$this->baseConfig) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->baseConfig of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
350
            $this->initBaseConfig();
351
        }
352
353
        return $this->baseConfig;
354
    }
355
356
    private function initBaseConfig()
357
    {
358
        $this->baseConfig = [];
359
360
        $application = $this->getApplication();
361
362
        $configFiles = [
363
            'app/etc/config.php',
364
            'app/etc/env.php'
365
        ];
366
367
        foreach ($configFiles as $configFileName) {
368
            $this->addBaseConfig($application->getMagentoRootFolder(), $configFileName);
369
        }
370
    }
371
372
    /**
373
     * private getter for application that has magento detected
374
     *
375
     * @return Application|\Symfony\Component\Console\Application
376
     */
377
    private function getApplication()
378
    {
379
        $command = $this->getHelperSet()->getCommand();
380
        if ($command == null) {
381
            $application = new Application();
382
        } else {
383
            $application = $command->getApplication(); /* @var $application Application */
384
        }
385
        $application->detectMagento();
386
387
        return $application;
388
    }
389
390
    private function addBaseConfig($root, $configFileName)
391
    {
392
        $configFile = $root . '/' . $configFileName;
393
        if (!(is_file($configFile) && is_readable($configFile))) {
394
            throw new RuntimeException(sprintf('%s is not readable', $configFileName));
395
        }
396
397
        $config = @include $configFile;
398
399
        if (!is_array($config)) {
400
            throw new RuntimeException(sprintf('%s is corrupted. Please check it.', $configFileName));
401
        }
402
403
        $this->baseConfig = array_merge($this->baseConfig, $config);
404
    }
405
}
406