Completed
Push — master ( eb8966...049e5c )
by Stéphane
03:01
created

Builder::build()   C

Complexity

Conditions 8
Paths 11

Size

Total Lines 34
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 8.0747

Importance

Changes 0
Metric Value
cc 8
eloc 19
nc 11
nop 2
dl 0
loc 34
ccs 17
cts 19
cp 0.8947
crap 8.0747
rs 5.3846
c 0
b 0
f 0
1
<?php namespace Todaymade\Daux\Tree;
2
3
use RuntimeException;
4
use SplFileInfo;
5
use Todaymade\Daux\DauxHelper;
6
7
class Builder
8
{
9
    protected static $IGNORED = [
10
        // Popular VCS Systems
11
        '.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg',
12
13
        // Operating system files
14
        '.DS_Store', 'Thumbs.db',
15
    ];
16
17 15
    protected static function isIgnored(\SplFileInfo $file, $ignore)
18
    {
19 15
        $filename = $file->getFilename();
20
21 15
        if (in_array($filename, static::$IGNORED)) {
22
            return true;
23
        }
24
25 15
        if (array_key_exists('folders', $ignore) && $file->isDir() && in_array($filename, $ignore['folders'])) {
26
            return true;
27
        }
28
29 15
        if (array_key_exists('files', $ignore) && !$file->isDir() && in_array($filename, $ignore['files'])) {
30
            return true;
31
        }
32
33 15
        return false;
34
    }
35
36
    /**
37
     * Get name for a file
38
     *
39
     * @param string $path
40
     * @return string
41
     */
42 19
    protected static function getName($path)
43
    {
44
        // ['dir' => 1, 'basename' => 2, 'filename' => 3, 'extension' => 5]
45 19
        preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $m);
46
47 19
        if (!isset($m[3])) {
48
            throw new RuntimeException('Name not found');
49
        }
50
51 19
        return $m[3];
52
    }
53
54
    /**
55
     * Build the initial tree
56
     *
57
     * @param Directory $node
58
     * @param array $ignore
59
     */
60 15
    public static function build($node, $ignore)
61
    {
62 15
        if (($it = new \FilesystemIterator($node->getPath())) == false) {
0 ignored issues
show
introduced by Stéphane Goetz
The condition $it = new FilesystemIter...de->getPath()) == false is always false.
Loading history...
63
            return;
64
        }
65
66 15
        if ($node instanceof Root) {
67
            // Ignore config.json in the root directory
68 15
            $ignore['files'][] = 'config.json';
69
        }
70
71
        /** @var \SplFileInfo $file */
72 15
        foreach ($it as $file) {
73 15
            if (static::isIgnored($file, $ignore)) {
74
                continue;
75
            }
76
77 15
            if ($file->isDir()) {
78 14
                $title = static::removeSortingInformations($file->getFilename());
79 14
                $new = new Directory($node, $title, $file);
80 14
                $new->setName(static::getName($file->getPathName()));
81 14
                $new->setTitle(str_replace('_', ' ', static::removeSortingInformations($new->getName())));
82 14
                static::build($new, $ignore);
83
84 14
                $index = $new->getLocalIndexPage();
85 14
                if ($index && $index->getTitle() != $title) {
86 14
                    $new->setTitle($index->getTitle());
87
                }
88
            } else {
89 15
                static::createContent($node, $file);
90
            }
91
        }
92
93 15
        $node->sort();
94 15
    }
95
96
    /**
97
     * @param Directory $parent
98
     * @param SplFileInfo $file
99
     * @return Content|Raw
100
     */
101 15
    public static function createContent(Directory $parent, SplFileInfo $file)
