Passed
Push — master ( 986f6c...ae2e8a )
by Sebastian
03:10
created

FileHelper_PathsReducer::splitPaths()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 12
rs 10
cc 3
nc 3
nop 0
1
<?php
2
/**
3
 * File containing the {@see FileHelper_PathsReducer} class.
4
 *
5
 * @package AppUtils
6
 * @subpackage FileHelper
7
 * @see FileHelper_PathsReducer
8
 */
9
10
declare(strict_types=1);
11
12
namespace AppUtils;
13
14
/**
15
 * Takes a list of file or folder paths, and attempts to reduce
16
 * them to the closest common relative path.
17
 *
18
 * @package AppUtils
19
 * @subpackage FileHelper
20
 * @author Sebastian Mordziol <[email protected]>
21
 *
22
 * @see FileHelper::createPathsReducer()
23
 */
24
class FileHelper_PathsReducer
25
{
26
    /**
27
     * @var string[]
28
     */
29
    private $paths = array();
30
31
    /**
32
     * @param string[] $paths
33
     * @throws FileHelper_Exception
34
     */
35
    public function __construct(array $paths=array())
36
    {
37
        $this->addPaths($paths);
38
    }
39
40
    /**
41
     * Adds a list of paths to reduce.
42
     *
43
     * @param string[] $paths
44
     * @return $this
45
     * @throws FileHelper_Exception
46
     */
47
    public function addPaths(array $paths) : FileHelper_PathsReducer
48
    {
49
        foreach($paths as $path) {
50
            $this->addPath($path);
51
        }
52
53
        return $this;
54
    }
55
56
    /**
57
     * Adds a single path to the reducer.
58
     *
59
     * @param string $path
60
     * @return $this
61
     * @throws FileHelper_Exception
62
     */
63
    public function addPath(string $path) : FileHelper_PathsReducer
64
    {
65
        $path = FileHelper::normalizePath(FileHelper::requireFileExists($path));
66
67
        if(!in_array($path, $this->paths)) {
68
            $this->paths[] = $path;
69
        }
70
71
        return $this;
72
    }
73
74
    /**
75
     * Analyzes the paths and returns them reduced
76
     * if at all possible.
77
     *
78
     * @return string[]
79
     */
80
    public function reduce() : array
81
    {
82
        $split = $this->splitPaths();
83
84
        if(empty($split)) {
85
            return array();
86
        }
87
88
        while($this->shiftPart($split) === true) {}
89
90
        return $this->joinPaths($split);
91
    }
92
93
    /**
94
     * @param array<int,string[]> $split
95
     * @return string[]
96
     */
97
    private function joinPaths(array $split) : array
98
    {
99
        $result = array();
100
101
        foreach ($split as $entry) {
102
            if(!empty($entry)) {
103
                $result[] = implode('/', $entry);
104
            }
105
        }
106
107
        return $result;
108
    }
109
110
    /**
111
     * @param array<int,string[]> &$split
112
     * @return bool
113
     */
114
    private function shiftPart(array &$split) : bool
115
    {
116
        $current = null;
117
        $result = array();
118
119
        foreach($split as $entry)
120
        {
121
            if(empty($entry)) {
122
                return false;
123
            }
124
125
            $part = array_shift($entry);
126
            if(empty($entry)) {
127
                return false;
128
            }
129
130
            if($current === null) {
131
                $current = $part;
132
            }
133
134
            if($part !== $current) {
135
                return false;
136
            }
137
138
            $result[] = $entry;
139
        }
140
141
        $split = $result;
142
143
        return true;
144
    }
145
146
    private function splitPaths() : array
147
    {
148
        $split = array();
149
150
        foreach($this->paths as $path) {
151
            $entry = ConvertHelper::explodeTrim('/', $path);
152
            if(!empty($entry)) {
153
                $split[] = $entry;
154
            }
155
        }
156
157
        return $split;
158
    }
159
}
160