BasePathComponent::expandPathVariables()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 16
nc 3
nop 2
dl 0
loc 28
rs 9.7333
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright © Vaimo Group. All rights reserved.
4
 * See LICENSE_VAIMO.txt for license details.
5
 */
6
namespace Vaimo\ComposerPatches\Patch\Definition\NormalizerComponents;
7
8
use Vaimo\ComposerPatches\Patch\Definition as PatchDefinition;
9
use Vaimo\ComposerPatches\Config as PluginConfig;
10
use Vaimo\ComposerPatches\Composer\Constants as ComposerConstants;
11
12
class BasePathComponent implements \Vaimo\ComposerPatches\Interfaces\DefinitionNormalizerComponentInterface
13
{
14
    /**
15
     * @var \Vaimo\ComposerPatches\Utils\TemplateUtils
16
     */
17
    private $templateUtils;
18
19
    public function __construct()
20
    {
21
        $this->templateUtils = new \Vaimo\ComposerPatches\Utils\TemplateUtils();
22
    }
23
24
    public function normalize($target, $label, array $data, array $ownerConfig)
25
    {
26
        if ($this->shouldSkip($ownerConfig, $data)) {
27
            return array();
28
        }
29
30
        $source = $data[PatchDefinition::SOURCE];
31
32
        if (is_numeric($label) && isset($data[PatchDefinition::LABEL])) {
33
            $label = $data[PatchDefinition::LABEL];
34
        }
35
36
        if (strpos($data[PatchDefinition::PATH], DIRECTORY_SEPARATOR) === 0
37
            && file_exists($data[PatchDefinition::PATH])
38
        ) {
39
            return array(
40
                PatchDefinition::LABEL => $label,
41
                PatchDefinition::SOURCE => $source
42
            );
43
        }
44
45
        $template = $this->resolveTemplate($ownerConfig, $target);
46
        list ($sourcePath, $sourceTags) = $this->deconstructSource($source);
47
        $nameParts = explode(ComposerConstants::PACKAGE_SEPARATOR, $target);
48
49
        $pathVariables = array(
50
            'file' => $sourcePath,
51
            'vendor' => array_shift($nameParts),
52
            'package' => implode(ComposerConstants::PACKAGE_SEPARATOR, $nameParts),
53
            'label' => $label
54
        );
55
56
        $mutationNamesMap = array(
57
            'file' => 'file name',
58
            'vendor' => 'vendor name',
59
            'package' => 'module name',
60
            'label' => 'label value'
61
        );
62
63
        $extraVariables = array(
64
            'version' => preg_replace(
65
                '/[^A-Za-z0-9.-]/',
66
                '',
67
                strtok(reset($data[PatchDefinition::DEPENDS]) ?: '0.0.0', ' ')
68
            ),
69
            'file' => $sourcePath,
70
            'label' => $label
71
        );
72
73
        $variablePattern = '{{%s}}';
74
75
        $pathVariables = $this->expandPathVariables($pathVariables, $mutationNamesMap);
76
77
        $templateVariables = $this->prepareTemplateValues(
78
            $template,
79
            $variablePattern,
80
            array_replace($pathVariables, $extraVariables)
81
        );
82
83
        $sourcePath = $this->templateUtils->compose(
84
            $template . ($sourceTags ? ('#' . $sourceTags) : ''),
85
            $templateVariables,
86
            array_fill_keys(array($variablePattern), array())
87
        );
88
89
        return array(
90
            PatchDefinition::LABEL => $this->normalizeLabelForSourcePath($label, $sourcePath),
91
            PatchDefinition::SOURCE => $sourcePath
92
        );
93
    }
94
95
    private function shouldSkip(array $ownerConfig, array $data)
96
    {
97
        if (!isset($ownerConfig[PluginConfig::PATCHES_BASE])) {
98
            return true;
99
        }
100
101
        if (parse_url($data[PatchDefinition::SOURCE], PHP_URL_SCHEME)) {
102
            return true;
103
        }
104
105
        return false;
106
    }
107
108
    private function normalizeLabelForSourcePath($label, $sourcePath)
109
    {
110
        $filename = basename($sourcePath);
111
112
        if (substr($label, -strlen($filename)) === $filename) {
113
            return str_replace(
114
                $filename,
115
                preg_replace('/\s{2,}/', ' ', preg_replace('/[^A-Za-z0-9]/', ' ', strtok($filename, '.'))),
116
                $label
117
            );
118
        }
119
120
        return $label;
121
    }
122
123
    private function deconstructSource($source)
124
    {
125
        $sourceTags = '';
126
127
        if (strpos($source, '#') !== false) {
128
            $sourceSegments = explode('#', $source);
129
130
            $sourceTags = array_pop($sourceSegments);
131
            $source = implode('#', $sourceSegments);
132
        }
133
134
        return array($source, $sourceTags);
135
    }
136
137
    private function prepareTemplateValues($template, $variablePattern, $variableValues)
138
    {
139
        $mutationRules = $this->templateUtils->collectValueMutationRules(
140
            $template,
141
            array($variablePattern)
142
        );
143
144
        return array_replace(
145
            $this->templateUtils->applyMutations(
146
                $variableValues,
147
                $mutationRules,
148
                ' :-_.'
149
            ),
150
            $variableValues
151
        );
152
    }
153
154
    private function expandPathVariables(array $pathVariables, array $mutationNamesMap)
155
    {
156
        $normalizedVariables = array_map(function ($part) {
157
            $part = strtolower(
158
                preg_replace(
159
                    array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'),
160
                    array('\\1_\\2', '\\1_\\2'),
161
                    str_replace('_', '.', $part)
162
                )
163
            );
164
165
            return preg_replace('/\s{2,}/', ' ', str_replace(array(' ', '_', '-', '.', '/', ':'), ' ', $part));
166
        }, $pathVariables);
167
168
        $mutationAppliers = $this->createMutationAppliers();
169
170
        $pathVariables = array();
171
172
        foreach ($normalizedVariables as $name => $value) {
173
            $variableName = $mutationNamesMap[$name];
174
175
            foreach ($mutationAppliers as $mutationApplier) {
176
                $mutationName = $mutationApplier($variableName);
177
                $pathVariables[$mutationName] = $mutationApplier($value);
178
            }
179
        }
180
181
        return $pathVariables;
182
    }
183
184
    private function resolveTemplate($ownerConfig, $packageName)
185
    {
186
        $templates = $ownerConfig[PluginConfig::PATCHES_BASE];
187
188
        $vendorName = strtok($packageName, ComposerConstants::PACKAGE_SEPARATOR);
189
190
        if (is_array($templates)) {
191
            if (isset($templates[$packageName])) {
192
                return $templates[$packageName];
193
            } elseif (isset($templates[$vendorName])) {
194
                return $templates[$vendorName];
195
            } elseif ($templates[PluginConfig::PATCHES_BASE_DEFAULT]) {
196
                return $templates[PluginConfig::PATCHES_BASE_DEFAULT];
197
            }
198
199
            return reset($templates);
200
        }
201
202
        return $templates;
203
    }
204
205
    private function createMutationAppliers()
206
    {
207
        return array(
208
            function ($value) {
209
                return str_replace(' ', '', $value);
210
            },
211
            function ($value) {
212
                return str_replace(' ', '', ucwords($value));
213
            },
214
            function ($value) {
215
                return str_replace(' ', '', ucfirst($value));
216
            },
217
            function ($value) {
218
                return str_replace(' ', '-', $value);
219
            },
220
            function ($value) {
221
                return str_replace(' ', '_', $value);
222
            },
223
        );
224
    }
225
}
226