Completed
Push — 3.0 ( ac6a55...46111f )
by Daniel
02:19
created

Plugin::writeDebug()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.0416
Metric Value
dl 0
loc 10
ccs 5
cts 6
cp 0.8333
rs 9.4285
cc 3
eloc 5
nc 3
nop 2
crap 3.0416
1
<?php
2
/**
3
 *
4
 *
5
 *
6
 *
7
 */
8
9
namespace MagentoHackathon\Composer\Magento;
10
11
use Composer\Config;
12
use Composer\Installer;
13
use Composer\Package\AliasPackage;
14
use Composer\Script\Event;
15
use MagentoHackathon\Composer\Helper;
16
use MagentoHackathon\Composer\Magento\Event\EventManager;
17
use MagentoHackathon\Composer\Magento\Event\PackageDeployEvent;
18
use MagentoHackathon\Composer\Magento\Factory\DeploystrategyFactory;
19
use MagentoHackathon\Composer\Magento\Factory\EntryFactory;
20
use MagentoHackathon\Composer\Magento\Factory\ParserFactory;
21
use MagentoHackathon\Composer\Magento\Factory\PathTranslationParserFactory;
22
use MagentoHackathon\Composer\Magento\Patcher\Bootstrap;
23
use MagentoHackathon\Composer\Magento\Repository\InstalledPackageFileSystemRepository;
24
use MagentoHackathon\Composer\Magento\UnInstallStrategy\UnInstallStrategy;
25
use MagentoHackathon\Composer\Magento\Factory\InstallStrategyFactory;
26
use RecursiveDirectoryIterator;
27
use RecursiveIteratorIterator;
28
use Composer\Composer;
29
use Composer\IO\IOInterface;
30
use Composer\Package\PackageInterface;
31
use Composer\Plugin\PluginInterface;
32
use Composer\EventDispatcher\EventSubscriberInterface;
33
use Composer\Script\ScriptEvents;
34
use Composer\Util\Filesystem;
35
use Symfony\Component\Process\Process;
36
37
class Plugin implements PluginInterface, EventSubscriberInterface
38
{
39
    /**
40
     * The type of packages this plugin supports
41
     */
42
    const PACKAGE_TYPE = 'magento-module';
43
44
    const VENDOR_DIR_KEY = 'vendor-dir';
45
46
    const BIN_DIR_KEY = 'bin-dir';
47
48
    const THESEER_AUTOLOAD_EXEC_BIN_PATH = '/phpab';
49
50
    const THESEER_AUTOLOAD_EXEC_REL_PATH = '/theseer/autoload/composer/bin/phpab';
51
52
    /**
53
     * @var IOInterface
54
     */
55
    protected $io;
56
57
    /**
58
     * @var ProjectConfig
59
     */
60
    protected $config;
61
62
    /**
63
     * @var DeployManager
64
     */
65
    protected $deployManager;
66
67
    /**
68
     * @var Composer
69
     */
70
    protected $composer;
71
72
    /**
73
     * @var Filesystem
74
     */
75
    protected $filesystem;
76
77
    /**
78
     * @var EntryFactory
79
     */
80
    protected $entryFactory;
81
82
    /**
83
     * @var EventManager
84
     */
85
    private $eventManager;
86
87
    /**
88
     * @var ModuleManager
89
     */
90
    private $moduleManager;
91
92
    /**
93
     * init the DeployManager
94
     *
95
     * @param Composer    $composer
96
     * @param IOInterface $io
97
     */
98 5
    protected function initDeployManager(Composer $composer, IOInterface $io, EventManager $eventManager)
0 ignored issues
show
Unused Code introduced by
The parameter $io is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
99
    {
100 5
        $this->deployManager = new DeployManager($eventManager);
101 5
        $this->deployManager->setSortPriority($this->getSortPriority($composer));
102
103 5
        $this->applyEvents($eventManager);
104 5
    }
105
106 5
    protected function applyEvents(EventManager $eventManager)
107
    {
108
109 5
        if ($this->config->hasAutoAppendGitignore()) {
110 1
            $gitIgnoreLocation = sprintf('%s/.gitignore', $this->config->getMagentoRootDir());
111 1
            $gitIgnore = new GitIgnoreListener(new GitIgnore($gitIgnoreLocation));
112
113 1
            $eventManager->listen('post-package-deploy', [$gitIgnore, 'addNewInstalledFiles']);
114 1
            $eventManager->listen('post-package-uninstall', [$gitIgnore, 'removeUnInstalledFiles']);
115
        }
116
117 5
        $io = $this->io;
118 5
        if ($this->io->isDebug()) {
119
            $eventManager->listen('pre-package-deploy', function (PackageDeployEvent $event) use ($io) {
120
                $io->write('Start magento deploy for ' . $event->getDeployEntry()->getPackageName());
121 1
            });
122
        }
123 5
    }
124
125
    /**
126
     * get Sort Priority from extra Config
127
     *
128
     * @param \Composer\Composer $composer
129
     *
130
     * @return array
131
     */
132 5
    private function getSortPriority(Composer $composer)
133
    {
134 5
        $extra = $composer->getPackage()->getExtra();
135
136 5
        return isset($extra[ProjectConfig::SORT_PRIORITY_KEY])
137
            ? $extra[ProjectConfig::SORT_PRIORITY_KEY]
138 5
            : array();
139
    }
140
141
    /**
142
     * Apply plugin modifications to composer
143
     *
144
     * @param Composer    $composer
145
     * @param IOInterface $io
146
     */
147 5
    public function activate(Composer $composer, IOInterface $io)
148
    {
149 5
        $this->io = $io;
150 5
        $this->composer = $composer;
151
152 5
        $this->filesystem = new Filesystem();
153 5
        $this->config = new ProjectConfig($composer->getPackage()->getExtra(), $composer->getConfig()->all());
154
155 5
        if (!$this->config->skipSuggestComposerRepositories()) {
156 4
            $this->suggestComposerRepositories();
157
        }
158
159 5
        $this->entryFactory = new EntryFactory(
160 5
            $this->config,
161 5
            new DeploystrategyFactory($this->config),
162 5
            new PathTranslationParserFactory(new ParserFactory($this->config), $this->config)
163
        );
164
165 5
        $this->initDeployManager($composer, $io, $this->getEventManager());
166 5
        $this->writeDebug('activate magento plugin');
167 5
    }
168
169
    /**
170
     * Returns an array of event names this subscriber wants to listen to.
171
     *
172
     * The array keys are event names and the value can be:
173
     *
174
     * * The method name to call (priority defaults to 0)
175
     * * An array composed of the method name to call and the priority
176
     * * An array of arrays composed of the method names to call and respective
177
     *   priorities, or 0 if unset
178
     *
179
     * For instance:
180
     *
181
     * * array('eventName' => 'methodName')
182
     * * array('eventName' => array('methodName', $priority))
183
     * * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
184
     *
185
     * @return array The event names to listen to
186
     */
187
    public static function getSubscribedEvents()
188
    {
189
        return array(
190
            ScriptEvents::POST_INSTALL_CMD => array(
191
                array('onNewCodeEvent', 0),
192
            ),
193
            ScriptEvents::POST_UPDATE_CMD  => array(
194
                array('onNewCodeEvent', 0),
195
            ),
196
        );
197
    }
198
199
    /**
200
     * event listener is named this way, as it listens for events leading to changed code files
201
     *
202
     * @param Event $event
203
     */
204 2
    public function onNewCodeEvent(Event $event)
205
    {
206
207 2
        $packageTypeToMatch = static::PACKAGE_TYPE;
208 2
        $magentoModules = array_filter(
209 2
            $this->composer->getRepositoryManager()->getLocalRepository()->getPackages(),
210 2
            function (PackageInterface $package) use ($packageTypeToMatch) {
211 2
                if ($package instanceof AliasPackage) {
212 1
                    return false;
213
                }
214 2
                return $package->getType() === $packageTypeToMatch;
215 2
            }
216
        );
217
218 2
        $vendorDir = rtrim($this->composer->getConfig()->get(self::VENDOR_DIR_KEY), '/');
219
220 2
        Helper::initMagentoRootDir(
221 2
            $this->config,
222 2
            $this->io,
223 2
            $this->filesystem,
224
            $vendorDir
225
        );
226
227 2
        $this->applyEvents($this->getEventManager());
228
229 2
        if (in_array('--redeploy', $event->getArguments())) {
230
            $this->writeDebug('remove all deployed modules');
231
            $this->getModuleManager()->updateInstalledPackages(array());
232
        }
233 2
        $this->writeDebug('start magento module deploy via moduleManager');
234 2
        $this->getModuleManager()->updateInstalledPackages($magentoModules);
235 2
        $this->deployLibraries();
236
237 2
        $patcher = Bootstrap::fromConfig($this->config);
238 2
        $patcher->setIo($this->io);
239
        try {
240 2
            $patcher->patch();
241 2
        } catch (\DomainException $e) {
242 2
            $this->io->write('<comment>'.$e->getMessage().'</comment>');
243
        }
244 2
    }
245
246
    /**
247
     * test configured repositories and give message about adding recommended ones
248
     */
249 4
    protected function suggestComposerRepositories()
250
    {
251 4
        $foundFiregento = false;
252 4
        $foundMagento   = false;
253
254 4
        foreach ($this->config->getComposerRepositories() as $repository) {
255
            if (!isset($repository["type"]) || $repository["type"] !== "composer") {
256
                continue;
257
            }
258
            if (strpos($repository["url"], "packages.firegento.com") !== false) {
259
                $foundFiregento = true;
260
            }
261
            if (strpos($repository["url"], "packages.magento.com") !== false) {
262
                $foundMagento = true;
263
            }
264
        };
265 4
        $message1 = "<comment>you may want to add the %s repository to composer.</comment>";
266 4
        $message2 = "<comment>add it with:</comment> composer.phar config -g repositories.%s composer %s";
267 4
        if (!$foundFiregento) {
268 4
            $this->io->write(sprintf($message1, 'packages.firegento.com'));
269 4
            $this->io->write(sprintf($message2, 'firegento', 'http://packages.firegento.com'));
270
        }
271 4
        if (!$foundMagento) {
272 4
            $this->io->write(sprintf($message1, 'packages.magento.com'));
273 4
            $this->io->write(sprintf($message2, 'magento', 'https?://packages.magento.com'));
274
        }
275
276 4
    }
277
278
    /**
279
     * deploy Libraries
280
     */
281 2
    protected function deployLibraries()
282
    {
283 2
        $packages = $this->composer->getRepositoryManager()->getLocalRepository()->getPackages();
284 2
        $autoloadDirectories = array();
285
286 2
        $libraryPath = $this->config->getLibraryPath();
287
288 2
        if ($libraryPath === null) {
289 2
            $this->writeDebug('jump over deployLibraries as no Magento libraryPath is set');
290
291 2
            return;
292
        }
293
294
        $vendorDir = rtrim($this->composer->getConfig()->get(self::VENDOR_DIR_KEY), '/');
295
296
        $this->filesystem->removeDirectory($libraryPath);
297
        $this->filesystem->ensureDirectoryExists($libraryPath);
298
299
        foreach ($packages as $package) {
300
            /** @var PackageInterface $package */
301
            $packageConfig = $this->config->getLibraryConfigByPackagename($package->getName());
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $packageConfig is correct as $this->config->getLibrar...me($package->getName()) (which targets MagentoHackathon\Compose...ryConfigByPackagename()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
302
            if ($packageConfig === null) {
303
                continue;
304
            }
305
            if (!isset($packageConfig['autoload'])) {
306
                $packageConfig['autoload'] = array('/');
307
            }
308
            foreach ($packageConfig['autoload'] as $path) {
309
                $autoloadDirectories[] = $libraryPath . '/' . $package->getName() . "/" . $path;
310
            }
311
            $this->writeDebug(sprintf('Magento deployLibraries executed for %s', $package->getName()));
312
313
            $libraryTargetPath = $libraryPath . '/' . $package->getName();
314
            $this->filesystem->removeDirectory($libraryTargetPath);
315
            $this->filesystem->ensureDirectoryExists($libraryTargetPath);
316
            $this->copyRecursive($vendorDir . '/' . $package->getPrettyName(), $libraryTargetPath);
317
        }
318
319
        if (false !== ($executable = $this->getTheseerAutoloadExecutable())) {
320
            $this->writeDebug('Magento deployLibraries executes autoload generator');
321
322
            $params = $this->getTheseerAutoloadParams($libraryPath, $autoloadDirectories);
323
324
            $process = new Process($executable . $params);
325
            $process->run();
326
        }
327
    }
328
329
    /**
330
     * return the autoload generator binary path or false if not found
331
     *
332
     * @return bool|string
333
     */
334
    protected function getTheseerAutoloadExecutable()
335
    {
336
        $executable = $this->composer->getConfig()->get(self::BIN_DIR_KEY)
337
            . self::THESEER_AUTOLOAD_EXEC_BIN_PATH;
338
339
        if (!file_exists($executable)) {
340
            $executable = $this->composer->getConfig()->get(self::VENDOR_DIR_KEY)
341
                . self::THESEER_AUTOLOAD_EXEC_REL_PATH;
342
        }
343
344
        if (!file_exists($executable)) {
345
            $this->writeDebug(
346
                'Magento deployLibraries autoload generator not available, you should require "theseer/autoload"',
347
                $executable
348
            );
349
350
            return false;
351
        }
352
353
        return $executable;
354
    }
355
356
    /**
357
     * get Theseer Autoload Generator Params
358
     *
359
     * @param string $libraryPath
360
     * @param array  $autoloadDirectories
361
     *
362
     * @return string
363
     */
364
    protected function getTheseerAutoloadParams($libraryPath, $autoloadDirectories)
365
    {
366
        // @todo  --blacklist 'test\\\\*'
367
        return " -b {$libraryPath} -o {$libraryPath}/autoload.php  " . implode(' ', $autoloadDirectories);
368
    }
369
370
    /**
371
     * Copy then delete is a non-atomic version of {@link rename}.
372
     *
373
     * Some systems can't rename and also don't have proc_open,
374
     * which requires this solution.
375
     *
376
     * copied from \Composer\Util\Filesystem::copyThenRemove and removed the remove part
377
     *
378
     * @param string $source
379
     * @param string $target
380
     */
381
    protected function copyRecursive($source, $target)
382
    {
383
        $it = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS);
384
        $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::SELF_FIRST);
385
        $this->filesystem->ensureDirectoryExists($target);
386
387
        foreach ($ri as $file) {
388
            $targetPath = $target . DIRECTORY_SEPARATOR . $ri->getSubPathName();
389
            if ($file->isDir()) {
390
                $this->filesystem->ensureDirectoryExists($targetPath);
391
            } else {
392
                copy($file->getPathname(), $targetPath);
393
            }
394
        }
395
    }
