1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @copyright 2018 Vladimir Jimenez |
5
|
|
|
* @license https://github.com/stakx-io/stakx/blob/master/LICENSE.md MIT |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace allejo\stakx\Manager; |
9
|
|
|
|
10
|
|
|
use allejo\stakx\Document\CollectableItem; |
11
|
|
|
use allejo\stakx\Document\JailedDocument; |
12
|
|
|
use allejo\stakx\Document\ReadableDocument; |
13
|
|
|
use allejo\stakx\Document\TemplateReadyDocument; |
14
|
|
|
use allejo\stakx\Filesystem\File; |
15
|
|
|
use allejo\stakx\Filesystem\FileExplorer; |
16
|
|
|
use allejo\stakx\Filesystem\FileExplorerDefinition; |
17
|
|
|
use allejo\stakx\Filesystem\FilesystemPath; |
18
|
|
|
use allejo\stakx\RuntimeStatus; |
19
|
|
|
use allejo\stakx\Service; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Class TrackingManager. |
23
|
|
|
*/ |
24
|
|
|
abstract class TrackingManager extends BaseManager |
25
|
|
|
{ |
26
|
|
|
/** |
27
|
|
|
* @var FileExplorer |
28
|
|
|
*/ |
29
|
|
|
protected $fileExplorer = null; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* An array corresponding with $folderDefinitions to store metadata regarding a specificc folder. |
33
|
|
|
* |
34
|
|
|
* $folderDefinitionsOption['<folder path>'] = array() |
35
|
|
|
* |
36
|
|
|
* @var string[] |
37
|
|
|
*/ |
38
|
|
|
protected $folderDefinitionsOptions = []; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* An array of folders which tracked items are stored in. |
42
|
|
|
* |
43
|
|
|
* $folderDefinitions[] = '<folder path>' |
44
|
|
|
* |
45
|
|
|
* @deprecated This has been superseded by `$watchedFolders` |
46
|
|
|
* @var string[] |
47
|
|
|
*/ |
48
|
|
|
protected $folderDefinitions = []; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* An array of folder definitions which tracked items are stored in. |
52
|
|
|
* |
53
|
|
|
* @var FileExplorerDefinition[] |
54
|
|
|
*/ |
55
|
|
|
protected $watchedFolders = []; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* The storage which contains the same information as $trackedItems but organized by relative file path instead of a |
59
|
|
|
* namespace or file name without extension. |
60
|
|
|
* |
61
|
|
|
* $trackedItemsOptions['<relative file path>'] = mixed |
62
|
|
|
* |
63
|
|
|
* @var array |
64
|
|
|
*/ |
65
|
|
|
protected $trackedItemsFlattened = []; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* The storage used to cache any information needed for a specific FrontMatterObject or DataItem. |
69
|
|
|
* |
70
|
|
|
* For example, with a DataItem, which is just an array, the file path to the original file can be stored in this |
71
|
|
|
* array to be accessible in the future to refresh the contents without parsing all of the files again. |
72
|
|
|
* |
73
|
|
|
* $trackedItemsOptions['<relative file path>'] = array |
74
|
|
|
* |
75
|
|
|
* @var array |
76
|
|
|
*/ |
77
|
|
|
protected $trackedItemsOptions = []; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* The storage used for ReadableDocument in the respective static classes. |
81
|
|
|
* |
82
|
|
|
* $trackedItems['<namespace>']['<file name w/o extension>'] = mixed |
83
|
|
|
* $trackedItems['<file name w/o extension>'] = mixed |
84
|
|
|
* |
85
|
|
|
* @var array |
86
|
|
|
*/ |
87
|
|
|
protected $trackedItems = []; |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* @param File|string $filePath |
91
|
|
|
* |
92
|
|
|
* @return mixed|null |
93
|
|
|
*/ |
94
|
|
|
public function createNewItem($filePath) |
95
|
|
|
{ |
96
|
|
|
return $this->handleTrackableItem($filePath); |
|
|
|
|
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @param FilesystemPath|string $filePath |
101
|
|
|
* |
102
|
|
|
* @return mixed|null |
103
|
|
|
*/ |
104
|
|
|
public function getTracked($filePath) |
105
|
|
|
{ |
106
|
|
|
if ($this->isTracked($filePath)) |
|
|
|
|
107
|
|
|
{ |
108
|
|
|
return $this->trackedItemsFlattened[(string)$filePath]; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
return null; |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* Check whether a file is already being tracked. |
116
|
|
|
* |
117
|
|
|
* @param string $filePath The relative path of the file |
118
|
|
|
* |
119
|
|
|
* @return bool |
120
|
|
|
*/ |
121
|
1 |
|
public function isTracked($filePath) |
122
|
|
|
{ |
123
|
1 |
|
return array_key_exists((string)$filePath, $this->trackedItemsFlattened); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Check to see if a given file path matches this tracker's definition and would be tracked. |
128
|
|
|
* |
129
|
|
|
* This function should be used to check whether or not to add a file to this tracker after the initial scan has |
130
|
|
|
* already happened. |
131
|
|
|
* |
132
|
|
|
* @param string $filePath |
133
|
|
|
* |
134
|
|
|
* @return bool True if the file is inside a tracked folder |
135
|
|
|
*/ |
136
|
|
|
public function shouldBeTracked($filePath) |
137
|
|
|
{ |
138
|
|
|
foreach ($this->folderDefinitions as $folder) |
|
|
|
|
139
|
|
|
{ |
140
|
|
|
if (substr($filePath, 0, strlen($folder)) === $folder) |
141
|
|
|
{ |
142
|
|
|
return true; |
143
|
|
|
} |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
return false; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Update the contents of a specified file. |
151
|
|
|
* |
152
|
|
|
* @param File|string $filePath The relative path of the file |
153
|
|
|
* |
154
|
|
|
* @return mixed|null |
155
|
|
|
*/ |
156
|
|
|
public function refreshItem($filePath) |
157
|
|
|
{ |
158
|
|
|
return $this->handleTrackableItem($filePath); |
|
|
|
|
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/// |
162
|
|
|
// Internal object handling |
163
|
|
|
/// |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* Initialize a namespace that will be tracked. |
167
|
|
|
* |
168
|
|
|
* @param string $namespace |
169
|
|
|
*/ |
170
|
52 |
|
protected function declareTrackingNamespace($namespace) |
171
|
|
|
{ |
172
|
52 |
|
if (!isset($this->trackedItems[$namespace])) |
173
|
|
|
{ |
174
|
37 |
|
$this->trackedItems[$namespace] = []; |
175
|
|
|
} |
176
|
52 |
|
} |
177
|
|
|
|
178
|
|
|
protected function addFileToTracker(File &$file) |
179
|
|
|
{ |
180
|
|
|
$this->trackedItemsFlattened[$file->getRelativeFilePath()] = &$file; |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
protected function delFileFromTracker(File &$file) |
184
|
|
|
{ |
185
|
|
|
unset($this->trackedItemsFlattened[$file->getRelativeFilePath()]); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Add a ReadableDocument to the tracker. |
190
|
|
|
* |
191
|
|
|
* @param ReadableDocument $trackedItem |
192
|
|
|
* @param string|null $namespace |
193
|
|
|
*/ |
194
|
53 |
|
protected function addObjectToTracker(ReadableDocument &$trackedItem, $namespace = null) |
195
|
|
|
{ |
196
|
53 |
|
if ($namespace == null) |
|
|
|
|
197
|
|
|
{ |
198
|
1 |
|
$this->trackedItems[$trackedItem->getIndexName()] = &$trackedItem; |
199
|
|
|
} |
200
|
|
|
else |
201
|
|
|
{ |
202
|
52 |
|
$this->trackedItems[$namespace][$trackedItem->getIndexName()] = &$trackedItem; |
203
|
|
|
} |
204
|
|
|
|
205
|
53 |
|
$this->trackedItemsFlattened[$trackedItem->getIndexName()] = &$trackedItem; |
206
|
53 |
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* Remove an entry from the tracked items array. |
210
|
|
|
* |
211
|
|
|
* @param ReadableDocument $trackedItem |
212
|
|
|
* @param string|null $namespace |
213
|
|
|
*/ |
214
|
|
|
protected function delObjectFromTracker(ReadableDocument &$trackedItem, $namespace = null) |
215
|
|
|
{ |
216
|
|
|
if ($namespace == null) |
|
|
|
|
217
|
|
|
{ |
218
|
|
|
unset($this->trackedItems[$trackedItem->getIndexName()]); |
219
|
|
|
} |
220
|
|
|
else |
221
|
|
|
{ |
222
|
|
|
unset($this->trackedItems[$namespace][$trackedItem->getIndexName()]); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
unset($this->trackedItemsFlattened[$trackedItem->getIndexName()]); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/// |
229
|
|
|
// Extra options stored for future use |
230
|
|
|
/// |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* Save a folder that is tracked by this manager and its respective options. |
234
|
|
|
* |
235
|
|
|
* @deprecated |
236
|
|
|
* |
237
|
|
|
* @param string $folderPath |
238
|
|
|
* @param array $options |
239
|
|
|
*/ |
240
|
|
|
protected function saveFolderDefinition($folderPath, array $options = []) |
241
|
|
|
{ |
242
|
|
|
$this->folderDefinitions[] = $folderPath; |
|
|
|
|
243
|
|
|
$this->folderDefinitionsOptions[(string)$folderPath] = $options; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Save any options related to an item needed in order to refresh the content. |
248
|
|
|
* |
249
|
|
|
* @param string $filePath |
250
|
|
|
* @param array $options |
251
|
|
|
*/ |
252
|
2 |
|
protected function saveTrackerOptions($filePath, array $options = []) |
253
|
|
|
{ |
254
|
2 |
|
$this->trackedItemsOptions[$filePath] = $options; |
255
|
2 |
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Delete any options that were saved corresponding to an item. |
259
|
|
|
* |
260
|
|
|
* @param string $filePath |
261
|
|
|
*/ |
262
|
|
|
protected function forgetTrackerOptions($filePath) |
263
|
|
|
{ |
264
|
|
|
unset($this->trackedItemsOptions[$filePath]); |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/// |
268
|
|
|
// Handling of trackable items |
269
|
|
|
/// |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Parse the specified folder for items to track. |
273
|
|
|
* |
274
|
|
|
* @param FileExplorerDefinition $def |
275
|
|
|
* @param array $options Special options that will be passed to the `static::parseTrackableItem()` |
276
|
|
|
* implementation |
277
|
|
|
*/ |
278
|
52 |
|
protected function scanTrackableItems(FileExplorerDefinition $def, array $options = []) |
279
|
|
|
{ |
280
|
52 |
|
$this->watchedFolders[$def->folder->getAbsolutePath()] = $def; |
281
|
|
|
|
282
|
52 |
|
if (empty($def->excludes)) |
283
|
|
|
{ |
284
|
52 |
|
$def->excludes = self::$documentIgnoreList; |
285
|
|
|
} |
286
|
|
|
|
287
|
52 |
|
$fileExplorer = FileExplorer::createFromDefinition($def); |
288
|
52 |
|
$fileIterator = $fileExplorer->getFileIterator(); |
289
|
|
|
|
290
|
52 |
|
foreach ($fileIterator as $file) |
291
|
|
|
{ |
292
|
52 |
|
$this->handleTrackableItem($file, $options); |
293
|
|
|
} |
294
|
52 |
|
} |
295
|
|
|
|
296
|
|
|
/** |
297
|
|
|
* Handle a specific file type, parse it into the appropriate object type, and add it to the tracker. |
298
|
|
|
* |
299
|
|
|
* This function should make use of the appropriate functions: |
300
|
|
|
* |
301
|
|
|
* - TrackingManager::addObjectToTracker() |
302
|
|
|
* - TrackingManager::addFileToTracker() |
303
|
|
|
* - TrackingManager::saveTrackerOptions() |
304
|
|
|
* |
305
|
|
|
* @param File $filePath |
306
|
|
|
* @param array $options |
307
|
|
|
* |
308
|
|
|
* @return mixed|null |
309
|
|
|
*/ |
310
|
|
|
abstract protected function handleTrackableItem(File $filePath, array $options = []); |
311
|
|
|
|
312
|
|
|
/// |
313
|
|
|
// Utility functions |
314
|
|
|
/// |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* Return an array of JailedDocuments created from the tracked items. |
318
|
|
|
* |
319
|
|
|
* @param JailedDocument[] $elements An array of elements to get jailed versions of |
320
|
|
|
* @param \Closure $name A closure to generate the name of the element that will be used as the key in |
|
|
|
|
321
|
|
|
* this associative array. |
322
|
|
|
* |
323
|
|
|
* @return JailedDocument[]|JailedDocument[][] |
324
|
|
|
*/ |
325
|
21 |
|
protected static function getJailedTrackedItems(array &$elements, \Closure $name = null) |
326
|
|
|
{ |
327
|
21 |
|
$jailItems = []; |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* @var string |
331
|
|
|
* @var CollectableItem|ReadableDocument $item |
332
|
|
|
*/ |
333
|
21 |
|
foreach ($elements as &$item) |
334
|
|
|
{ |
335
|
21 |
|
if ($item instanceof TemplateReadyDocument) |
336
|
|
|
{ |
337
|
21 |
|
if (!Service::hasRunTimeFlag(RuntimeStatus::USING_DRAFTS) && $item->isDraft()) |
338
|
|
|
{ |
339
|
1 |
|
continue; |
340
|
|
|
} |
341
|
|
|
} |
342
|
|
|
|
343
|
21 |
|
$keyName = ($name === null) ? $item->getRelativeFilePath() : $name($item); |
|
|
|
|
344
|
|
|
|
345
|
21 |
|
if (empty($item->getNamespace())) |
|
|
|
|
346
|
|
|
{ |
347
|
1 |
|
$jailItems[$keyName] = $item->createJail(); |
|
|
|
|
348
|
|
|
} |
349
|
|
|
else |
350
|
|
|
{ |
351
|
20 |
|
$jailItems[$item->getNamespace()][$keyName] = $item->createJail(); |
|
|
|
|
352
|
|
|
} |
353
|
|
|
} |
354
|
|
|
|
355
|
21 |
|
return $jailItems; |
356
|
|
|
} |
357
|
|
|
} |
358
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.