1 | <?php |
||
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 $cache; |
||
|
|||
29 | |||
30 | /** |
||
31 | * The cache key. |
||
32 | * |
||
33 | * @var string |
||
34 | */ |
||
35 | private string $cacheKey; |
||
36 | |||
37 | /** |
||
38 | * Documentation resource directory. |
||
39 | * |
||
40 | * @var string |
||
41 | */ |
||
42 | private string $documentationDirectory; |
||
43 | |||
44 | /** |
||
45 | * @var Filesystem |
||
46 | */ |
||
47 | private Filesystem $filesystem; |
||
48 | |||
49 | /** |
||
50 | * @var ConfigProvider |
||
51 | */ |
||
52 | private ConfigProvider $configProvider; |
||
53 | |||
54 | /** |
||
55 | * @var MarkdownParser |
||
56 | */ |
||
57 | private MarkdownParser $markdownParser; |
||
58 | |||
59 | /** |
||
60 | * Create a new documentation instance. |
||
61 | * |
||
62 | * @throws BadImplementation |
||
63 | */ |
||
64 | public function __construct( |
||
65 | Filesystem $filesystem, |
||
66 | Cache $cache, |
||
67 | ConfigProvider $configProvider, |
||
68 | MarkdownParser $markdownParser |
||
69 | ) { |
||
70 | $this->filesystem = $filesystem; |
||
71 | $this->cache = $cache; |
||
72 | $this->configProvider = $configProvider; |
||
73 | $this->documentationDirectory = $configProvider->getDocumentationDirectory(); |
||
74 | $this->cacheKey = $this->configProvider->getCacheKey(); |
||
75 | $this->markdownParser = $markdownParser; |
||
76 | $documentationDirectoryAbsolutePath = base_path($this->documentationDirectory); |
||
77 | |||
78 | if (!$this->filesystem->isDirectory($documentationDirectoryAbsolutePath)) { |
||
79 | throw new BadImplementation(sprintf('Documentation resource directory `%s` does not exist.', $this->documentationDirectory)); |
||
80 | } |
||
81 | } |
||
82 | |||
83 | /** |
||
84 | * @throws InvalidArgumentException |
||
85 | * @throws FileNotFoundException |
||
86 | */ |
||
87 | public function getPage(Product $product, string $version, string $page = null): string |
||
88 | { |
||
89 | $page = $page ?? self::PAGE_INDEX; |
||
90 | $cacheKey = sprintf('%s.%s.%s.%s', $this->cacheKey, $product->getKey(), $version, $page); |
||
91 | |||
92 | if ($this->cache->has($cacheKey)) { |
||
93 | return $this->cache->get($cacheKey); |
||
94 | } |
||
95 | |||
96 | $pageContent = $this->getPageContent($product, $version, $page); |
||
97 | |||
98 | $this->cache->put($cacheKey, $pageContent, self::CACHE_TIMEOUT_SECONDS); |
||
99 | |||
100 | return $pageContent; |
||
101 | } |
||
102 | |||
103 | public function replaceLinks(Product $product, string $version, string $content): string |
||
104 | { |
||
105 | $routePrefix = $this->configProvider->getRoutePrefix(); |
||
106 | $versionPlaceholder = '{{version}}'; |
||
107 | |||
108 | // ensure product name exists in url |
||
109 | if (!empty($product)) { |
||
110 | $content = str_replace( |
||
111 | sprintf('docs/%s', $versionPlaceholder), |
||
112 | sprintf('%s/%s/%s', $routePrefix, $product->getKey(), $version), |
||
113 | $content |
||
114 | ); |
||
115 | } |
||
116 | |||
117 | return str_replace($versionPlaceholder, $version, $content); |
||
118 | } |
||
119 | |||
120 | public function sectionExists(Product $product, string $version, string $page): bool |
||
121 | { |
||
122 | $filePath = $this->getFilePathForProductPage($product, $version, $page); |
||
123 | |||
124 | return $this->filesystem->exists($filePath); |
||
125 | } |
||
126 | |||
127 | private function getFilePathForProductPage(Product $product, string $version, string $page): string |
||
128 | { |
||
129 | $directory = $product->getDirectory(); |
||
130 | $filename = ($page === self::PAGE_INDEX) ? $this->configProvider->getContentIndexPageName() : $page; |
||
131 | |||
132 | return sprintf('%s/%s/%s.%s', $directory, $version, $filename, self::FILE_EXTENSION); |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * @throws FileNotFoundException |
||
137 | */ |
||
138 | private function getPageContent(Product $product, string $version, string $page): string |
||
139 | { |
||
140 | $filePath = $this->getFilePathForProductPage($product, $version, $page); |
||
141 | $pageContent = ''; |
||
142 | |||
143 | if ($this->filesystem->exists($filePath)) { |
||
144 | $fileContents = $this->filesystem->get($filePath); |
||
145 | $pageContent = $this->replaceLinks( |
||
146 | $product, |
||
147 | $version, |
||
148 | $this->markdownParser->parse($fileContents) |
||
149 | ); |
||
150 | } |
||
151 | |||
152 | return $pageContent; |
||
153 | } |
||
154 | } |
||
155 |