102
    {
103 15
        $name = static::getName($file->getPathname());
104
105 15
        $config = $parent->getConfig();
106
107 15
        if (!in_array($file->getExtension(), $config['valid_content_extensions'])) {
108 1
            $uri = $file->getFilename();
109
110 1
            $entry = new Raw($parent, $uri, $file);
111 1
            $entry->setTitle(str_replace('_', ' ', static::removeSortingInformations($name)));
112 1
            $entry->setName($name);
113
114 1
            return $entry;
115
        }
116
117 15
        $uri = static::removeSortingInformations($name);
118 15
        if ($config->isStatic()) {
119 15
            $uri .= '.html';
120
        }
121
122 15
        $entry = new Content($parent, $uri, $file);
123
124 15
        if ($entry->getUri() == $config['index_key']) {
125 1
            if ($parent instanceof Root) {
126
                $entry->setTitle($config->getTitle());
127
            } else {
128 1
                $entry->setTitle($parent->getTitle());
129
            }
130
        } else {
131 15
            $entry->setTitle(str_replace('_', ' ', static::removeSortingInformations($name)));
132
        }
133
134 15
        $entry->setName($name);
135
136 15
        return $entry;
137
    }
138
139
    /**
140
     * @param string $filename
141
     * @return string
142
     */
143 39
    public static function removeSortingInformations($filename)
144
    {
145 39
        preg_match('/^[-+]?[0-9]*_?(.*)/', $filename, $matches);
146
147
        // Remove the numeric part
148
        // of the filename, only if
149
        // there is something after
150 39
        return empty($matches[1]) ? $matches[0] : $matches[1];
151
    }
152
153
    /**
154
     * @param Directory $parent
155
     * @param string $title
156
     * @return Directory
157
     */
158 2
    public static function getOrCreateDir(Directory $parent, $title)
159
    {
160 2
        $slug = DauxHelper::slug($title);
161
162 2
        if (array_key_exists($slug, $parent->getEntries())) {
163 1
            return $parent->getEntries()[$slug];
164
        }
165
166 1
        $dir = new Directory($parent, $slug);
167 1
        $dir->setTitle($title);
168
169 1
        return $dir;
170
    }
171
172
    /**
173
     * @param Directory $parent
174
     * @param string $path
175
     * @return ContentAbstract
176
     */
177 5
    public static function getOrCreatePage(Directory $parent, $path)
178
    {
179 5
        $extension = pathinfo($path, PATHINFO_EXTENSION);
180
        // If the file doesn't have an extension, set .md as a default
181 5
        if ($extension == '') {
182 1
            $extension = 'md';
183 1
            $path .= '.md';
184
        }
185
186 5
        $raw = !in_array($extension, $parent->getConfig()['valid_content_extensions']);
187
188 5
        $title = $uri = $path;
189 5
        if (!$raw) {
190 4
            $title = static::getName($path);
191 4
            $uri = DauxHelper::slug($title);
192 4
            if ($parent->getConfig()->isStatic()) {
193 4
                $uri .= '.html';
194
            }
195
        }
196
197 5
        if (array_key_exists($uri, $parent->getEntries())) {
198 1
            return $parent->getEntries()[$uri];
199
        }
200
201 4
        $page = $raw ? new ComputedRaw($parent, $uri) : new Content($parent, $uri);
202 4
        $page->setContent('-'); //set an almost empty content to avoid problems
203 4
        $page->setName($path);
204 4
        $page->setTitle($title);
205
206 4
        if ($title == 'index' || $title == '_index') {
207 1
            $page->setTitle($parent->getTitle());
208
        }
209
210 4
        return $page;
211
    }
212
213
    /**
214
     * Sort the tree recursively
215
     *
216
     * @param Directory $current
217
     */
218
    public static function sortTree(Directory $current) {
219
        $current->sort();
220
        foreach ($current->getEntries() as $entry) {
221
            if ($entry instanceof Directory) {
222
                Builder::sortTree($entry);
223
            }
224
        }
225
    }
226
227
    /**
228
     * Calculate next and previous for all pages
229
     *
230
     * @param Directory $current
231
     * @param null|Content $prev
232
     * @return null|Content
233
     */
234
    public static function finalizeTree(Directory $current, $prev = null)
235
    {
236
        foreach ($current->getEntries() as $entry) {
237
            if ($entry instanceof Directory) {
238
                $prev = Builder::finalizeTree($entry, $prev);
239
            } elseif ($entry instanceof Content) {
240
                if ($prev) {
241
                    $prev->setNext($entry);
242
                    $entry->setPrevious($prev);
243
                }
244
245
                $prev = $entry;
246
            }
247
        }
248
249
        return $prev;
250
    }
251
252
}
253