UniqueCommand::identify()   B
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 25
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 20
nc 3
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * Magento Version Identification
4
 *
5
 * PHP version 5
6
 *
7
 * @author    Steve Robbins <[email protected]>
8
 * @copyright 2015 Steve Robbins
9
 * @license   http://creativecommons.org/licenses/by/4.0/ CC BY 4.0
10
 * @link      https://github.com/steverobbins/magento-version-identification-php
11
 */
12
13
namespace Mvi\Command;
14
15
use Mvi\Command\MviCommand;
16
use Symfony\Component\Console\Input\InputInterface;
17
use Symfony\Component\Console\Output\OutputInterface;
18
19
/**
20
 * Finds unique md5 hashes
21
 */
22
class UniqueCommand extends MviCommand
23
{
24
    const VERSION_DESTINATION = 'version.json';
25
26
    const ACCURACY_FACTOR = 500;
27
28
    const EDITION_SHORT_ENTERPRISE = 'EE';
29
    const EDITION_SHORT_COMMUNITY  = 'CE';
30
    const EDITION_LONG_ENTERPRISE  = 'Enterprise';
31
    const EDITION_LONG_COMMUNITY   = 'Community';
32
33
    /**
34
     * Patterns of file that might not be reliable
35
     *
36
     * @var string[]
37
     */
38
    protected $fileIgnorePatterns = [
39
        "/\/rwd\//",
40
        "/[^(js|css)]$/",
41
    ];
42
43
    /**
44
     * Configure generate command
45
     *
46
     * @return void
47
     */
48
    protected function configure()
49
    {
50
        $this
51
            ->setName('unique')
52
            ->setDescription('Find unique md5 hashes and save to file');
53
    }
54
55
    /**
56
     * Run unique command
57
     *
58
     * @param InputInterface  $input
59
     * @param OutputInterface $output
60
     *
61
     * @return void
62
     */
63
    protected function execute(InputInterface $input, OutputInterface $output)
64
    {
65
        $data           = $this->collectData();
66
        $fileHashCounts = $this->buildFileHashCounts($data);
67
        $fingerprints   = [];
68
        $tries          = 0;
69
        while (count($data) > 0) {
70
            $accuracy = ceil(++$tries / self::ACCURACY_FACTOR);
71
            $file     = key($fileHashCounts);
72
            foreach ($data as $release => $value) {
73
                $this->identify($value, $file, $fileHashCounts, $accuracy, $fingerprints, $release, $data, $output);
74
            }
75
            next($fileHashCounts) ?: reset($fileHashCounts);
76
        }
77
        if ($this->saveUniqueVersions($fingerprints)) {
78
            $output->writeln(sprintf('Unique hashes written to <info>%s</info>', self::VERSION_DESTINATION));
79
        } else {
80
            $output->writeln('<error>Failed to write unique hashes to file</error>');
81
        }
82
    }
83
84
    /**
85
     * Collect all the release hash datas
86
     *
87
     * [
88
     *     'CE-1.0.0' => [
89
     *         'abc123' => 'foo.js',
90
     *         'edf456' => 'bar.js',
91
     *     ],
92
     *     'CE-1.1.0' => [ ... ]
93
     * ]
94
     *
95
     * @return array
96
     */
97
    protected function collectData()
98
    {
99
        $data = [];
100
        foreach (glob($this->baseDir . DS . self::DIR_MD5 . DS . 'magento-*') as $release) {
101
            $lines   = explode("\n", file_get_contents($release));
102
            $release = str_replace($this->baseDir . DS . self::DIR_MD5 . DS . 'magento-', '', $release);
103
            $data[$release] = [];
104
            foreach ($lines as $line) {
105
                if (strlen($line) === 0) {
106
                    continue;
107
                }
108
                list($hash, $file) = explode(' ', $line);
109
                foreach ($this->fileIgnorePatterns as $pattern) {
110
                    if (preg_match($pattern, $file)) {
111
                        continue 2;
112
                    }
113
                }
114
                $data[$release][$hash] = $file;
115
            }
116
        }
117
        return $data;
118
    }
119
120
    /**
121
     * Get the most import files determined by how many unique hashes they have
122
     *
123
     * [
124
     *     'skin/adminhtml/default/default/boxes.css' => [
125
     *         'abc123' => [
126
     *             'CE-1.0'
127
     *         ],
128
     *         'efg456' => [
129
     *             'CE-1.1.0',
130
     *             'CE-1.1.1'
131
     *         ],
132
     *         ...
133
     *     ],
134
     *     ...
135
     * ]
136
     *
137
     * @param array $data
138
     *
139
     * @return array
140
     */
141
    protected function buildFileHashCounts(array $data)
142
    {
143
        $counts = [];
144
        foreach ($data as $release => $value) {
145
            foreach ($value as $hash => $file) {
146
                if (!isset($counts[$file])) {
147
                    $counts[$file] = [];
148
                }
149
                if (!isset($counts[$file][$hash])) {
150
                    $counts[$file][$hash] = [];
151
                }
152
                $counts[$file][$hash][] = $release;
153
            }
154
        }
155
        uasort($counts, function ($a, $b) {
156
            return count($b) - count($a);
157
        });
158
        return $counts;
159
    }
160
161
    /**
162
     * Take the release short name and expand
163
     *
164
     * @param string $name
165
     * @param array  $existing
166
     *
167
     * @return string[]
168
     */
169
    protected function prepareReleaseName($name, &$existing)
170
    {
171
        list($edition, $version) = explode('-', $name);
172
        switch ($edition) {
173
            case self::EDITION_SHORT_ENTERPRISE:
174
                $edition = self::EDITION_LONG_ENTERPRISE;
175
                break;
176
            case self::EDITION_SHORT_COMMUNITY:
177
                $edition = self::EDITION_LONG_COMMUNITY;
178
                break;
179
        }
180
        if (!is_array($existing)) {
181
            $existing = [];
182
        }
183
        if (!isset($existing[$edition])) {
184
            $existing[$edition] = [];
185
        }
186
        $existing[$edition][] = $version;
187
    }
188
189
    /**
190
     * Add file/hash/release combo to fingerprints if accurate enough
191
     *
192
     * @param array           $value
193
     * @param string          $file
194
     * @param array           $fileHashCounts
195
     * @param string          $accuracy
196
     * @param array           $fingerprints
197
     * @param string          $release
198
     * @param array           $data
199
     * @param OutputInterface $output
200
     *
201
     * @return void
202
     */
203
    protected function identify(
204
        array $value,
205
        $file,
206
        array $fileHashCounts,
207
        $accuracy,
208
        &$fingerprints,
209
        $release,
210
        array &$data,
211
        OutputInterface $output
212
    ) {
213
        $fileHash = array_flip($value);
214
        if (isset($fileHash[$file]) && count($fileHashCounts[$file][$fileHash[$file]]) <= $accuracy) {
215
            if (!isset($fingerprints[$file])) {
216
                $fingerprints[$file] = [];
217
            }
218
            $this->prepareReleaseName($release, $fingerprints[$file][$fileHash[$file]]);
219
            $output->writeln(sprintf(
220
                '<info>%s</info> can be identified by <info>%s</info> with hash <info>%s</info>',
221
                $release,
222
                $file,
223
                $fileHash[$file]
224
            ));
225
            unset($data[$release]);
226
        }
227
    }
228
229
    /**
230
     * Save fingerprints to file
231
     *
232
     * @param array $fingerprints
233
     *
234
     * @return integer
235
     */
236
    protected function saveUniqueVersions($fingerprints)
237
    {
238
        uasort($fingerprints, function ($a, $b) {
239
            return count($b) - count($a);
240
        });
241
        $json = str_replace('\\/', '/', json_encode($fingerprints, JSON_PRETTY_PRINT));
242
        return file_put_contents($this->baseDir . DS . self::VERSION_DESTINATION, $json);
243
    }
244
}
245