Completed
Push — master ( a49358...a99fa5 )
by Mikael
03:35
created

CFileBasedContent::load()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 19
ccs 0
cts 10
cp 0
rs 9.2
cc 4
eloc 12
nc 3
nop 1
crap 20
1
<?php
2
3
namespace Anax\Content;
4
5
/**
6
 * Pages based on file content.
7
 */
8
class CFileBasedContent
9
{
10
    use \Anax\TConfigure,
11
        \Anax\DI\TInjectionAware,
12
        TFBCBreadcrumb,
13
        TFBCLoadAdditionalContent,
14
        TFBCUtilities;
15
16
17
18
    /**
19
     * All routes.
20
     */
21
    private $index = null;
22
23
    /**
24
     * All authors.
25
     */
26
    private $author = null;
27
28
    /**
29
     * All categories.
30
     */
31
    private $category = null;
32
33
    /**
34
     * All routes having meta.
35
     */
36
    private $meta = null;
37
38
    /**
39
     * This is the base route.
40
     */
41
    private $baseRoute = null;
42
43
    /**
44
     * This is the extendede meta route, if any.
45
     */
46
    private $metaRoute = null;
47
48
    /**
49
     * This is the current page, to supply pagination, if used.
50
     */
51
    private $currentPage = null;
52
53
    /**
54
     * Use cache or recreate each time.
55
     */
56
    private $ignoreCache = false;
57
    
58
    /**
59
     * File name pattern, all files must match this pattern and the first
60
     * numbered part is optional, the second part becomes the route.
61
     */
62
    private $filenamePattern = "#^(\d*)_*([^\.]+)\.md$#";
63
64
    /**
65
     * Internal routes that is marked as internal content routes and not
66
     * exposed as public routes.
67
     */
68
    private $internalRouteDirPattern = [
69
        "#block/#",
70
    ];
71
72
    private $internalRouteFilePattern = [
73
        "#^block[_-]{1}#",
74
        "#^_#",
75
    ];
76
77
    /**
78
     * Routes that should be used in toc.
79
     */
80
    private $allowedInTocPattern = "([\d]+_(\w)+)";
81
82
83
84
    /**
85
     * Set default values from configuration.
86
     *
87
     * @return this.
0 ignored issues
show
Documentation introduced by
The doc-type this. could not be parsed: Unknown type name "this." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
88
     */
89
    public function setDefaultsFromConfiguration()
90
    {
91
        $this->ignoreCache = isset($this->config["ignoreCache"])
92
            ? $this->config["ignoreCache"]
93
            : $this->ignoreCache;
94
95
        return $this;
96
    }
97
98
99
100
    /**
101
     * Should the cache be used or ignored.
102
     *
103
     * @param boolean $use true to use the cache or false to ignore the cache
104
     *
105
     * @return this.
0 ignored issues
show
Documentation introduced by
The doc-type this. could not be parsed: Unknown type name "this." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
106
     */
107
    public function useCache($use)
108
    {
109
        $this->ignoreCache = !$use;
110
111
        return $this;
112
    }
113
114
115
116
    /**
117
     * Create the index of all content into an array.
118
     *
119
     * @param string $type of index to load.
120
     *
121
     * @return void.
0 ignored issues
show
Documentation introduced by
The doc-type void. could not be parsed: Unknown type name "void." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
122
     */
123
    private function load($type)
124
    {
125
        $index = $this->$type;
126
        if ($index) {
127
            return;
128
        }
129
130
        $cache = $this->di->get("cache");
131
        $key = $cache->createKey(__CLASS__, $type);
132
        $index = $cache->get($key);
133
134
        if (is_null($index) || $this->ignoreCache) {
135
            $createMethod = "create$type";
136
            $index = $this->$createMethod();
137
            $cache->put($key, $index);
138
        }
139
140
        $this->$type = $index;
141
    }
142
143
144
145
146
    // = Create and manage index ==================================
147
148
    /**
149
     * Generate an index from the directory structure.
150
     *
151
     * @return array as index for all content files.
152
     */
153
    private function createIndex()
154
    {
155
        $basepath   = $this->config["basepath"];
156
        $pattern    = $this->config["pattern"];
157
        $path       = "$basepath/$pattern";
158
159
        $index = [];
160
        foreach (glob_recursive($path) as $file) {
161
            $filepath = substr($file, strlen($basepath) + 1);
162
163
            // Find content files
164
            $matches = [];
165
            preg_match($this->filenamePattern, basename($filepath), $matches);
166
            $dirpart = dirname($filepath) . "/";
167
            if ($dirpart === "./") {
168
                $dirpart = null;
169
            }
170
            $key = $dirpart . $matches[2];
171
            
172
            // Create level depending on the file id
173
            // TODO ciamge doc, can be replaced by __toc__ in meta?
174
            $id = $matches[1];
175
            $level = 2;
176 View Code Duplication
            if ($id % 100 === 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
177
                $level = 0;
178
            } elseif ($id % 10 === 0) {
179
                $level = 1;
180
            }
181
182
            $index[$key] = [
183
                "file"     => $filepath,
184
                "section"  => $matches[1],
185
                "level"    => $level,  // TODO ?
186
                "internal" => $this->isInternalRoute($filepath),
187
                "tocable"  => $this->allowInToc($filepath),
188
            ];
189
        }
190
191
        return $index;
192
    }
193
194
195
196
    /**
197
     * Check if a filename is to be marked as an internal route..
198
     *
199
     * @param string $filepath as the basepath (routepart) to the file.
200
     *
201
     * @return boolean true if the route content is internal, else false
202
     */
203
    private function isInternalRoute($filepath)
204
    {
205
        foreach ($this->internalRouteDirPattern as $pattern) {
206
            if (preg_match($pattern, $filepath)) {
207
                return true;
208
            }
209
        }
210
211
        $filename = basename($filepath);
212
        foreach ($this->internalRouteFilePattern as $pattern) {
213
            if (preg_match($pattern, $filename)) {
214
                return true;
215
            }
216
        }
217
218
        return false;
219
    }
220
221
222
223
    /**
224
     * Check if filepath should be used as part of toc.
225
     *
226
     * @param string $filepath as the basepath (routepart) to the file.
227
     *
228
     * @return boolean true if the route content shoul dbe in toc, else false
229
     */
230
    private function allowInToc($filepath)
231
    {
232
        return (boolean) preg_match($this->allowedInTocPattern, $filepath);
233
    }
234
235
236
237
    // = Create and manage meta ==================================
238
239
    /**
240
     * Generate an index for meta files.
241
     *
242
     * @return array as meta index.
243
     */
244
    private function createMeta()
245
    {
246
        $basepath = $this->config["basepath"];
247
        $filter   = $this->config["textfilter-frontmatter"];
248
        $pattern  = $this->config["meta"];
249
        $path     = "$basepath/$pattern";
250
        $textfilter = $this->di->get("textFilter");
251
252
        $index = [];
253
        foreach (glob_recursive($path) as $file) {
254
            // The key entry to index
255
            $key = dirname(substr($file, strlen($basepath) + 1));
256
257
            // Get info from base document
258
            $src = file_get_contents($file);
259
            $filtered = $textfilter->parse($src, $filter);
260
            $index[$key] = $filtered->frontmatter;
261
262
            // Add Toc to the data array
263
            $index[$key]["__toc__"] = $this->createBaseRouteToc($key);
264
        }
265
266
        // Add author details
267
        $this->meta = $index;
268
        $this->createAuthor();
269
        $this->createCategory();
270
271
        return $this->meta;
272
    }
273
274
275
276
    /**
277
     * Get a reference to meta data for specific route.
278
     *
279
     * @param string $route current route used to access page.
280
     *
281
     * @return array as table of content.
282
     */
283
    private function getMetaForRoute($route)
284
    {
285
        $base = dirname($route);
286
        return isset($this->meta[$base])
287
            ? $this->meta[$base]
288
            : [];
289
    }
290
291
292
293
    /**
294
     * Create a table of content for routes at particular level.
295
     *
296
     * @param string $route base route to use.
297
     *
298
     * @return array as the toc.
299
     */
300
    private function createBaseRouteToc($route)
301
    {
302
        $toc = [];
303
        $len = strlen($route);
304
305
        foreach ($this->index as $key => $value) {
306
            if (substr($key, 0, $len) === $route) {
307
                if ($value["internal"] === false
308
                    && $value["tocable"] === true) {
309
                    $toc[$key] = $value;
310
                    
311
                    $frontm = $this->getFrontmatter($value["file"]);
312
                    $toc[$key]["title"] = $frontm["title"];
313
                    $toc[$key]["publishTime"] = $this->getPublishTime($frontm);
314
                    $toc[$key]["sectionHeader"] = isset($frontm["sectionHeader"])
315
                        ? $frontm["sectionHeader"]
316
                        : null;
317
                    $toc[$key]["linkable"] = isset($frontm["linkable"])
318
                        ? $frontm["linkable"]
319
                        : null;
320
                }
321
            }
322
        };
323
324
        return $toc;
325
    }
326
327
328
329
    // = Deal with authors ====================================
330
    
331
    /**
332
     * Generate a lookup index for authors that maps into the meta entry
333
     * for the author.
334
     *
335
     * @return void.
0 ignored issues
show
Documentation introduced by
The doc-type void. could not be parsed: Unknown type name "void." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
336
     */
337
    private function createAuthor()
338
    {
339
        $pattern = $this->config["author"];
340
341
        $index = [];
342
        $matches = [];
343
        foreach ($this->meta as $key => $entry) {
344
            if (preg_match($pattern, $key, $matches)) {
345
                $acronym = $matches[1];
346
                $index[$acronym] = $key;
347
                $this->meta[$key]["acronym"] = $acronym;
348
                $this->meta[$key]["url"] = $key;
349
                unset($this->meta[$key]["__toc__"]);
350
351
                // Get content for byline
352
                $route = "$key/byline";
353
                $data = $this->getDataForAdditionalRoute($route);
354
                $this->meta[$key]["byline"] = $data["content"];
355
            }
356
        }
357
358
        return $index;
359
    }
360
361
362
363
    /**
364
     * Load details for the author.
365
     *
366
     * @param array|string $author with details on the author(s).
367
     *
368
     * @return array with more details on the authors(s).
369
     */
370 View Code Duplication
    private function loadAuthorDetails($author)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
371
    {
372
        if (is_array($author) && is_array(array_values($author)[0])) {
373
            return $author;
374
        }
375
376
        if (!is_array($author)) {
377
            $tmp = $author;
378
            $author = [];
379
            $author[] = $tmp;
380
        }
381
382
        $authors = [];
383
        foreach ($author as $acronym) {
384
            if (isset($this->author[$acronym])) {
385
                $key = $this->author[$acronym];
386
                $authors[$acronym] = $this->meta[$key];
387
            } else {
388
                $authors[$acronym]["acronym"] = $acronym;
389
            }
390
        }
391
392
        return $authors;
393
    }
394
395
396
397
    // = Deal with categories ====================================
398
    
399
    /**
400
     * Generate a lookup index for categories that maps into the meta entry
401
     * for the category.
402
     *
403
     * @return void.
0 ignored issues
show
Documentation introduced by
The doc-type void. could not be parsed: Unknown type name "void." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
404
     */
405
    private function createCategory()
406
    {
407
        $pattern = $this->config["category"];
408
409
        $index = [];
410
        $matches = [];
411
        foreach ($this->meta as $key => $entry) {
412
            if (preg_match($pattern, $key, $matches)) {
413
                $catKey = $matches[1];
414
                $index[$catKey] = $key;
415
                $this->meta[$key]["key"] = $catKey;
416
                $this->meta[$key]["url"] = $key;
417
                unset($this->meta[$key]["__toc__"]);
418
            }
419
        }
420
421
        return $index;
422
    }
423
424
425
426
    /**
427
     * Find next and previous links of current content.
428
     *
429
     * @param array|string $author with details on the category(s).
0 ignored issues
show
Bug introduced by
There is no parameter named $author. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
430
     *
431
     * @return array with more details on the category(s).
432
     */
433 View Code Duplication
    private function loadCategoryDetails($category)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
434
    {
435
        if (is_array($category) && is_array(array_values($category)[0])) {
436
            return $category;
437
        }
438
439
        if (!is_array($category)) {
440
            $tmp = $category;
441
            $category = [];
442
            $category[] = $tmp;
443
        }
444
445
        $categorys = [];
446
        foreach ($category as $catKey) {
447
            if (isset($this->category[$catKey])) {
448
                $key = $this->category[$catKey];
449
                $categorys[$catKey] = $this->meta[$key];
450
            } else {
451
                $categorys[$catKey]["key"] = $catKey;
452
            }
453
        }
454
455
        return $categorys;
456
    }
457
458
459
460
461
    // == Used by meta and breadcrumb (to get title) ===========================
462
    // TODO REFACTOR THIS?
463
    // Support getting only frontmatter.
464
    // Merge with function that retrieves whole filtered since getting
465
    // frontmatter will involve full parsing of document.
466
    // Title is retrieved from the HTML code.
467
    // Also do cacheing of each retrieved and parsed document
468
    // in this cycle, to gather code that loads and parses a individual
469
    // document. 
470
    
471
    /**
472
     * Get the frontmatter of a document.
473
     *
474
     * @param string $file to get frontmatter from.
475
     *
476
     * @return array as frontmatter.
477
     */
478
    private function getFrontmatter($file)
479
    {
480
        $basepath = $this->config["basepath"];
481
        $filter1  = $this->config["textfilter-frontmatter"];
482
        $filter2  = $this->config["textfilter-title"];
483
        $filter = array_merge($filter1, $filter2);
484
        
485
        $path = $basepath . "/" . $file;
486
        $src = file_get_contents($path);
487
        $filtered = $this->di->get("textFilter")->parse($src, $filter);
488
        return $filtered->frontmatter;
489
    }
490
491
492
493
    // == Look up route in index ===================================
494
    
495
    /**
496
     * Check if currrent route is a supported meta route.
497
     *
498
     * @param string $route current route used to access page.
499
     *
500
     * @return string as route.
501
     */
502
    private function checkForMetaRoute($route)
503
    {
504
        $this->baseRoute = $route;
505
        $this->metaRoute = null;
506
507
        // If route exits in index, use it
508
        if ($this->mapRoute2IndexKey($route)) {
509
            return $route;
510
        }
511
512
        // Check for pagination
513
        $pagination = $this->config["pagination"];
514
        $matches = [];
515
        $pattern = "/(.*?)\/($pagination)\/(\d+)$/";
516
        if (preg_match($pattern, $route, $matches)) {
517
            $this->baseRoute = $matches[1];
518
            $this->metaRoute = $route;
519
            $this->currentPage = $matches[3];
520
        }
521
522
        return $this->baseRoute;
523
    }
524
525
526
527
    /**
528
     * Map the route to the correct key in the index.
529
     *
530
     * @param string $route current route used to access page.
531
     *
532
     * @return string as key or false if no match.
533
     */
534
    private function mapRoute2IndexKey($route)
535
    {
536
        $route = rtrim($route, "/");
537
538
        if (key_exists($route, $this->index)) {
539
            return $route;
540
        } elseif (empty($route) && key_exists("index", $this->index)) {
541
            return "index";
542
        } elseif (key_exists($route . "/index", $this->index)) {
543
            return "$route/index";
544
        }
545
546
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Anax\Content\CFileBasedContent::mapRoute2IndexKey of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
547
    }
548
549
550
551
    /**
552
     * Map the route to the correct entry in the index.
553
     *
554
     * @param string $route current route used to access page.
555
     *
556
     * @return array as the matched route.
557
     */
558
    private function mapRoute2Index($route)
559
    {
560
        $routeIndex = $this->mapRoute2IndexKey($route);
561
562
        if ($routeIndex) {
563
            return [$routeIndex, $this->index[$routeIndex]];
564
        }
565
566
        throw new \Anax\Exception\NotFoundException(t("The route '!ROUTE' does not exists in the index.", ["!ROUTE" => $route]));
567
    }
568
569
570
571
    // = Get view data by merging from meta and current frontmatter =========
572
    
573
    /**
574
     * Get view by mergin information from meta and frontmatter.
575
     *
576
     * @param string $route       current route used to access page.
577
     * @param array  $frontmatter for the content.
578
     * @param string $key         for the view to retrive.
579
     *
580
     * @return array with data to add as view.
581
     */
582
    private function getView($route, $frontmatter, $key)
583
    {
584
        $view = [];
585
586
        // From meta frontmatter
587
        $meta = $this->getMetaForRoute($route);
588
        if (isset($meta[$key])) {
589
            $view = $meta[$key];
590
        }
591
592
        // From document frontmatter
593
        if (isset($frontmatter[$key])) {
594
            $view = array_merge_recursive_distinct($view, $frontmatter[$key]);
595
            //$view = array_merge($view, $frontmatter[$key]);
596
        }
597
598
        return $view;
599
    }
600
601
602
603
    /**
604
     * Get details on extra views.
605
     *
606
     * @param string $route       current route used to access page.
607
     * @param array  $frontmatter for the content.
608
     *
609
     * @return array with page data to send to view.
610
     */
611
    private function getViews($route, $frontmatter)
612
    {
613
        // Arrange data into views
614
        $views = $this->getView($route, $frontmatter, "views", true);
0 ignored issues
show
Unused Code introduced by
The call to CFileBasedContent::getView() has too many arguments starting with true.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
615
616
        // Set defaults
617
        if (!isset($views["main"]["template"])) {
618
            $views["main"]["template"] = $this->config["template"];
619
        }
620
        if (!isset($views["main"]["data"])) {
621
            $views["main"]["data"] = [];
622
        }
623
624
        // Merge remaining frontmatter into view main data.
625
        $data = $this->getMetaForRoute($route);
626
        unset($data["__toc__"]);
627
        unset($data["views"]);
628
        unset($frontmatter["views"]);
629
630
        if ($frontmatter) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $frontmatter of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
631
            $data = array_merge_recursive_distinct($data, $frontmatter);
632
        }
633
        $views["main"]["data"] = array_merge_recursive_distinct($views["main"]["data"], $data);
634
635
        return $views;
636
    }
