[FEATURE] EXT:form - integrate new form framework
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Classes / Mvc / Configuration / YamlSource.php
1 <?php
2 declare(strict_types=1);
3 namespace TYPO3\CMS\Form\Mvc\Configuration;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Symfony\Component\Yaml\Exception\ParseException;
19 use Symfony\Component\Yaml\Yaml;
20 use TYPO3\CMS\Core\Resource\File;
21 use TYPO3\CMS\Core\Utility\ArrayUtility;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Form\Mvc\Configuration\Exception\NoSuchFileException;
24 use TYPO3\CMS\Form\Mvc\Configuration\Exception\ParseErrorException;
25 use TYPO3\CMS\Form\Utility\ArrayUtility as FormArrayUtility;
26
27 /**
28 * Configuration source based on YAML files
29 *
30 * Scope: frontend / backend
31 * @internal
32 */
33 class YamlSource
34 {
35 /**
36 * Will be set if the PHP YAML Extension is installed.
37 * Having this installed massively improves YAML parsing performance.
38 *
39 * @var bool
40 * @see http://pecl.php.net/package/yaml
41 */
42 protected $usePhpYamlExtension = false;
43
44 /**
45 * Use PHP YAML Extension if installed.
46 * @internal
47 */
48 public function __construct()
49 {
50 if (extension_loaded('yaml')) {
51 $this->usePhpYamlExtension = true;
52 }
53 }
54
55 /**
56 * Loads the specified configuration files and returns its merged content
57 * as an array.
58 *
59 * @param array $filesToLoad
60 * @return array
61 * @throws ParseErrorException
62 * @throws NoSuchFileException
63 * @internal
64 */
65 public function load(array $filesToLoad): array
66 {
67 $configuration = [];
68 foreach ($filesToLoad as $fileToLoad) {
69 if ($fileToLoad instanceof File) {
70 $fileIdentifier = $fileToLoad->getIdentifier();
71 $rawYamlContent = $fileToLoad->getContents();
72 } else {
73 $fileIdentifier = $fileToLoad;
74 $fileToLoad = GeneralUtility::getFileAbsFileName($fileToLoad);
75 if (is_file($fileToLoad)) {
76 $rawYamlContent = file_get_contents($fileToLoad);
77 } else {
78 throw new NoSuchFileException(
79 'The file "' . $fileToLoad . '" does not exist.',
80 1471473378
81 );
82 }
83 }
84
85 try {
86 if ($this->usePhpYamlExtension) {
87 $loadedConfiguration = @yaml_parse($rawYamlContent);
88 if ($loadedConfiguration === false) {
89 throw new ParseErrorException(
90 'A parse error occurred while parsing file "' . $fileIdentifier . '".',
91 1391894094
92 );
93 }
94 } else {
95 $loadedConfiguration = Yaml::parse($rawYamlContent);
96 }
97
98 if (is_array($loadedConfiguration)) {
99 ArrayUtility::mergeRecursiveWithOverrule($configuration, $loadedConfiguration);
100 }
101 } catch (ParseException $exception) {
102 throw new ParseErrorException(
103 'A parse error occurred while parsing file "' . $fileIdentifier . '". Error message: ' . $exception->getMessage(),
104 1480195405
105 );
106 }
107 }
108
109 $configuration = FormArrayUtility::convertBooleanStringsToBooleanRecursive($configuration);
110 return $configuration;
111 }
112
113 /**
114 * Save the specified configuration array to the given file in YAML format.
115 *
116 * @param File|string $fileToSave The file to write to.
117 * @param array $configuration The configuration to save
118 * @return void
119 * @internal
120 */
121 public function save($fileToSave, array $configuration)
122 {
123 $header = $this->getHeaderFromFile($fileToSave);
124 $yaml = Yaml::dump($configuration, 99, 2);
125 if ($fileToSave instanceof File) {
126 $fileToSave->setContents($header . LF . $yaml);
127 } else {
128 @file_put_contents($fileToSave, $header . LF . $yaml);
129 }
130 }
131
132 /**
133 * Read the header part from the given file. That means, every line
134 * until the first non comment line is found.
135 *
136 * @param File|string $file
137 * @return string The header of the given YAML file
138 */
139 protected function getHeaderFromFile($file): string
140 {
141 $header = '';
142 if ($file instanceof File) {
143 $fileLines = explode(LF, $file->getContents());
144 } else {
145 $fileLines = file($file);
146 }
147 foreach ($fileLines as $line) {
148 if (preg_match('/^#/', $line)) {
149 $header .= $line;
150 } else {
151 break;
152 }
153 }
154 return $header;
155 }
156 }