Completed
Push — master ( 91746d...c63af8 )
by ReliQ
09:16
created

Provider::getPage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
cc 2
nc 2
nop 3
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
23
    /**
24
     * The cache implementation.
25
     *
26
     * @var Cache
27
     */
28
    private $cache;
29
30
    /**
31
     * The cache key.
32
     *
33
     * @var string
34
     */
35
    private $cacheKey;
36
37
    /**
38
     * Documentation resource directory.
39
     *
40
     * @var string
41
     */
42
    private $documentationDirectory;
43
44
    /**
45
     * @var Filesystem
46
     */
47
    private $filesystem;
48
49
    /**
50
     * @var ConfigProvider
51
     */
52
    private $configProvider;
53
54
    /**
55
     * @var MarkdownParser
56
     */
57
    private $markdownParser;
58
59
    /**
60
     * Create a new documentation instance.
61
     *
62
     * @param Filesystem     $filesystem
63
     * @param Cache          $cache
64
     * @param ConfigProvider $configProvider
65
     * @param MarkdownParser $markdownParser
66
     *
67
     * @throws BadImplementation
68
     */
69
    public function __construct(
70
        Filesystem $filesystem,
71
        Cache $cache,
72
        ConfigProvider $configProvider,
73
        MarkdownParser $markdownParser
74
    ) {
75
        $this->filesystem = $filesystem;
76
        $this->cache = $cache;
77
        $this->configProvider = $configProvider;
78
        $this->documentationDirectory = $configProvider->getDocumentationDirectory();
79
        $this->cacheKey = $this->configProvider->getCacheKey();
80
        $this->markdownParser = $markdownParser;
81
        $documentationDirectoryAbsolutePath = base_path($this->documentationDirectory);
82
83
        if (!$this->filesystem->isDirectory($documentationDirectoryAbsolutePath)) {
84
            throw new BadImplementation(
85
                sprintf(
86
                    'Documentation resource directory `%s` does not exist.',
87
                    $this->documentationDirectory
88
                )
89
            );
90
        }
91
    }
92
93
    /**
94
     * @param Product     $product
95
     * @param string      $version
96
     * @param null|string $page
97
     *
98
     * @throws InvalidArgumentException
99
     * @throws FileNotFoundException
100
     *
101
     * @return string
102
     */
103
    public function getPage(Product $product, string $version, string $page = null): string
104
    {
105
        $page = $page ?? self::PAGE_INDEX;
106
        $cacheKey = sprintf('%s.%s.%s.%s', $this->cacheKey, $product->getKey(), $version, $page);
107
108
        if ($this->cache->has($cacheKey)) {
109
            return $this->cache->get($cacheKey);
110
        }
111
112
        $pageContent = $this->getPageContent($product, $version, $page);
113
114
        $this->cache->put($cacheKey, $pageContent, self::CACHE_TIMEOUT_SECONDS);
115
116
        return $pageContent;
117
    }
118
119
    /**
120
     * @param Product $product
121
     * @param string  $version
122
     * @param string  $content
123
     *
124
     * @return string
125
     */
126
    public function replaceLinks(Product $product, string $version, string $content): string
127
    {
128
        $routePrefix = $this->configProvider->getRoutePrefix();
129
        $versionPlaceholder = '{{version}}';
130
131
        // ensure product name exists in url
132
        if (!empty($product)) {
133
            $content = str_replace(
134
                sprintf('docs/%s', $versionPlaceholder),
135
                sprintf('%s/%s/%s', $routePrefix, $product->getKey(), $version),
136
                $content
137
            );
138
        }
139
140
        return str_replace($versionPlaceholder, $version, $content);
141
    }
142
143
    /**
144
     * @param Product $product
145
     * @param string  $version
146
     * @param string  $page
147
     *
148
     * @return bool
149
     */
150
    public function sectionExists(Product $product, string $version, string $page): bool
151
    {
152
        $filePath = $this->getFilePathForProductPage($product, $version, $page);
153
154
        return $this->filesystem->exists($filePath);
155
    }
156
157
    /**
158
     * @param Product $product
159
     * @param string  $version
160
     * @param string  $page
161
     *
162
     * @return string
163
     */
164
    private function getFilePathForProductPage(Product $product, string $version, string $page): string
165
    {
166
        $directory = $product->getDirectory();
167
        $filename = ($page === self::PAGE_INDEX) ? $this->configProvider->getContentIndexPageName() : $page;
168
169
        return sprintf('%s/%s/%s.%s', $directory, $version, $filename, self::FILE_EXTENSION);
170
    }
171
172
    /**
173
     * @param Product $product
174
     * @param string  $version
175
     * @param string  $page
176
     *
177
     * @throws FileNotFoundException
178
     *
179
     * @return string
180
     */
181
    private function getPageContent(Product $product, string $version, string $page): string
182
    {
183
        $filePath = $this->getFilePathForProductPage($product, $version, $page);
184
        $pageContent = '';
185
186
        if ($this->filesystem->exists($filePath)) {
187
            $fileContents = $this->filesystem->get($filePath);
188
            $pageContent = $this->replaceLinks(
189
                $product,
190
                $version,
191
                $this->markdownParser->parse($fileContents)
192
            );
193
        }
194
195
        return $pageContent;
196
    }
197
}
198