637
638
639
640
    // == Create and load content ===================================
641
642
    /**
643
     * Map url to content, even internal content, if such mapping can be done.
644
     *
645
     * @param string $route route to look up.
646
     *
647
     * @return object with content and filtered version.
648
     */
649
    private function createContentForInternalRoute($route)
650
    {
651
        // Load index and map route to content
652
        $this->load("index");
653
        $this->load("meta");
654
        $this->load("author");
655
        $this->load("category");
656
        
657
        // Match the route
658
        $route = rtrim($route, "/");
659
        $route = $this->checkForMetaRoute($route);
660
        list($routeIndex, $content, $filtered) = $this->mapRoute2Content($route);
661
662
        // Create and arrange the content as views, merge with .meta,
663
        // frontmatter is complete.
664
        $content["views"] = $this->getViews($routeIndex, $filtered->frontmatter);
665
666
        // Do process content step two when all frontmatter is included.
667
        $this->processMainContentPhaseTwo($content, $filtered);
668
        
669
        // Set details of content
670
        $content["views"]["main"]["data"]["content"] = $filtered->text;
671
        $content["views"]["main"]["data"]["excerpt"] = $filtered->excerpt;
672
        $this->loadAdditionalContent($content["views"], $route, $routeIndex);
673
674
        // TODO Should not supply all frontmatter to theme, only the
675
        // parts valid to the index template. Separate that data into own
676
        // holder in frontmatter. Do not include whole frontmatter? Only
677
        // on debg?
678
        $content["frontmatter"] = $filtered->frontmatter;
679
680
        return (object) $content;
681
    }
