Completed
Pull Request — master (#24)
by Greg
03:13
created

ReorderFields::matchFieldInLabelMap()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 13
ccs 0
cts 0
cp 0
rs 9.4285
cc 2
eloc 8
nc 1
nop 2
crap 6
1
<?php
2
namespace Consolidation\OutputFormatters\Transformations;
3
4
use Symfony\Component\Finder\Glob;
5
6
/**
7
 * Reorder the field labels based on the user-selected fields
8
 * to display.
9
 */
10
class ReorderFields
11
{
12
    /**
13
     * Given a simple list of user-supplied field keys or field labels,
14
     * return a reordered version of the field labels matching the
15
     * user selection.
16
     *
17
     * @param string|array $fields The user-selected fields
18
     * @param array $fieldLabels An associative array mapping the field
19
     *   key to the field label
20
     * @param array $data The data that will be rendered.
21
     *
22 7
     * @return array
23
     */
24 7
    public function reorder($fields, $fieldLabels, $data)
25 5
    {
26 5
        if (empty($fieldLabels) && !empty($data)) {
27 5
            $firstRow = reset($data);
28 7
            $fieldLabels = array_combine(array_keys($firstRow), array_map('ucfirst', array_keys($firstRow)));
29 7
        }
30 7
        $fields = $this->getSelectedFieldKeys($fields, $fieldLabels);
31
        if (empty($fields)) {
32 2
            return $fieldLabels;
33
        }
34
        return $this->reorderFieldLabels($fields, $fieldLabels, $data);
35 2
    }
36
37 2
    protected function reorderFieldLabels($fields, $fieldLabels, $data)
38 2
    {
39 2
        $result = [];
40 2
        $firstRow = reset($data);
41 2
        foreach ($fields as $field) {
42 2
            if (array_key_exists($field, $firstRow)) {
43 2
                if (array_key_exists($field, $fieldLabels)) {
44 2
                    $result[$field] = $fieldLabels[$field];
45 2
                }
46 2
            }
47
        }
48
        return $result;
49 7
    }
50
51 7
    protected function getSelectedFieldKeys($fields, $fieldLabels)
52 1
    {
53 1
        if (is_string($fields)) {
54 7
            $fields = explode(',', $fields);
55 7
        }
56 7
        $selectedFields = [];
57 2
        foreach ($fields as $field) {
58 2
            $matchedFields = $this->matchFieldInLabelMap($field, $fieldLabels);
59 2
            $selectedFields = array_merge($selectedFields, $matchedFields);
60 2
        }
61 2
        return $selectedFields;
62 7
    }
63 7
64
    protected function matchFieldInLabelMap($field, $fieldLabels)
65
    {
66
        $fieldRegex = $this->convertToRegex($field);
67
        return array_keys(
68
            array_filter(
69
                $fieldLabels,
70
                function ($value, $key) use ($fieldRegex) {
71
                    return preg_match($fieldRegex, $value) || preg_match($fieldRegex, $key);
72
                },
73
                ARRAY_FILTER_USE_BOTH
74
            )
75
        );
76
    }
77
78
    /**
79
     * Convert the provided string into a regex suitable for use in
80
     * preg_match.
81
     *
82
     * Matching occurs in the same way as the Symfony Finder component:
83
     * http://symfony.com/doc/current/components/finder.html#file-name
84
     */
85
    protected function convertToRegex($str)
86
    {
87
        return $this->isRegex($str) ? $str : Glob::toRegex($str);
88
    }
89
90
    /**
91
     * Checks whether the string is a regex.  This function is copied from
92
     * MultiplePcreFilterIterator in the Symfony Finder component.
93
     *
94
     * @param string $str
95
     *
96
     * @return bool Whether the given string is a regex
97
     */
98
    protected function isRegex($str)
99
    {
100
        if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
101
            $start = substr($m[1], 0, 1);
102
            $end = substr($m[1], -1);
103
104
            if ($start === $end) {
105
                return !preg_match('/[*?[:alnum:] \\\\]/', $start);
106
            }
107
108
            foreach (array(array('{', '}'), array('(', ')'), array('[', ']'), array('<', '>')) as $delimiters) {
109
                if ($start === $delimiters[0] && $end === $delimiters[1]) {
110
                    return true;
111
                }
112
            }
113
        }
114
115
        return false;
116
    }
117
}
118