Passed
Push — master ( 2d5d29...0740c8 )
by ReliQ
04:50 queued 13s
created

Provider::sectionExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ReliqArts\Docweaver\Service\Documentation;
6
7
use Illuminate\Contracts\Cache\Repository as Cache;
8
use Illuminate\Contracts\Filesystem\FileNotFoundException;
9
use Psr\SimpleCache\InvalidArgumentException;
10
use ReliqArts\Docweaver\Contract\ConfigProvider;
11
use ReliqArts\Docweaver\Contract\Documentation\Provider as ProviderContract;
12
use ReliqArts\Docweaver\Contract\Filesystem;
13
use ReliqArts\Docweaver\Contract\MarkdownParser;
14
use ReliqArts\Docweaver\Exception\BadImplementation;
15
use ReliqArts\Docweaver\Model\Product;
16
17
final class Provider implements ProviderContract
18
{
19
    private const CACHE_TIMEOUT_SECONDS = 60 * 5;
20
    private const PAGE_INDEX = 'index';
21
    private const FILE_EXTENSION = 'md';
22
    private const VERSION_PLACEHOLDER = '{{version}}';
23
24
    /**
25
     * The cache implementation.
26
     *
27
     * @var Cache
28
     */
29
    private Cache $cache;
30
31
    /**
32
     * The cache key.
33
     *
34
     * @var string
35
     */
36
    private string $cacheKey;
37
38
    /**
39
     * @var Filesystem
40
     */
41
    private Filesystem $filesystem;
42
43
    /**
44
     * @var ConfigProvider
45
     */
46
    private ConfigProvider $configProvider;
47
48
    /**
49
     * @var MarkdownParser
50
     */
51
    private MarkdownParser $markdownParser;
52
53
    /**
54
     * Create a new documentation instance.
55
     *
56
     * @throws BadImplementation
57
     */
58
    public function __construct(
59
        Filesystem $filesystem,
60
        Cache $cache,
61
        ConfigProvider $configProvider,
62
        MarkdownParser $markdownParser
63
    ) {
64
        $this->filesystem = $filesystem;
65
        $this->cache = $cache;
66
        $this->configProvider = $configProvider;
67
        $this->cacheKey = $this->configProvider->getCacheKey();
68
        $this->markdownParser = $markdownParser;
69
        $documentationDirectory = $configProvider->getDocumentationDirectory();
70
        $documentationDirectoryAbsolutePath = base_path($documentationDirectory);
71
72
        if (!$this->filesystem->isDirectory($documentationDirectoryAbsolutePath)) {
73
            throw new BadImplementation(sprintf('Documentation resource directory `%s` does not exist.', $documentationDirectory));
74
        }
75
    }
76
77
    /**
78
     * @throws InvalidArgumentException
79
     * @throws FileNotFoundException
80
     */
81
    public function getPage(Product $product, string $version, string $page = null): string
82
    {
83
        $page = $page ?? self::PAGE_INDEX;
84
        $cacheKey = sprintf('%s.%s.%s.%s', $this->cacheKey, $product->getKey(), $version, $page);
85
86
        if ($this->cache->has($cacheKey)) {
87
            return $this->cache->get($cacheKey);
88
        }
89
90
        $pageContent = $this->getPageContent($product, $version, $page);
91
92
        $this->cache->put($cacheKey, $pageContent, self::CACHE_TIMEOUT_SECONDS);
93
94
        return $pageContent;
95
    }
96
97
    public function replaceLinks(Product $product, string $version, string $originalContent): string
98
    {
99
        $routePrefix = $this->configProvider->getRoutePrefix();
100
        $versionPlaceholder = urlencode(self::VERSION_PLACEHOLDER);
101
        $originalLinkPath = sprintf('docs/%s', $versionPlaceholder);
102
        $linkPathReplacement = sprintf('%s/%s/%s', $routePrefix, $product->getKey(), $version);
103
104
        return str_replace([$originalLinkPath, $versionPlaceholder], [$linkPathReplacement, $version], $originalContent);
105
    }
106
107
    public function sectionExists(Product $product, string $version, string $page): bool
108
    {
109
        $filePath = $this->getFilePathForProductPage($product, $version, $page);
110
111
        return $this->filesystem->exists($filePath);
112
    }
113
114
    private function getFilePathForProductPage(Product $product, string $version, string $page): string
115
    {
116
        $directory = $product->getDirectory();
117
        $filename = ($page === self::PAGE_INDEX) ? $this->configProvider->getContentIndexPageName() : $page;
118
119
        return sprintf('%s/%s/%s.%s', $directory, $version, $filename, self::FILE_EXTENSION);
120
    }
121
122
    /**
123
     * @throws FileNotFoundException
124
     */
125
    private function getPageContent(Product $product, string $version, string $page): string
126
    {
127
        $filePath = $this->getFilePathForProductPage($product, $version, $page);
128
        $pageContent = '';
129
130
        if ($this->filesystem->exists($filePath)) {
131
            $fileContents = $this->filesystem->get($filePath);
132
            $pageContent = $this->replaceLinks(
133
                $product,
134
                $version,
135
                $this->markdownParser->parse($fileContents)
136
            );
137
        }
138
139
        return $pageContent;
140
    }
141
}
142