ReorderFields::getSelectedFieldKeys()   A
last analyzed

Complexity

Conditions 5
Paths 7

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5

Importance

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