‪TYPO3CMS  9.5
FormPersistenceManager.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It originated from the Neos.Form package (www.neos.io)
9  *
10  * It is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License, either version 2
12  * of the License, or any later version.
13  *
14  * For the full copyright and license information, please read the
15  * LICENSE.txt file that was distributed with this source code.
16  *
17  * The TYPO3 project - inspiring people to share!
18  */
19 
41 
48 {
49  const ‪FORM_DEFINITION_FILE_EXTENSION = '.form.yaml';
50 
54  protected ‪$yamlSource;
55 
59  protected ‪$storageRepository;
60 
64  protected ‪$formSettings;
65 
70 
74  protected ‪$runtimeCache;
75 
80 
85  public function ‪injectYamlSource(\‪TYPO3\CMS\Form\Mvc\Configuration\YamlSource ‪$yamlSource)
86  {
87  $this->yamlSource = ‪$yamlSource;
88  }
89 
94  public function ‪injectStorageRepository(\‪TYPO3\CMS\Core\Resource\StorageRepository ‪$storageRepository)
95  {
96  $this->storageRepository = ‪$storageRepository;
97  }
98 
103  {
104  $this->filePersistenceSlot = ‪$filePersistenceSlot;
105  }
106 
110  public function ‪injectResourceFactory(\‪TYPO3\CMS\Core\Resource\‪ResourceFactory ‪$resourceFactory)
111  {
112  $this->resourceFactory = ‪$resourceFactory;
113  }
114 
118  public function ‪initializeObject()
119  {
120  $this->formSettings = GeneralUtility::makeInstance(ObjectManager::class)
121  ->get(ConfigurationManagerInterface::class)
123  $this->runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_runtime');
124  }
125 
136  public function ‪load(string $persistenceIdentifier): array
137  {
138  $cacheKey = 'formLoad' . md5($persistenceIdentifier);
139 
140  $yaml = $this->runtimeCache->get($cacheKey);
141  if ($yaml !== false) {
142  return $yaml;
143  }
144 
145  $file = $this->‪retrieveFileByPersistenceIdentifier($persistenceIdentifier);
146 
147  try {
148  $yaml = $this->yamlSource->load([$file]);
149  $this->‪generateErrorsIfFormDefinitionIsValidButHasInvalidFileExtension($yaml, $persistenceIdentifier);
150  } catch (\Exception $e) {
151  $yaml = [
152  'type' => 'Form',
153  'identifier' => $persistenceIdentifier,
154  'label' => $e->getMessage(),
155  'invalid' => true,
156  ];
157  }
158  $this->runtimeCache->set($cacheKey, $yaml);
159 
160  return $yaml;
161  }
162 
176  public function ‪save(string $persistenceIdentifier, array $formDefinition)
177  {
178  if (!$this->‪hasValidFileExtension($persistenceIdentifier)) {
179  throw new PersistenceManagerException(sprintf('The file "%s" could not be saved.', $persistenceIdentifier), 1477679820);
180  }
181 
182  if ($this->‪pathIsIntendedAsExtensionPath($persistenceIdentifier)) {
183  if (!$this->formSettings['persistenceManager']['allowSaveToExtensionPaths']) {
184  throw new PersistenceManagerException('Save to extension paths is not allowed.', 1477680881);
185  }
186  if (!$this->‪isFileWithinAccessibleExtensionFolders($persistenceIdentifier)) {
187  $message = sprintf('The file "%s" could not be saved. Please check your configuration option "persistenceManager.allowedExtensionPaths"', $persistenceIdentifier);
188  throw new PersistenceManagerException($message, 1484073571);
189  }
190  $fileToSave = GeneralUtility::getFileAbsFileName($persistenceIdentifier);
191  } else {
192  $fileToSave = $this->‪getOrCreateFile($persistenceIdentifier);
193  }
194 
195  try {
196  $this->yamlSource->save($fileToSave, $formDefinition);
197  } catch (FileWriteException $e) {
198  throw new PersistenceManagerException(sprintf(
199  'The file "%s" could not be saved: %s',
200  $persistenceIdentifier,
201  $e->getMessage()
202  ), 1512582637, $e);
203  }
204  }
205 
214  public function delete(string $persistenceIdentifier)
215  {
216  if (!$this->‪hasValidFileExtension($persistenceIdentifier)) {
217  throw new PersistenceManagerException(sprintf('The file "%s" could not be removed.', $persistenceIdentifier), 1472239534);
218  }
219  if (!$this->‪exists($persistenceIdentifier)) {
220  throw new PersistenceManagerException(sprintf('The file "%s" could not be removed.', $persistenceIdentifier), 1472239535);
221  }
222  if ($this->‪pathIsIntendedAsExtensionPath($persistenceIdentifier)) {
223  if (!$this->formSettings['persistenceManager']['allowDeleteFromExtensionPaths']) {
224  throw new PersistenceManagerException(sprintf('The file "%s" could not be removed.', $persistenceIdentifier), 1472239536);
225  }
226  if (!$this->‪isFileWithinAccessibleExtensionFolders($persistenceIdentifier)) {
227  $message = sprintf('The file "%s" could not be removed. Please check your configuration option "persistenceManager.allowedExtensionPaths"', $persistenceIdentifier);
228  throw new PersistenceManagerException($message, 1484073878);
229  }
230  $fileToDelete = GeneralUtility::getFileAbsFileName($persistenceIdentifier);
231  unlink($fileToDelete);
232  } else {
233  list($storageUid, $fileIdentifier) = explode(':', $persistenceIdentifier, 2);
234  $storage = $this->‪getStorageByUid((int)$storageUid);
235  $file = $storage->getFile($fileIdentifier);
236  if (!$storage->checkFileActionPermission('delete', $file)) {
237  throw new PersistenceManagerException(sprintf('No delete access to file "%s".', $persistenceIdentifier), 1472239516);
238  }
239  $storage->deleteFile($file);
240  }
241  }
242 
250  public function ‪exists(string $persistenceIdentifier): bool
251  {
252  $exists = false;
253  if ($this->‪hasValidFileExtension($persistenceIdentifier)) {
254  if ($this->‪pathIsIntendedAsExtensionPath($persistenceIdentifier)) {
255  if ($this->‪isFileWithinAccessibleExtensionFolders($persistenceIdentifier)) {
256  $exists = file_exists(GeneralUtility::getFileAbsFileName($persistenceIdentifier));
257  }
258  } else {
259  list($storageUid, $fileIdentifier) = explode(':', $persistenceIdentifier, 2);
260  $storage = $this->‪getStorageByUid((int)$storageUid);
261  $exists = $storage->hasFile($fileIdentifier);
262  }
263  }
264  return $exists;
265  }
266 
277  public function ‪listForms(): array
278  {
279  $identifiers = [];
280  $forms = [];
281 
282  foreach ($this->‪retrieveYamlFilesFromStorageFolders() as $file) {
284  $folder = $file->getParentFolder();
285  // TODO: deprecated since TYPO3 v9, will be removed in TYPO3 v10.0
286  $formReadOnly = $folder->getCombinedIdentifier() === '1:/user_upload/';
287 
288  $form = $this->‪loadMetaData($file);
289 
290  if (!$this->‪looksLikeAFormDefinition($form)) {
291  continue;
292  }
293 
294  $persistenceIdentifier = $file->getCombinedIdentifier();
295  if ($this->‪hasValidFileExtension($persistenceIdentifier)) {
296  $forms[] = [
297  'identifier' => $form['identifier'],
298  'name' => $form['label'] ?? $form['identifier'],
299  'persistenceIdentifier' => $persistenceIdentifier,
300  'readOnly' => $formReadOnly,
301  'removable' => true,
302  'location' => 'storage',
303  'duplicateIdentifier' => false,
304  'invalid' => $form['invalid'],
305  'fileUid' => $form['fileUid'],
306  ];
307  $identifiers[$form['identifier']]++;
308  } else {
309  $forms[] = [
310  'identifier' => $form['identifier'],
311  'name' => $form['label'] ?? $form['identifier'],
312  'persistenceIdentifier' => $persistenceIdentifier,
313  'readOnly' => true,
314  'removable' => false,
315  'location' => 'storage',
316  'duplicateIdentifier' => false,
317  'invalid' => false,
318  'deprecatedFileExtension' => true,
319  'fileUid' => $form['fileUid'],
320  ];
321  }
322  }
323 
324  foreach ($this->‪retrieveYamlFilesFromExtensionFolders() as $fullPath => $fileName) {
325  $form = $this->‪loadMetaData($fullPath);
326 
327  if ($this->‪looksLikeAFormDefinition($form)) {
328  if ($this->‪hasValidFileExtension($fileName)) {
329  $forms[] = [
330  'identifier' => $form['identifier'],
331  'name' => $form['label'] ?? $form['identifier'],
332  'persistenceIdentifier' => $fullPath,
333  'readOnly' => $this->formSettings['persistenceManager']['allowSaveToExtensionPaths'] ? false: true,
334  'removable' => $this->formSettings['persistenceManager']['allowDeleteFromExtensionPaths'] ? true: false,
335  'location' => 'extension',
336  'duplicateIdentifier' => false,
337  'invalid' => $form['invalid'],
338  'fileUid' => $form['fileUid'],
339  ];
340  $identifiers[$form['identifier']]++;
341  } else {
342  $forms[] = [
343  'identifier' => $form['identifier'],
344  'name' => $form['label'] ?? $form['identifier'],
345  'persistenceIdentifier' => $fullPath,
346  'readOnly' => true,
347  'removable' => false,
348  'location' => 'extension',
349  'duplicateIdentifier' => false,
350  'invalid' => false,
351  'deprecatedFileExtension' => true,
352  'fileUid' => $form['fileUid'],
353  ];
354  }
355  }
356  }
357 
358  foreach ($identifiers as $identifier => $count) {
359  if ($count > 1) {
360  foreach ($forms as &$formDefinition) {
361  if ($formDefinition['identifier'] === $identifier) {
362  $formDefinition['duplicateIdentifier'] = true;
363  }
364  }
365  }
366  }
367 
368  return $forms;
369  }
370 
378  public function ‪retrieveYamlFilesFromStorageFolders(): array
379  {
380  $filesFromStorageFolders = [];
381 
382  $fileExtensionFilter = GeneralUtility::makeInstance(FileExtensionFilter::class);
383  $fileExtensionFilter->setAllowedFileExtensions(['yaml']);
384 
385  foreach ($this->‪getAccessibleFormStorageFolders() as $folder) {
386  $storage = $folder->getStorage();
387  $storage->setFileAndFolderNameFilters([
388  [$fileExtensionFilter, 'filterFileList']
389  ]);
390 
391  $files = $folder->getFiles(
392  0,
393  0,
395  true
396  );
397  $filesFromStorageFolders = array_merge($filesFromStorageFolders, array_values($files));
398  $storage->resetFileAndFolderNameFiltersToDefault();
399  }
400 
401  return $filesFromStorageFolders;
402  }
403 
411  public function ‪retrieveYamlFilesFromExtensionFolders(): array
412  {
413  $filesFromExtensionFolders = [];
414 
415  foreach ($this->‪getAccessibleExtensionFolders() as $relativePath => $fullPath) {
416  foreach (new \DirectoryIterator($fullPath) as $fileInfo) {
417  if ($fileInfo->getExtension() !== 'yaml') {
418  continue;
419  }
420  $filesFromExtensionFolders[$relativePath . $fileInfo->getFilename()] = $fileInfo->getFilename();
421  }
422  }
423 
424  return $filesFromExtensionFolders;
425  }
426 
438  public function ‪getAccessibleFormStorageFolders(): array
439  {
440  $storageFolders = [];
441 
442  if (
443  !isset($this->formSettings['persistenceManager']['allowedFileMounts'])
444  || !is_array($this->formSettings['persistenceManager']['allowedFileMounts'])
445  || empty($this->formSettings['persistenceManager']['allowedFileMounts'])
446  ) {
447  return $storageFolders;
448  }
449 
450  foreach ($this->formSettings['persistenceManager']['allowedFileMounts'] as $allowedFileMount) {
451  $allowedFileMount = rtrim($allowedFileMount, '/') . '/';
452  // $fileMountPath is like "/form_definitions/" or "/group_homes/1/form_definitions/"
453  [$storageUid, $fileMountPath] = explode(':', $allowedFileMount, 2);
454 
455  try {
456  $storage = $this->‪getStorageByUid((int)$storageUid);
457  } catch (PersistenceManagerException $e) {
458  continue;
459  }
460 
461  $isStorageFileMount = false;
462  $parentFolder = $storage->getRootLevelFolder(false);
463 
464  foreach ($storage->getFileMounts() as $storageFileMount) {
466  $storageFileMountFolder = $storageFileMount['folder'];
467 
468  // Normally should use ResourceStorage::isWithinFolder() to check if the configured file mount path is within a storage file mount but this requires a valid Folder object and thus a directory which already exists. And the folder could simply not exist yet.
469  if (‪StringUtility::beginsWith($fileMountPath, $storageFileMountFolder->getIdentifier())) {
470  $isStorageFileMount = true;
471  $parentFolder = $storageFileMountFolder;
472  }
473  }
474 
475  // Get storage folder object, create it if missing
476  try {
477  $fileMountFolder = $storage->getFolder($fileMountPath);
478  } catch (InsufficientFolderAccessPermissionsException $e) {
479  continue;
480  } catch (FolderDoesNotExistException $e) {
481  if ($isStorageFileMount) {
482  $fileMountPath = substr(
483  $fileMountPath,
484  strlen($parentFolder->getIdentifier())
485  );
486  }
487 
488  try {
489  $fileMountFolder = $storage->createFolder($fileMountPath, $parentFolder);
490  } catch (InsufficientFolderAccessPermissionsException $e) {
491  continue;
492  }
493  }
494 
495  $storageFolders[$allowedFileMount] = $fileMountFolder;
496  }
497  return $storageFolders;
498  }
499 
510  public function ‪getAccessibleExtensionFolders(): array
511  {
512  $extensionFolders = $this->runtimeCache->get('formAccessibleExtensionFolders');
513 
514  if ($extensionFolders !== false) {
515  return $extensionFolders;
516  }
517 
518  $extensionFolders = [];
519  if (
520  !isset($this->formSettings['persistenceManager']['allowedExtensionPaths'])
521  || !is_array($this->formSettings['persistenceManager']['allowedExtensionPaths'])
522  || empty($this->formSettings['persistenceManager']['allowedExtensionPaths'])
523  ) {
524  $this->runtimeCache->set('formAccessibleExtensionFolders', $extensionFolders);
525  return $extensionFolders;
526  }
527 
528  foreach ($this->formSettings['persistenceManager']['allowedExtensionPaths'] as $allowedExtensionPath) {
529  if (!$this->‪pathIsIntendedAsExtensionPath($allowedExtensionPath)) {
530  continue;
531  }
532 
533  $allowedExtensionFullPath = GeneralUtility::getFileAbsFileName($allowedExtensionPath);
534  if (!file_exists($allowedExtensionFullPath)) {
535  continue;
536  }
537  $allowedExtensionPath = rtrim($allowedExtensionPath, '/') . '/';
538  $extensionFolders[$allowedExtensionPath] = $allowedExtensionFullPath;
539  }
540 
541  $this->runtimeCache->set('formAccessibleExtensionFolders', $extensionFolders);
542  return $extensionFolders;
543  }
544 
556  public function ‪getUniquePersistenceIdentifier(string $formIdentifier, string $savePath): string
557  {
558  $savePath = rtrim($savePath, '/') . '/';
559  $formPersistenceIdentifier = $savePath . $formIdentifier . ‪self::FORM_DEFINITION_FILE_EXTENSION;
560  if (!$this->‪exists($formPersistenceIdentifier)) {
561  return $formPersistenceIdentifier;
562  }
563  for ($attempts = 1; $attempts < 100; $attempts++) {
564  $formPersistenceIdentifier = $savePath . sprintf('%s_%d', $formIdentifier, $attempts) . ‪self::FORM_DEFINITION_FILE_EXTENSION;
565  if (!$this->‪exists($formPersistenceIdentifier)) {
566  return $formPersistenceIdentifier;
567  }
568  }
569  $formPersistenceIdentifier = $savePath . sprintf('%s_%d', $formIdentifier, time()) . ‪self::FORM_DEFINITION_FILE_EXTENSION;
570  if (!$this->‪exists($formPersistenceIdentifier)) {
571  return $formPersistenceIdentifier;
572  }
573 
574  throw new NoUniquePersistenceIdentifierException(
575  sprintf('Could not find a unique persistence identifier for form identifier "%s" after %d attempts', $formIdentifier, $attempts),
576  1476010403
577  );
578  }
579 
590  public function ‪getUniqueIdentifier(string $identifier): string
591  {
592  $originalIdentifier = $identifier;
593  if ($this->‪checkForDuplicateIdentifier($identifier)) {
594  for ($attempts = 1; $attempts < 100; $attempts++) {
595  $identifier = sprintf('%s_%d', $originalIdentifier, $attempts);
596  if (!$this->‪checkForDuplicateIdentifier($identifier)) {
597  return $identifier;
598  }
599  }
600  $identifier = $originalIdentifier . '_' . time();
601  if ($this->‪checkForDuplicateIdentifier($identifier)) {
602  throw new NoUniqueIdentifierException(
603  sprintf('Could not find a unique identifier for form identifier "%s" after %d attempts', $identifier, $attempts),
604  1477688567
605  );
606  }
607  }
608  return $identifier;
609  }
610 
618  public function ‪checkForDuplicateIdentifier(string $identifier): bool
619  {
620  $identifierUsed = false;
621  foreach ($this->‪listForms() as $formDefinition) {
622  if ($formDefinition['identifier'] === $identifier) {
623  $identifierUsed = true;
624  break;
625  }
626  }
627  return $identifierUsed;
628  }
629 
641  public function ‪isAllowedPersistencePath(string $persistencePath): bool
642  {
643  $pathinfo = ‪PathUtility::pathinfo($persistencePath);
644  $persistencePathIsFile = isset($pathinfo['extension']);
645 
646  if (
647  $persistencePathIsFile
648  && $this->‪pathIsIntendedAsExtensionPath($persistencePath)
649  && $this->‪hasValidFileExtension($persistencePath)
650  && $this->‪isFileWithinAccessibleExtensionFolders($persistencePath)
651  ) {
652  return true;
653  }
654  if (
655  $persistencePathIsFile
656  && $this->‪pathIsIntendedAsFileMountPath($persistencePath)
657  && $this->‪hasValidFileExtension($persistencePath)
658  && $this->‪isFileWithinAccessibleFormStorageFolders($persistencePath)
659  ) {
660  return true;
661  }
662  if (
663  !$persistencePathIsFile
664  && $this->‪pathIsIntendedAsExtensionPath($persistencePath)
665  && $this->‪isAccessibleExtensionFolder($persistencePath)
666  ) {
667  return true;
668  }
669  if (
670  !$persistencePathIsFile
671  && $this->‪pathIsIntendedAsFileMountPath($persistencePath)
672  && $this->‪isAccessibleFormStorageFolder($persistencePath)
673  ) {
674  return true;
675  }
676 
677  return false;
678  }
679 
684  protected function ‪pathIsIntendedAsExtensionPath(string $path): bool
685  {
686  return strpos($path, 'EXT:') === 0;
687  }
688 
693  protected function ‪pathIsIntendedAsFileMountPath(string $path): bool
694  {
695  if (empty($path)) {
696  return false;
697  }
698 
699  [$storageUid, $pathIdentifier] = explode(':', $path, 2);
700  if (empty($storageUid) || empty($pathIdentifier)) {
701  return false;
702  }
703 
704  return ‪MathUtility::canBeInterpretedAsInteger($storageUid);
705  }
706 
716  protected function ‪getOrCreateFile(string $persistenceIdentifier): File
717  {
718  list($storageUid, $fileIdentifier) = explode(':', $persistenceIdentifier, 2);
719  $storage = $this->‪getStorageByUid((int)$storageUid);
720  $pathinfo = ‪PathUtility::pathinfo($fileIdentifier);
721 
722  if (!$storage->hasFolder($pathinfo['dirname'])) {
723  throw new PersistenceManagerException(sprintf('Could not create folder "%s".', $pathinfo['dirname']), 1471630579);
724  }
725 
726  try {
727  $folder = $storage->getFolder($pathinfo['dirname']);
728  } catch (InsufficientFolderAccessPermissionsException $e) {
729  throw new PersistenceManagerException(sprintf('No read access to folder "%s".', $pathinfo['dirname']), 1512583307);
730  }
731 
732  if (!$storage->checkFolderActionPermission('write', $folder)) {
733  throw new PersistenceManagerException(sprintf('No write access to folder "%s".', $pathinfo['dirname']), 1471630580);
734  }
735 
736  if (!$storage->hasFile($fileIdentifier)) {
737  $this->filePersistenceSlot->allowInvocation(
739  $folder->getCombinedIdentifier() . $pathinfo['basename']
740  );
741  $file = $folder->createFile($pathinfo['basename']);
742  } else {
743  $file = $storage->getFile($fileIdentifier);
744  }
745  return $file;
746  }
747 
755  protected function ‪getStorageByUid(int $storageUid): ResourceStorage
756  {
757  $storage = $this->storageRepository->findByUid($storageUid);
758  if (
759  !$storage instanceof ResourceStorage
760  || !$storage->isBrowsable()
761  ) {
762  throw new PersistenceManagerException(sprintf('Could not access storage with uid "%d".', $storageUid), 1471630581);
763  }
764  return $storage;
765  }
766 
772  protected function ‪loadMetaData($persistenceIdentifier): array
773  {
774  if ($persistenceIdentifier instanceof ‪File) {
775  $file = $persistenceIdentifier;
776  $persistenceIdentifier = $file->getCombinedIdentifier();
777  } else {
778  $file = $this->‪retrieveFileByPersistenceIdentifier($persistenceIdentifier);
779  }
780 
781  try {
782  $rawYamlContent = $file->getContents();
783 
784  if ($rawYamlContent === false) {
785  throw new ‪NoSuchFileException(sprintf('YAML file "%s" could not be loaded', $persistenceIdentifier), 1524684462);
786  }
787 
788  $yaml = $this->‪extractMetaDataFromCouldBeFormDefinition($rawYamlContent);
789  $this->‪generateErrorsIfFormDefinitionIsValidButHasInvalidFileExtension($yaml, $persistenceIdentifier);
790  $yaml['fileUid'] = $file->getUid();
791  } catch (\‪Exception $e) {
792  $yaml = [
793  'type' => 'Form',
794  'identifier' => $persistenceIdentifier,
795  'label' => $e->getMessage(),
796  'invalid' => true,
797  ];
798  }
799 
800  return $yaml;
801  }
802 
807  protected function ‪extractMetaDataFromCouldBeFormDefinition(string $maybeRawFormDefinition): array
808  {
809  $metaDataProperties = ['identifier', 'type', 'label', 'prototypeName'];
810  $metaData = [];
811  foreach (explode(LF, $maybeRawFormDefinition) as $line) {
812  if (empty($line) || $line[0] === ' ') {
813  continue;
814  }
815 
816  [$key, $value] = explode(':', $line);
817  if (
818  empty($key)
819  || empty($value)
820  || !in_array($key, $metaDataProperties, true)
821  ) {
822  continue;
823  }
824 
825  $value = trim($value, " '\"\r");
826  $metaData[$key] = $value;
827  }
828 
829  return $metaData;
830  }
831 
837  protected function ‪generateErrorsIfFormDefinitionIsValidButHasInvalidFileExtension(array $formDefinition, string $persistenceIdentifier): void
838  {
839  if (
840  $this->‪looksLikeAFormDefinition($formDefinition)
841  && !$this->‪hasValidFileExtension($persistenceIdentifier)
842  ) {
843  if (strpos($persistenceIdentifier, 'EXT:') === 0) {
844  trigger_error(
845  'Form definition file name ("' . $persistenceIdentifier . '") which does not end with ".form.yaml" will not be supported in TYPO3 v10.0.',
846  E_USER_DEPRECATED
847  );
848  } elseif (strpos($persistenceIdentifier, 'EXT:') !== 0) {
849  throw new ‪PersistenceManagerException(sprintf('Form definition "%s" does not end with ".form.yaml".', $persistenceIdentifier), 1531160649);
850  }
851  }
852  }
853 
860  protected function ‪retrieveFileByPersistenceIdentifier(string $persistenceIdentifier): ‪File
861  {
862  if (pathinfo($persistenceIdentifier, PATHINFO_EXTENSION) !== 'yaml') {
863  throw new ‪PersistenceManagerException(sprintf('The file "%s" could not be loaded.', $persistenceIdentifier), 1477679819);
864  }
865 
866  if (
867  $this->‪pathIsIntendedAsExtensionPath($persistenceIdentifier)
868  && !$this->‪isFileWithinAccessibleExtensionFolders($persistenceIdentifier)
869  ) {
870  $message = sprintf('The file "%s" could not be loaded. Please check your configuration option "persistenceManager.allowedExtensionPaths"', $persistenceIdentifier);
871  throw new PersistenceManagerException($message, 1484071985);
872  }
873 
874  try {
875  $file = $this->resourceFactory->retrieveFileOrFolderObject($persistenceIdentifier);
876  } catch (\Exception $e) {
877  // Top level catch to ensure useful following exception handling, because FAL throws top level exceptions.
878  $file = null;
879  }
880 
881  if ($file === null) {
882  throw new NoSuchFileException(sprintf('YAML file "%s" could not be loaded', $persistenceIdentifier), 1524684442);
883  }
884 
885  if (!$file->getStorage()->checkFileActionPermission('read', $file)) {
886  throw new PersistenceManagerException(sprintf('No read access to file "%s".', $persistenceIdentifier), 1471630578);
887  }
888 
889  return $file;
890  }
891 
896  protected function ‪hasValidFileExtension(string $fileName): bool
897  {
898  return ‪StringUtility::endsWith($fileName, self::FORM_DEFINITION_FILE_EXTENSION);
899  }
900 
905  protected function ‪isFileWithinAccessibleExtensionFolders(string $fileName): bool
906  {
907  $dirName = rtrim(‪PathUtility::pathinfo($fileName, PATHINFO_DIRNAME), '/') . '/';
908  return array_key_exists($dirName, $this->‪getAccessibleExtensionFolders());
909  }
910 
915  protected function ‪isFileWithinAccessibleFormStorageFolders(string $fileName): bool
916  {
917  $pathInfo = ‪PathUtility::pathinfo($fileName, PATHINFO_DIRNAME);
918  $pathInfo = is_string($pathInfo) ? $pathInfo : '';
919  $dirName = rtrim($pathInfo, '/') . '/';
920  return array_key_exists($dirName, $this->‪getAccessibleFormStorageFolders());
921  }
922 
927  protected function ‪isAccessibleExtensionFolder(string $folderName): bool
928  {
929  $folderName = rtrim($folderName, '/') . '/';
930  return array_key_exists($folderName, $this->‪getAccessibleExtensionFolders());
931  }
932 
937  protected function ‪isAccessibleFormStorageFolder(string $folderName): bool
938  {
939  $folderName = rtrim($folderName, '/') . '/';
940  return array_key_exists($folderName, $this->‪getAccessibleFormStorageFolders());
941  }
942 
947  protected function ‪looksLikeAFormDefinition(array $data): bool
948  {
949  return isset($data['identifier'], $data['type']) && !empty($data['identifier']) && $data['type'] === 'Form';
950  }
951 }
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\listForms
‪array listForms()
Definition: FormPersistenceManager.php:271
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\isAccessibleFormStorageFolder
‪bool isAccessibleFormStorageFolder(string $folderName)
Definition: FormPersistenceManager.php:931
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\hasValidFileExtension
‪bool hasValidFileExtension(string $fileName)
Definition: FormPersistenceManager.php:890
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:23
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:73
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\$filePersistenceSlot
‪FilePersistenceSlot $filePersistenceSlot
Definition: FormPersistenceManager.php:65
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\isFileWithinAccessibleExtensionFolders
‪bool isFileWithinAccessibleExtensionFolders(string $fileName)
Definition: FormPersistenceManager.php:899
‪TYPO3\CMS\Form\Mvc\Configuration\Exception\FileWriteException
Definition: FileWriteException.php:24
‪TYPO3\CMS\Core\Utility\StringUtility\endsWith
‪static bool endsWith($haystack, $needle)
Definition: StringUtility.php:60
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\$yamlSource
‪TYPO3 CMS Form Mvc Configuration YamlSource $yamlSource
Definition: FormPersistenceManager.php:53
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\injectStorageRepository
‪injectStorageRepository(\TYPO3\CMS\Core\Resource\StorageRepository $storageRepository)
Definition: FormPersistenceManager.php:88
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\checkForDuplicateIdentifier
‪bool checkForDuplicateIdentifier(string $identifier)
Definition: FormPersistenceManager.php:612
‪TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
Definition: InsufficientFolderAccessPermissionsException.php:21
‪TYPO3\CMS\Form\Mvc\Persistence\Exception\PersistenceManagerException
Definition: PersistenceManagerException.php:26
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\isFileWithinAccessibleFormStorageFolders
‪bool isFileWithinAccessibleFormStorageFolders(string $fileName)
Definition: FormPersistenceManager.php:909
‪TYPO3
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\retrieveFileByPersistenceIdentifier
‪File retrieveFileByPersistenceIdentifier(string $persistenceIdentifier)
Definition: FormPersistenceManager.php:854
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\retrieveYamlFilesFromExtensionFolders
‪File[] retrieveYamlFilesFromExtensionFolders()
Definition: FormPersistenceManager.php:405
‪TYPO3\CMS\Form\Mvc\Persistence\Exception\NoUniqueIdentifierException
Definition: NoUniqueIdentifierException.php:24
‪TYPO3\CMS\Core\Resource\Folder\FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS
‪const FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS
Definition: Folder.php:66
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\injectResourceFactory
‪injectResourceFactory(\TYPO3\CMS\Core\Resource\ResourceFactory $resourceFactory)
Definition: FormPersistenceManager.php:104
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\getStorageByUid
‪ResourceStorage getStorageByUid(int $storageUid)
Definition: FormPersistenceManager.php:749
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\pathIsIntendedAsExtensionPath
‪bool pathIsIntendedAsExtensionPath(string $path)
Definition: FormPersistenceManager.php:678
‪TYPO3\CMS\Core\Utility\PathUtility\pathinfo
‪static string array pathinfo($path, $options=null)
Definition: PathUtility.php:207
‪TYPO3\CMS\Core\Utility\StringUtility\beginsWith
‪static bool beginsWith($haystack, $needle)
Definition: StringUtility.php:31
‪TYPO3\CMS\Form\Mvc\Persistence
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\isAllowedPersistencePath
‪bool isAllowedPersistencePath(string $persistencePath)
Definition: FormPersistenceManager.php:635
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\initializeObject
‪initializeObject()
Definition: FormPersistenceManager.php:112
‪TYPO3\CMS\Form\Slot\FilePersistenceSlot\COMMAND_FILE_CREATE
‪const COMMAND_FILE_CREATE
Definition: FilePersistenceSlot.php:31
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\injectFilePersistenceSlot
‪injectFilePersistenceSlot(\TYPO3\CMS\Form\Slot\FilePersistenceSlot $filePersistenceSlot)
Definition: FormPersistenceManager.php:96
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\$formSettings
‪array $formSettings
Definition: FormPersistenceManager.php:61
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\looksLikeAFormDefinition
‪bool looksLikeAFormDefinition(array $data)
Definition: FormPersistenceManager.php:941
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\getAccessibleFormStorageFolders
‪Folder[] getAccessibleFormStorageFolders()
Definition: FormPersistenceManager.php:432
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager
Definition: FormPersistenceManager.php:48
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\load
‪array load(string $persistenceIdentifier)
Definition: FormPersistenceManager.php:130
‪TYPO3\CMS\Core\Resource\ResourceStorage\isBrowsable
‪bool isBrowsable()
Definition: ResourceStorage.php:340
‪TYPO3\CMS\Core\Resource\Folder
Definition: Folder.php:34
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:33
‪TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException
Definition: FolderDoesNotExistException.php:21
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\exists
‪bool exists(string $persistenceIdentifier)
Definition: FormPersistenceManager.php:244
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:23
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:34
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\extractMetaDataFromCouldBeFormDefinition
‪array extractMetaDataFromCouldBeFormDefinition(string $maybeRawFormDefinition)
Definition: FormPersistenceManager.php:801
‪TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter
Definition: FileExtensionFilter.php:28
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\getUniquePersistenceIdentifier
‪string getUniquePersistenceIdentifier(string $formIdentifier, string $savePath)
Definition: FormPersistenceManager.php:550
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\$storageRepository
‪TYPO3 CMS Core Resource StorageRepository $storageRepository
Definition: FormPersistenceManager.php:57
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\$runtimeCache
‪FrontendInterface $runtimeCache
Definition: FormPersistenceManager.php:69
‪TYPO3\CMS\Form\Slot\FilePersistenceSlot
Definition: FilePersistenceSlot.php:29
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\injectYamlSource
‪injectYamlSource(\TYPO3\CMS\Form\Mvc\Configuration\YamlSource $yamlSource)
Definition: FormPersistenceManager.php:79
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:21
‪TYPO3\CMS\Core\Resource\ResourceStorage
Definition: ResourceStorage.php:74
‪TYPO3\CMS\Form\Mvc\Persistence\Exception
Definition: Exception.php:26
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\getAccessibleExtensionFolders
‪array getAccessibleExtensionFolders()
Definition: FormPersistenceManager.php:504
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\getOrCreateFile
‪File getOrCreateFile(string $persistenceIdentifier)
Definition: FormPersistenceManager.php:710
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\getUniqueIdentifier
‪string getUniqueIdentifier(string $identifier)
Definition: FormPersistenceManager.php:584
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:21
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\save
‪save(string $persistenceIdentifier, array $formDefinition)
Definition: FormPersistenceManager.php:170
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\loadMetaData
‪array loadMetaData($persistenceIdentifier)
Definition: FormPersistenceManager.php:766
‪TYPO3\CMS\Form\Mvc\Configuration\ConfigurationManagerInterface\CONFIGURATION_TYPE_YAML_SETTINGS
‪const CONFIGURATION_TYPE_YAML_SETTINGS
Definition: ConfigurationManagerInterface.php:28
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\$resourceFactory
‪ResourceFactory $resourceFactory
Definition: FormPersistenceManager.php:73
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\generateErrorsIfFormDefinitionIsValidButHasInvalidFileExtension
‪generateErrorsIfFormDefinitionIsValidButHasInvalidFileExtension(array $formDefinition, string $persistenceIdentifier)
Definition: FormPersistenceManager.php:831
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\isAccessibleExtensionFolder
‪bool isAccessibleExtensionFolder(string $folderName)
Definition: FormPersistenceManager.php:921
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface
Definition: FormPersistenceManagerInterface.php:28
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:21
‪TYPO3\CMS\Extbase\Object\ObjectManager
Definition: ObjectManager.php:25
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\pathIsIntendedAsFileMountPath
‪bool pathIsIntendedAsFileMountPath(string $path)
Definition: FormPersistenceManager.php:687
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\FORM_DEFINITION_FILE_EXTENSION
‪const FORM_DEFINITION_FILE_EXTENSION
Definition: FormPersistenceManager.php:49
‪TYPO3\CMS\Form\Mvc\Configuration\Exception\NoSuchFileException
Definition: NoSuchFileException.php:24
‪TYPO3\CMS\Form\Mvc\Persistence\Exception\NoUniquePersistenceIdentifierException
Definition: NoUniquePersistenceIdentifierException.php:24
‪TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager\retrieveYamlFilesFromStorageFolders
‪File[] retrieveYamlFilesFromStorageFolders()
Definition: FormPersistenceManager.php:372
‪TYPO3\CMS\Form\Mvc\Configuration\ConfigurationManagerInterface
Definition: ConfigurationManagerInterface.php:27