7fb20c63248eba81029ff48757ba1266c5b6d261
[Packages/TYPO3.CMS.git] / typo3 / sysext / documentation / Classes / Domain / Repository / DocumentRepository.php
1 <?php
2 namespace TYPO3\CMS\Documentation\Domain\Repository;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Localization\Locales;
18 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Core\Utility\PathUtility;
21 use TYPO3\CMS\Documentation\Domain\Model\Document;
22 use TYPO3\CMS\Documentation\Domain\Model\DocumentFormat;
23 use TYPO3\CMS\Documentation\Domain\Model\DocumentTranslation;
24 use TYPO3\CMS\Documentation\Utility\MiscUtility;
25 use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
26 use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
27
28 /**
29 * An extension helper repository to be used in ext:documentation context
30 */
31 class DocumentRepository
32 {
33 /**
34 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
35 */
36 protected $objectManager;
37
38 /**
39 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
40 */
41 public function injectObjectManager(ObjectManagerInterface $objectManager)
42 {
43 $this->objectManager = $objectManager;
44 }
45
46 /**
47 * Finds all documents.
48 *
49 * @return \TYPO3\CMS\Documentation\Domain\Model\Document[]
50 */
51 public function findAll()
52 {
53 $documents = $this->findSphinxDocuments();
54 $openOfficeDocuments = $this->findOpenOfficeDocuments();
55
56 // Add OpenOffice documents if there is not already an existing, non OpenOffice version
57 foreach ($openOfficeDocuments as $documentKey => $document) {
58 if (!isset($documents[$documentKey])) {
59 $documents[$documentKey] = $document;
60 }
61 }
62
63 return $documents;
64 }
65
66 /**
67 * Finds documents by language, always falls back to 'default' (English).
68 *
69 * @param string $language
70 * @return \TYPO3\CMS\Documentation\Domain\Model\Document[]
71 */
72 public function findByLanguage($language)
73 {
74 $allDocuments = $this->findAll();
75
76 // Initialize the dependency of languages
77 $languageDependencies = [];
78 /** @var $locales \TYPO3\CMS\Core\Localization\Locales */
79 $locales = GeneralUtility::makeInstance(Locales::class);
80 // Language is found. Configure it:
81 $shortLanguage = $language;
82 if (!in_array($shortLanguage, $locales->getLocales()) && strpos($shortLanguage, '_') !== false) {
83 list($shortLanguage, $_) = explode('_', $shortLanguage);
84 }
85 if (in_array($shortLanguage, $locales->getLocales())) {
86 $languageDependencies[] = $language;
87 if ($language !== $shortLanguage) {
88 $languageDependencies[] = $shortLanguage;
89 }
90 foreach ($locales->getLocaleDependencies($shortLanguage) as $languageDependency) {
91 $languageDependencies[] = $languageDependency;
92 }
93 }
94 if ($language !== 'default') {
95 $languageDependencies[] = 'default';
96 }
97
98 foreach ($allDocuments as $document) {
99 // Remove every unwanted translation
100 $selectedTranslation = null;
101 $highestPriorityLanguageIndex = count($languageDependencies);
102
103 $translations = $document->getTranslations();
104 foreach ($translations as $translation) {
105 $languageIndex = array_search($translation->getLanguage(), $languageDependencies);
106 if ($languageIndex !== false) {
107 if ($languageIndex < $highestPriorityLanguageIndex) {
108 $selectedTranslation = $translation;
109 $highestPriorityLanguageIndex = $languageIndex;
110 }
111 } else {
112 // No exact translation found, perhaps another locale would fit as well. E.g., when requesting
113 // a documentation as fr_CA but only fr_FR exists
114 if (strpos($translation->getLanguage(), '_') !== false) {
115 list($translationLanguage, $_) = explode('_', $translation->getLanguage());
116 $languageIndex = array_search($translationLanguage, $languageDependencies);
117 if ($languageIndex !== false && $languageIndex < $highestPriorityLanguageIndex) {
118 $selectedTranslation = $translation;
119 $highestPriorityLanguageIndex = $languageIndex;
120 }
121 }
122 }
123 }
124
125 $newTranslations = new ObjectStorage();
126 $document->setTranslations($newTranslations);
127 if ($selectedTranslation !== null) {
128 $document->addTranslation($selectedTranslation);
129 }
130 }
131
132 return $allDocuments;
133 }
134
135 /**
136 * Retrieves Sphinx documents.
137 *
138 * @return array
139 */
140 protected function findSphinxDocuments()
141 {
142 $basePath = 'typo3conf/Documentation/';
143
144 $documents = [];
145 $documentKeys = GeneralUtility::get_dirs(PATH_site . $basePath);
146 // Early return in case no document keys were found
147 if (!is_array($documentKeys)) {
148 return $documents;
149 }
150
151 foreach ($documentKeys as $documentKey) {
152 $icon = MiscUtility::getIcon($documentKey);
153
154 /** @var \TYPO3\CMS\Documentation\Domain\Model\Document $document */
155 $document = $this->objectManager->get(Document::class)
156 ->setPackageKey($documentKey)
157 ->setIcon($icon);
158
159 $languagePath = $basePath . $documentKey . '/';
160 $languages = GeneralUtility::get_dirs(PATH_site . $languagePath);
161 foreach ($languages as $language) {
162 $metadata = $this->getMetadata($documentKey, $language);
163 if (!empty($metadata['extensionKey'])) {
164 $document->setExtensionKey($metadata['extensionKey']);
165 }
166
167 /** @var \TYPO3\CMS\Documentation\Domain\Model\DocumentTranslation $documentTranslation */
168 $documentTranslation = $this->objectManager->get(DocumentTranslation::class)
169 ->setLanguage($language)
170 ->setTitle($metadata['title'])
171 ->setDescription($metadata['description']);
172
173 $formatPath = $languagePath . $language . '/';
174 $formats = GeneralUtility::get_dirs(PATH_site . $formatPath);
175 foreach ($formats as $format) {
176 $documentFile = '';
177 switch ($format) {
178 case 'html':
179 // Try to find a valid index file
180 $indexFiles = ['Index.html', 'index.html', 'index.htm'];
181 foreach ($indexFiles as $indexFile) {
182 if (file_exists(PATH_site . $formatPath . $format . '/' . $indexFile)) {
183 $documentFile = $indexFile;
184 break;
185 }
186 }
187 break;
188 case 'pdf':
189 // Retrieve first PDF
190 $files = GeneralUtility::getFilesInDir(PATH_site . $formatPath . $format, 'pdf');
191 if (is_array($files) && !empty($files)) {
192 $documentFile = current($files);
193 }
194 break;
195 }
196 if (!empty($documentFile)) {
197 /** @var \TYPO3\CMS\Documentation\Domain\Model\DocumentFormat $documentFormat */
198 $documentFormat = $this->objectManager->get(DocumentFormat::class)
199 ->setFormat($format)
200 ->setPath($formatPath . $format . '/' . $documentFile);
201
202 $documentTranslation->addFormat($documentFormat);
203 }
204 }
205
206 if (!empty($documentTranslation->getFormats())) {
207 $document->addTranslation($documentTranslation);
208 $documents[$documentKey] = $document;
209 }
210 }
211 }
212
213 return $documents;
214 }
215
216 /**
217 * Retrieves OpenOffice documents (manual.sxw).
218 *
219 * @return array
220 */
221 protected function findOpenOfficeDocuments()
222 {
223 $documents = [];
224 $language = 'default';
225
226 foreach (array_keys($GLOBALS['TYPO3_LOADED_EXT']) as $extensionKey) {
227 $path = GeneralUtility::getFileAbsFileName('EXT:' . $extensionKey . '/doc/');
228 if (is_file($path . 'manual.sxw')) {
229 $documentKey = 'typo3cms.extensions.' . $extensionKey;
230 $icon = MiscUtility::getIcon($documentKey);
231
232 /** @var \TYPO3\CMS\Documentation\Domain\Model\Document $document */
233 $document = $this->objectManager->get(Document::class)
234 ->setPackageKey($documentKey)
235 ->setExtensionKey($extensionKey)
236 ->setIcon($icon);
237
238 $metadata = $this->getMetadata($documentKey, $language);
239 /** @var \TYPO3\CMS\Documentation\Domain\Model\DocumentTranslation $documentTranslation */
240 $documentTranslation = $this->objectManager->get(DocumentTranslation::class)
241 ->setLanguage($language)
242 ->setTitle($metadata['title'])
243 ->setDescription($metadata['description']);
244
245 /** @var \TYPO3\CMS\Documentation\Domain\Model\DocumentFormat $documentFormat */
246 $documentFormat = $this->objectManager->get(DocumentFormat::class)
247 ->setFormat('sxw')
248 ->setPath(PathUtility::stripPathSitePrefix($path . 'manual.sxw'));
249
250 $documentTranslation->addFormat($documentFormat);
251 $document->addTranslation($documentTranslation);
252 $documents[$documentKey] = $document;
253 }
254 }
255
256 return $documents;
257 }
258
259 /**
260 * Returns metadata associated to a given document key.
261 *
262 * @param string $documentKey
263 * @param string $language
264 * @return array
265 */
266 protected function getMetadata($documentKey, $language)
267 {
268 $documentPath = PATH_site . 'typo3conf/Documentation/' . $documentKey . '/' . $language . '/';
269 $metadata = [
270 'title' => $documentKey,
271 'description' => '',
272 ];
273 if (GeneralUtility::isFirstPartOfStr($documentKey, 'typo3cms.extensions.')) {
274 $extensionKey = substr($documentKey, 20);
275 if (ExtensionManagementUtility::isLoaded($extensionKey)) {
276 $metadata = MiscUtility::getExtensionMetaData($extensionKey);
277 }
278 } elseif (is_file($documentPath . 'composer.json')) {
279 $info = json_decode(file_get_contents($documentPath . 'composer.json'), true);
280 if (is_array($info)) {
281 $metadata['title'] = $info['name'];
282 $metadata['description'] = $info['description'];
283 }
284 }
285 return $metadata;
286 }
287 }