ModuleInstaller::getInstallPath()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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,'
50
                . ' package name must be in the form "VENDOR/simplesamlphp-(module|assets)-MODULENAME".',
51
                $name,
52
            ));
53
        }
54
55
        Assert::count($matches, 3);
56
        $moduleType = $matches[1];
57
        $moduleDir = $matches[2];
58
59
        Assert::regex(
60
            $moduleDir,
61
            '@^[a-z0-9_.-]*$@',
62
            sprintf(
63
                'Unable to install module %s,'
64
                . ' module name must only contain characters from a-z, 0-9, "_", "." and "-".',
65
                $name
66
            ),
67
            InvalidArgumentException::class
68
        );
69
70
        Assert::notStartsWith(
71
            $moduleDir,
72
            '.',
73
            sprintf('Unable to install module %s, module name cannot start with ".".', $name),
74
            InvalidArgumentException::class
75
        );
76
77
        /**
78
         * Composer packages are supposed to only contain lowercase letters,
79
         *  but historically many modules have had names in mixed case.
80
         * We must provide a way to handle those. Here we allow the module directory
81
         *  to be overridden with a mixed case name.
82
         */
83
        $extraData = $package->getExtra();
84
        if (isset($extraData[self::MIXED_CASE])) {
85
            $mixedCaseModuleName = $extraData[self::MIXED_CASE];
86
            Assert::string(
87
                $mixedCaseModuleName,
88
                sprintf('Unable to install module %s, "%s" must be a string.', $name, self::MIXED_CASE),
89
                InvalidArgumentException::class
90
            );
91
92
            Assert::same(
93
                mb_strtolower($mixedCaseModuleName, 'utf-8'),
94
                $moduleDir,
95
                sprintf(
96
                    'Unable to install module %s,'
97
                    . ' "%s" must match the package name except that it can contain uppercase letters.',
98
                    $name,
99
                    self::MIXED_CASE
100
                ),
101
                InvalidArgumentException::class
102
            );
103
            $moduleDir = $mixedCaseModuleName;
104
        }
105
106
        switch ($moduleType) {
107
            case 'assets':
108
                return $ssp_path . '/public/assets/' . $moduleDir;
109
            case 'module':
110
                return $ssp_path . '/modules/' . $moduleDir;
111
            default:
112
                throw new InvalidArgumentException(sprintf('Unsupported type: %s', $moduleType));
113
        }
114
    }
115
116
117
    /**
118
     * {@inheritDoc}
119
     */
120
    public function supports(string $packageType)
121
    {
122
        return in_array($packageType, self::SUPPORTED);
123
    }
124
}
125