682
683
684
685
    /**
686
     * Look up the route in the index and use that to retrieve the filtered
687
     * content.
688
     *
689
     * @param string $route to look up.
690
     *
691
     * @return array with content and filtered version.
692
     */
693
    private function mapRoute2Content($route)
694
    {
695
        // Look it up in the index
696
        list($keyIndex, $content) = $this->mapRoute2Index($route);
697
        $filtered = $this->loadFileContentPhaseOne($keyIndex);
698
699
        return [$keyIndex, $content, $filtered];
700
    }
701
702
703
704
    /**
705
     * Load content file and frontmatter, this is the first time we process
706
     * the content.
707
     *
708
     * @param string $key     to index with details on the route.
709
     *
710
     * @throws NotFoundException when mapping can not be done.
711
     *
712
     * @return void.
0 ignored issues
show
Documentation introduced by
The doc-type void. could not be parsed: Unknown type name "void." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
713
     */
714
    private function loadFileContentPhaseOne($key)
715
    {
716
        // Settings from config
717
        $basepath = $this->config["basepath"];
718
        $filter   = $this->config["textfilter-frontmatter"];
719
720
        // Whole path to file
721
        $path = $basepath . "/" . $this->index[$key]["file"];
722
723
        // Load content from file
724
        if (!is_file($path)) {
725
            $msg = t("The content '!ROUTE' does not exists as a file '!FILE'.", ["!ROUTE" => $key, "!FILE" => $path]);
726
            throw new \Anax\Exception\NotFoundException($msg);
727
        }
728
729
        // Get filtered content
730
        $src = file_get_contents($path);
731
        $filtered = $this->di->get("textFilter")->parse($src, $filter);
732
733
        return $filtered;
734
    }
