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