396
397
    /**
398
     * print Debug Message
399
     *
400
     * @param $message
401
     */
402 5
    private function writeDebug($message, $varDump = null)
403
    {
404 5
        if ($this->io->isDebug()) {
405 1
            $this->io->write($message);
406
407 1
            if (!is_null($varDump)) {
408
                var_dump($varDump);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($varDump); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
409
            }
410
        }
411 5
    }
412
413
    /**
414
     * @param PackageInterface $package
415
     * @return string
416
     */
417
    public function getPackageInstallPath(PackageInterface $package)
418
    {
419
        $vendorDir = realpath(rtrim($this->composer->getConfig()->get('vendor-dir'), '/'));
420
        return sprintf('%s/%s', $vendorDir, $package->getPrettyName());
421
    }
422
423
    /**
424
     * @return EventManager
425
     */
426
    protected function getEventManager()
427
    {
428
        if (null === $this->eventManager) {
429
            $this->eventManager = new EventManager;
430
        }
431
432
        return $this->eventManager;
433
    }
434
435
    /**
436
     * @return ModuleManager
437
     */
438
    protected function getModuleManager()
439
    {
440
        if (null === $this->moduleManager) {
441
            $this->moduleManager = new ModuleManager(
442
                new InstalledPackageFileSystemRepository(
443
                    rtrim($this->composer->getConfig()->get(self::VENDOR_DIR_KEY), '/') . '/installed.json',
444
                    new InstalledPackageDumper()
445
                ),
446
                $this->getEventManager(),
447
                $this->config,
448
                new UnInstallStrategy($this->filesystem, $this->config->getMagentoRootDir()),
449
                new InstallStrategyFactory($this->config, new ParserFactory($this->config))
450
            );
451
        }
452
453
        return $this->moduleManager;
454
    }
455
}
456