735
736
737
738
    // == Process content phase 2 ===================================
739
    // TODO REFACTOR THIS?
740
    
741
    /**
742
     * Look up the route in the index and use that to retrieve the filtered
743
     * content.
744
     *
745
     * @param array  &$content   to process.
746
     * @param object &$filtered to use for settings.
747
     *
748
     * @return array with content and filtered version.
749
     */
750
     private function processMainContentPhaseTwo(&$content, &$filtered)
751
     {
752
        // From configuration
753
         $filter = $this->config["textfilter"];
754
         $revisionStart = $this->config["revision-history"]["start"];
755
         $revisionEnd   = $this->config["revision-history"]["end"];
756
         $revisionClass = $this->config["revision-history"]["class"];
757
         
758
         $textFilter = $this->di->get("textFilter");
759
         $text = $filtered->text;
760
761
         // Check if revision history is to be included
762
         if (isset($content["views"]["main"]["data"]["revision"])) {
763
             $text = $textFilter->addRevisionHistory(
764
                 $text,
765
                 $content["views"]["main"]["data"]["revision"],
766
                 $revisionStart,
767
                 $revisionEnd,
768
                 $revisionClass
769
             );
770
         }
771
772
         // Get new filtered content (and updated frontmatter)
773
         $new = $textFilter->parse($text, $filter);
774
         $filtered->text = $new->text;
775
         if ($filtered->frontmatter) {
776
             $filtered->frontmatter = array_merge_recursive_distinct($filtered->frontmatter, $new->frontmatter);
777
         } else {
778
             $filtered->frontmatter = $new->frontmatter;
779
         }
780
781
         // Load details on author, if set.
782
         $data = &$content["views"]["main"]["data"];
783
         if (isset($data["author"])) {
784
             $data["author"] = $this->loadAuthorDetails($data["author"]);
785
         }
786
787
         // Load details on category, if set.
788
         if (isset($data["category"])) {
789
             $data["category"] = $this->loadCategoryDetails($data["category"]);
790
         }
791
792
         // Update all anchor urls to use baseurl, needs info about baseurl
793
         // from merged frontmatter
794
         $baseurl = isset($data["baseurl"])
795
            ? $data["baseurl"]
796
            : null;
797
         $this->addBaseurl2AnchorUrls($filtered, $baseurl);
798
799
         // Add excerpt and hasMore, if available
800
         $textFilter->addExcerpt($filtered);
801
    }
