Completed
Push — master ( a6c8f9...b97be3 )
by Vladimir
03:52 queued 19s
created

TrackingManager::scanTrackableItems()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 10
cts 10
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
nc 8
nop 4
crap 4
1
<?php
2
3
/**
4
 * @copyright 2017 Vladimir Jimenez
5
 * @license   https://github.com/allejo/stakx/blob/master/LICENSE.md MIT
6
 */
7
8
namespace allejo\stakx\Manager;
9
10
use allejo\stakx\Command\BuildableCommand;
11
use allejo\stakx\Document\CollectableItem;
12
use allejo\stakx\Document\JailedDocument;
13
use allejo\stakx\Document\ReadableDocument;
14
use allejo\stakx\Document\TemplateReadyDocument;
15
use allejo\stakx\Filesystem\File;
16
use allejo\stakx\Service;
17
use allejo\stakx\Filesystem\FileExplorer;
18
19
/**
20
 * Class TrackingManager.
21
 */
22
abstract class TrackingManager extends BaseManager
23
{
24
    /**
25
     * @var FileExplorer
26
     */
27
    protected $fileExplorer;
28
29
    /**
30
     * An array corresponding with $folderDefinitions to store metadata regarding a specificc folder.
31
     *
32
     * $folderDefinitionsOption['<folder path>'] = array()
33
     *
34
     * @var string[]
35
     */
36
    protected $folderDefinitionsOptions;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $folderDefinitionsOptions exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
37
38
    /**
39
     * An array of folders which tracked items are stored in.
40
     *
41
     * $folderDefinitions[] = '<folder path>'
42
     *
43
     * @var string[]
44
     */
45
    protected $folderDefinitions;
46
47
    /**
48
     * The storage which contains the same information as $trackedItems but organized by relative file path instead of a
49
     * namespace or file name without extension.
50
     *
51
     * $trackedItemsOptions['<relative file path>'] = mixed
52
     *
53
     * @var ReadableDocument[]
54
     */
55
    protected $trackedItemsFlattened;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $trackedItemsFlattened exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
56
57
    /**
58
     * The storage used to cache any information needed for a specific FrontMatterObject or DataItem.
59
     *
60
     * For example, with a DataItem, which is just an array, the file path to the original file can be stored in this
61
     * array to be accessible in the future to refresh the contents without parsing all of the files again.
62
     *
63
     * $trackedItemsOptions['<relative file path>'] = array
64
     *
65
     * @var array
66
     */
67
    protected $trackedItemsOptions;
68
69
    /**
70
     * The storage used for ReadableDocument in the respective static classes.
71
     *
72
     * $trackedItems['<namespace>']['<file name w/o extension>'] = mixed
73
     * $trackedItems['<file name w/o extension>'] = mixed
74
     *
75
     * @var ReadableDocument[]
76
     */
77
    protected $trackedItems;
78
79 42
    public function __construct()
80
    {
81 42
        parent::__construct();
82
83 42
        $this->folderDefinitionsOptions = array();
84 42
        $this->folderDefinitions = array();
85 42
        $this->trackedItemsFlattened = array();
86 42
        $this->trackedItemsOptions = array();
87 42
        $this->trackedItems = array();
88 42
    }
89
90
    /**
91
     * @param File|string $filePath
92
     *
93
     * @return mixed|null
94
     */
95
    public function createNewItem($filePath)
96
    {
97
        return $this->handleTrackableItem($filePath);
0 ignored issues
show
Bug introduced by
It seems like $filePath defined by parameter $filePath on line 95 can also be of type string; however, allejo\stakx\Manager\Tra...::handleTrackableItem() does only seem to accept object<allejo\stakx\Filesystem\File>, maybe add an additional type check?

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.

Loading history...
98
    }
99
100
    /**
101
     * Check whether a file is already being tracked.
102
     *
103
     * @param string $filePath The relative path of the file
104
     *
105
     * @return bool
106
     */
107 1
    public function isTracked($filePath)
108
    {
109 1
        return array_key_exists((string)$filePath, $this->trackedItemsFlattened);
110
    }
111
112
    /**
113
     * Check to see if a given file path matches this tracker's definition and would be tracked.
114
     *
115
     * This function should be used to check whether or not to add a file to this tracker after the initial scan has
116
     * already happened.
117
     *
118
     * @param string $filePath
119
     *
120
     * @return bool True if the file is inside a tracked folder
121
     */
122
    public function shouldBeTracked($filePath)
123
    {
124
        foreach ($this->folderDefinitions as $folder)
125
        {
126
            if (substr($filePath, 0, strlen($folder)) === $folder)
127
            {
128
                return true;
129
            }
130
        }
131
132
        return false;
133
    }
134
135
    /**
136
     * Update the contents of a specified file.
137
     *
138
     * @param File|string $filePath The relative path of the file
139
     *
140
     * @return mixed|null
141
     */
142
    public function refreshItem($filePath)
143
    {
144
        return $this->handleTrackableItem($filePath);
0 ignored issues
show
Bug introduced by
It seems like $filePath defined by parameter $filePath on line 142 can also be of type string; however, allejo\stakx\Manager\Tra...::handleTrackableItem() does only seem to accept object<allejo\stakx\Filesystem\File>, maybe add an additional type check?

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.

Loading history...
145
    }
146
147
    ///
148
    // Internal object handling
149
    ///
150
151
    protected function addFileToTracker(File &$file)
152
    {
153
        $this->trackedItemsFlattened[$file->getRelativeFilePath()] = &$file;
154
    }
155
156
    protected function delFileFromTracker(File &$file)
157
    {
158
        unset($this->trackedItemsFlattened[$file->getRelativeFilePath()]);
159
    }
160
161
    /**
162
     * Add a ReadableDocument to the tracker.
163
     *
164
     * @param ReadableDocument $trackedItem
165
     * @param string|null       $namespace
166
     */
167 41
    protected function addObjectToTracker(ReadableDocument &$trackedItem, $namespace = null)
168
    {
169 41
        if ($namespace == null)
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $namespace of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
170 41
        {
171 1
            $this->trackedItems[$trackedItem->getIndexName()] = &$trackedItem;
172 1
        }
173
        else
174
        {
175 40
            $this->trackedItems[$namespace][$trackedItem->getIndexName()] = &$trackedItem;
176
        }
177
178 41
        $this->trackedItemsFlattened[$trackedItem->getIndexName()] = &$trackedItem;
179 41
    }
180
181
    /**
182
     * Remove an entry from the tracked items array.
183
     *
184
     * @param ReadableDocument $trackedItem
185
     * @param string|null       $namespace
186
     */
187
    protected function delObjectFromTracker(ReadableDocument &$trackedItem, $namespace = null)
188
    {
189
        if ($namespace == null)
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $namespace of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
190
        {
191
            unset($this->trackedItems[$trackedItem->getIndexName()]);
192
        }
193
        else
194
        {
195
            unset($this->trackedItems[$namespace][$trackedItem->getIndexName()]);
196
        }
197
198
        unset($this->trackedItemsFlattened[$trackedItem->getIndexName()]);
199
    }
200
201
    ///
202
    // Extra options stored for future use
203
    ///
204
205
    /**
206
     * Save a folder that is tracked by this manager and its respective options.
207
     *
208
     * @param string $folderPath
209
     * @param array  $options
210
     */
211 39
    protected function saveFolderDefinition($folderPath, array $options = array())
212
    {
213 39
        $this->folderDefinitions[] = $folderPath;
214 39
        $this->folderDefinitionsOptions[$folderPath] = $options;
215 39
    }
216
217
    /**
218
     * Save any options related to an item needed in order to refresh the content.
219
     *
220
     * @param string $filePath
221
     * @param array  $options
222
     */
223 2
    protected function saveTrackerOptions($filePath, array $options = array())
224
    {
225 2
        $this->trackedItemsOptions[$filePath] = $options;
226 2
    }
227
228
    /**
229
     * Delete any options that were saved corresponding to an item.
230
     *
231
     * @param string $filePath
232
     */
233
    protected function forgetTrackerOptions($filePath)
234
    {
235
        unset($this->trackedItemsOptions[$filePath]);
236
    }
237
238
    ///
239
    // Handling of trackable items
240
    ///
241
242
    /**
243
     * Parse the specified folder for items to track.
244
     *
245
     * @param string $path
246
     * @param array  $options  Special options that will be passed to the static::parseTrackableItem() implementation
247
     * @param array  $includes
248
     * @param array  $excludes
249
     */
250 41
    protected function scanTrackableItems($path, array $options = array(), array $includes = array(), array $excludes = array())
251
    {
252 41
        $this->folderDefinitions[] = $this->fs->getRelativePath($path);
253
254 41
        $excludes = empty($excludes) ? self::$documentIgnoreList : $excludes;
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $excludes. This often makes code more readable.
Loading history...
255
256 41
        $fileExplorerFlags = array_key_exists('fileExplorer', $options) ? $options['fileExplorer'] : null;
257 41
        $this->fileExplorer = FileExplorer::create($path, $excludes, $includes, $fileExplorerFlags);
258 41
        $fileExplorer = $this->fileExplorer->getExplorer();
259
260 41
        foreach ($fileExplorer as $file)
261
        {
262 41
            $this->handleTrackableItem($file, $options);
263 41
        }
264 41
    }
265
266
    /**
267
     * Handle a specific file type, parse it into the appropriate object type, and add it to the tracker.
268
     *
269
     * This function should make use of the appropriate functions:
270
     *
271
     *  - TrackingManager::addObjectToTracker()
272
     *  - TrackingManager::addFileToTracker()
273
     *  - TrackingManager::saveTrackerOptions()
274
     *
275
     * @param File  $filePath
276
     * @param array $options
277
     *
278
     * @return mixed|null
279
     */
280
    abstract protected function handleTrackableItem($filePath, array $options = array());
281
282
    ///
283
    // Utility functions
284
    ///
285
286
    /**
287
     * Return an array of JailedDocuments created from the tracked items
288
     *
289
     * @param array    $elements
290
     * @param \Closure $name
0 ignored issues
show
Documentation introduced by
Should the type for parameter $name not be null|\Closure?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
291
     *
292
     * @return JailedDocument[]|JailedDocument[][]
293
     */
294 21
    protected static function getJailedTrackedItems(array &$elements, \Closure $name = null)
295
    {
296 21
        $jailItems = array();
297
298
        /**
299
         * @var string                           $key
300
         * @var CollectableItem|ReadableDocument $item
301
         */
302 21
        foreach ($elements as &$item)
303
        {
304 21
            if ($item instanceof TemplateReadyDocument)
305 21
            {
306 21
                if (!Service::getParameter(BuildableCommand::USE_DRAFTS) && $item->isDraft())
307 21
                {
308 1
                    continue;
309
                }
310 21
            }
311
312 21
            $keyName = ($name === null) ? $item->getRelativeFilePath() : $name($item);
313
314 21
            if (empty($item->getNamespace()))
315 21
            {
316 1
                $jailItems[$keyName] = $item->createJail();
317 1
            }
318
            else
319
            {
320 20
                $jailItems[$item->getNamespace()][$keyName] = $item->createJail();
321
            }
322 21
        }
323
324 21
        return $jailItems;
325
    }
326
}
327