Passed
Push — master ( 79ebcc...8d3dd7 )
by Allan
02:23 queued 11s
created

BasePathComponent::shouldSkip()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 3
nop 2
dl 0
loc 11
rs 10
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
47
        list ($sourcePath, $sourceTags) = $this->deconstructSource($source);
48
49
        $nameParts = explode(ComposerConstants::PACKAGE_SEPARATOR, $target);
50
51
        $pathVariables = array(
52
            'file' => $sourcePath,
53
            'vendor' => array_shift($nameParts),
54
            'package' => implode(ComposerConstants::PACKAGE_SEPARATOR, $nameParts),
55
            'label' => $label
56
        );
57
58
        $mutationNamesMap = array(
59
            'file' => 'file name',
60
            'vendor' => 'vendor name',
61
            'package' => 'module name',
62
            'label' => 'label value'
63
        );
64
65
        $extraVariables = array(
66
            'version' => preg_replace(
67
                '/[^A-Za-z0-9.-]/',
68
                '',
69
                strtok(reset($data[PatchDefinition::DEPENDS]) ?: '0.0.0', ' ')
70
            ),
71
            'file' => $sourcePath,
72
            'label' => $label
73
        );
74
75
        $variablePattern = '{{%s}}';
76
77
        $pathVariables = $this->expandPathVariables($pathVariables, $mutationNamesMap);
78
79
        $templateVariables = $this->prepareTemplateValues(
80
            $template,
81
            $variablePattern,
82
            array_replace($pathVariables, $extraVariables)
83
        );
84
85
        $sourcePath = $this->templateUtils->compose(
86
            $template . ($sourceTags ? ('#' . $sourceTags) : ''),
87
            $templateVariables,
88
            array_fill_keys(array($variablePattern), array())
89
        );
90
91
        return array(
92
            PatchDefinition::LABEL => $this->normalizeLabelForSourcePath($label, $sourcePath),
93
            PatchDefinition::SOURCE => $sourcePath
94
        );
95
    }
96
97
    private function shouldSkip(array $data, array $ownerConfig)
98
    {
99
        if (!isset($ownerConfig[PluginConfig::PATCHES_BASE])) {
100
            return true;
101
        }
102
103
        if (parse_url($data[PatchDefinition::SOURCE], PHP_URL_SCHEME)) {
104
            return true;
105
        }
106
107
        return false;
108
    }
109
110
    private function normalizeLabelForSourcePath($label, $sourcePath)
111
    {
112
        $filename = basename($sourcePath);
113
114
        if (substr($label, -strlen($filename)) === $filename) {
115
            return str_replace(
116
                $filename,
117
                preg_replace('/\s{2,}/', ' ', preg_replace('/[^A-Za-z0-9]/', ' ', strtok($filename, '.'))),
118
                $label
119
            );
120
        }
121
122
        return $label;
123
    }
124
125
    private function deconstructSource($source)
126
    {
127
        $sourceTags = '';
128
129
        if (strpos($source, '#') !== false) {
130
            $sourceSegments = explode('#', $source);
131
132
            $sourceTags = array_pop($sourceSegments);
133
            $source = implode('#', $sourceSegments);
134
        }
135
136
        return array($source, $sourceTags);
137
    }
138
139
    private function prepareTemplateValues($template, $variablePattern, $variableValues)
140
    {
141
        $mutationRules = $this->templateUtils->collectValueMutationRules(
142
            $template,
143
            array($variablePattern)
144
        );
145
146
        return array_replace(
147
            $this->templateUtils->applyMutations(
148
                $variableValues,
149
                $mutationRules,
150
                ' :-_.'
151
            ),
152
            $variableValues
153
        );
154
    }
155
156
    private function expandPathVariables(array $pathVariables, array $mutationNamesMap)
157
    {
158
        $normalizedVariables = array_map(function ($part) {
159
            $part = strtolower(
160
                preg_replace(
161
                    array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'),
162
                    array('\\1_\\2', '\\1_\\2'),
163
                    str_replace('_', '.', $part)
164
                )
165
            );
166
167
            return preg_replace('/\s{2,}/', ' ', str_replace(array(' ', '_', '-', '.', '/', ':'), ' ', $part));
168
        }, $pathVariables);
169
170
        $mutationAppliers = $this->createMutationAppliers();
171
172
        $pathVariables = array();
173
174
        foreach ($normalizedVariables as $name => $value) {
175
            $variableName = $mutationNamesMap[$name];
176
177
            foreach ($mutationAppliers as $mutationApplier) {
178
                $mutationName = $mutationApplier($variableName);
179
                $pathVariables[$mutationName] = $mutationApplier($value);
180
            }
181
        }
182
183
        return $pathVariables;
184
    }
185
186
    private function resolveTemplate($ownerConfig, $packageName)
187
    {
188
        $templates = $ownerConfig[PluginConfig::PATCHES_BASE];
189
190
        $vendorName = strtok($packageName, ComposerConstants::PACKAGE_SEPARATOR);
191
192
        if (is_array($templates)) {
193
            if (isset($templates[$packageName])) {
194
                return $templates[$packageName];
195
            } elseif (isset($templates[$vendorName])) {
196
                return $templates[$vendorName];
197
            } elseif ($templates[PluginConfig::PATCHES_BASE_DEFAULT]) {
198
                return $templates[PluginConfig::PATCHES_BASE_DEFAULT];
199
            }
200
201
            return reset($templates);
202
        }
203
204
        return $templates;
205
    }
206
207
    private function createMutationAppliers()
208
    {
209
        return array(
210
            function ($value) {
211
                return str_replace(' ', '', $value);
212
            },
213
            function ($value) {
214
                return str_replace(' ', '', ucwords($value));
215
            },
216
            function ($value) {
217
                return str_replace(' ', '', ucfirst($value));
218
            },
219
            function ($value) {
220
                return str_replace(' ', '-', $value);
221
            },
222
            function ($value) {
223
                return str_replace(' ', '_', $value);
224
            },
225
        );
226
    }
227
}
228