ModuleInstaller   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 104
Duplicated Lines 0 %

Importance

Changes 5
Bugs 1 Features 0
Metric Value
wmc 8
eloc 52
c 5
b 1
f 0
dl 0
loc 104
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getInstallPath() 0 3 1
B getPackageBasePath() 0 73 6
A supports() 0 3 1
1
<?php
2
3
namespace SimpleSAML\Composer;
4
5
use Composer\Package\PackageInterface;
6
use Composer\Installer\LibraryInstaller;
7
use InvalidArgumentException;
8
use SimpleSAML\Assert\Assert;
9
10
use function in_array;
11
use function is_string;
12
use function mb_strtolower;
13
use function preg_match;
14
use function sprintf;
15
16
class ModuleInstaller extends LibraryInstaller
17
{
18
    /** @var string */
19
    public const MIXED_CASE = 'ssp-mixedcase-module-name';
20
21
    /** @var array */
22
    public const SUPPORTED = ['simplesamlphp-assets', 'simplesamlphp-module'];
23
24
25
    /**
26
     * {@inheritDoc}
27
     */
28
    public function getInstallPath(PackageInterface $package)
29
    {
30
        return $this->getPackageBasePath($package);
31
    }
32
33
34
    /**
35
     * {@inheritDoc}
36
     */
37
    protected function getPackageBasePath(PackageInterface $package)
38
    {
39
        if ($this->composer->getPackage()->getPrettyName() === 'simplesamlphp/simplesamlphp') {
40
            $ssp_path = ".";
41
        } else {
42
            $ssp_path = $this->composer->getConfig()->get('vendor-dir') . '/simplesamlphp/simplesamlphp';
43
        }
44
45
        $matches = [];
46
        $name = $package->getPrettyName();
47
        if (!preg_match('@^.*/simplesamlphp-(module|assets)-(.+)$@', $name, $matches)) {
48
            throw new InvalidArgumentException(sprintf(
49
                'Unable to install module %s, package name must be on the form "VENDOR/simplesamlphp-(module|assets)-MODULENAME".',
50
                $name,
51
            ));
52
        }
53
54
        Assert::count($matches, 3);
55
        $moduleType = $matches[1];
56
        $moduleDir = $matches[2];
57
58
        Assert::regex(
59
            $moduleDir,
60
            '@^[a-z0-9_.-]*$@',
61
            sprintf(
62
                'Unable to install module %s, module name must only contain characters from a-z, 0-9, "_", "." and "-".',
63
                $name
64
            ),
65
            InvalidArgumentException::class
66
        );
67
68
        Assert::notStartsWith(
69
            $moduleDir,
70
            '.',
71
            sprintf('Unable to install module %s, module name cannot start with ".".', $name),
72
            InvalidArgumentException::class
73
        );
74
75
        /**
76
         * Composer packages are supposed to only contain lowercase letters,
77
         *  but historically many modules have had names in mixed case.
78
         * We must provide a way to handle those. Here we allow the module directory
79
         *  to be overridden with a mixed case name.
80
         */
81
        $extraData = $package->getExtra();
82
        if (isset($extraData[self::MIXED_CASE])) {
83
            $mixedCaseModuleName = $extraData[self::MIXED_CASE];
84
            Assert::string(
85
                $mixedCaseModuleName,
86
                sprintf('Unable to install module %s, "%s" must be a string.', $name, self::MIXED_CASE),
87
                InvalidArgumentException::class
88
            );
89
90
            Assert::same(
91
                mb_strtolower($mixedCaseModuleName, 'utf-8'),
92
                $moduleDir,
93
                sprintf(
94
                    'Unable to install module %s, "%s" must match the package name except that it can contain uppercase letters.',
95
                    $name,
96
                    self::MIXED_CASE
97
                ),
98
                InvalidArgumentException::class
99
            );
100
            $moduleDir = $mixedCaseModuleName;
101
        }
102
103
        switch ($moduleType) {
104
            case 'assets':
105
                return $ssp_path . '/public/assets/' . $moduleDir;
106
            case 'module':
107
                return $ssp_path . '/modules/' . $moduleDir;
108
            default:
109
                throw new InvalidArgumentException(sprintf('Unsupported type: %s', $moduleType));
110
        }
111
    }
112
113
114
    /**
115
     * {@inheritDoc}
116
     */
117
    public function supports(string $packageType)
118
    {
119
        return in_array($packageType, self::SUPPORTED);
120
    }
121
}
122