802
803
804
805
    // == Public methods ============================================
806
    
807
    /**
808
     * Map url to content, even internal content, if such mapping can be done.
809
     *
810
     * @param string $route optional route to look up.
811
     *
812
     * @return object with content and filtered version.
813
     */
814
    public function contentForInternalRoute($route = null)
815
    {
816
        // Get the route
817
        if (is_null($route)) {
818
            $route = $this->di->get("request")->getRoute();
819
        }
820
821
        // Check cache for content or create cached version of content
822
        $slug = $this->di->get("url")->slugify($route);
823
        $key = $this->di->cache->createKey(__CLASS__, "route-$slug");
824
        $content = $this->di->cache->get($key);
825
826
        if (!$content || $this->ignoreCache) {
827
            $content = $this->createContentForInternalRoute($route);
828
            $this->di->cache->put($key, $content);
829
        }
830
831
        return $content;
832
    }
833
834
835
836
    /**
837
     * Map url to content if such mapping can be done, exclude internal routes.
838
     *
839
     * @param string $route optional route to look up.
840
     *
841
     * @return object with content and filtered version.
842
     */
843
    public function contentForRoute($route = null)
844
    {
845
        $content = $this->contentForInternalRoute($route);
846
        if ($content->internal === true) {
847
            $msg = t("The content '!ROUTE' does not exists as a public route.", ["!ROUTE" => $route]);
848
            throw new \Anax\Exception\NotFoundException($msg);
849
        }
850
851
        return $content;
852
    }
853
}
854