Revert "[FEATURE] EXT:form - introduce YAML "imports""
[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 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
20 use Symfony\Component\Yaml\Exception\ParseException;
21 use Symfony\Component\Yaml\Yaml;
22 use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException;
23 use TYPO3\CMS\Core\Resource\File;
24 use TYPO3\CMS\Core\Utility\ArrayUtility;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26 use TYPO3\CMS\Form\Mvc\Configuration\Exception\FileWriteException;
27 use TYPO3\CMS\Form\Mvc\Configuration\Exception\NoSuchFileException;
28 use TYPO3\CMS\Form\Mvc\Configuration\Exception\ParseErrorException;
29
30 /**
31 * Configuration source based on YAML files
32 *
33 * Scope: frontend / backend
34 * @internal
35 */
36 class YamlSource
37 {
38 /**
39 * Will be set if the PHP YAML Extension is installed.
40 * Having this installed massively improves YAML parsing performance.
41 *
42 * @var bool
43 * @see http://pecl.php.net/package/yaml
44 */
45 protected $usePhpYamlExtension = false;
46
47 /**
48 * Use PHP YAML Extension if installed.
49 * @internal
50 */
51 public function __construct()
52 {
53 if (extension_loaded('yaml')) {
54 $this->usePhpYamlExtension = true;
55 }
56 }
57
58 /**
59 * Loads the specified configuration files and returns its merged content
60 * as an array.
61 *
62 * @param array $filesToLoad
63 * @return array
64 * @throws ParseErrorException
65 * @throws NoSuchFileException
66 * @internal
67 */
68 public function load(array $filesToLoad): array
69 {
70 $configuration = [];
71 foreach ($filesToLoad as $fileToLoad) {
72 if ($fileToLoad instanceof File) {
73 $fileIdentifier = $fileToLoad->getIdentifier();
74 $rawYamlContent = $fileToLoad->getContents();
75 if ($rawYamlContent === false) {
76 throw new NoSuchFileException(
77 'The file "' . $fileToLoad . '" does not exist.',
78 1498802253
79 );
80 }
81 } else {
82 $fileIdentifier = $fileToLoad;
83 $fileToLoad = GeneralUtility::getFileAbsFileName($fileToLoad);
84 if (is_file($fileToLoad)) {
85 $rawYamlContent = file_get_contents($fileToLoad);
86 } else {
87 throw new NoSuchFileException(
88 'The file "' . $fileToLoad . '" does not exist.',
89 1471473378
90 );
91 }
92 }
93
94 try {
95 if ($this->usePhpYamlExtension) {
96 $loadedConfiguration = @yaml_parse($rawYamlContent);
97 if ($loadedConfiguration === false) {
98 throw new ParseErrorException(
99 'A parse error occurred while parsing file "' . $fileIdentifier . '".',
100 1391894094
101 );
102 }
103 } else {
104 $loadedConfiguration = Yaml::parse($rawYamlContent);
105 }
106
107 if (is_array($loadedConfiguration)) {
108 ArrayUtility::mergeRecursiveWithOverrule($configuration, $loadedConfiguration);
109 }
110 } catch (ParseException $exception) {
111 throw new ParseErrorException(
112 'An error occurred while parsing file "' . $fileIdentifier . '": ' . $exception->getMessage(),
113 1480195405
114 );
115 }
116 }
117
118 $configuration = ArrayUtility::convertBooleanStringsToBooleanRecursive($configuration);
119 return $configuration;
120 }
121
122 /**
123 * Save the specified configuration array to the given file in YAML format.
124 *
125 * @param File|string $fileToSave The file to write to.
126 * @param array $configuration The configuration to save
127 * @throws FileWriteException if the file could not be written
128 * @internal
129 */
130 public function save($fileToSave, array $configuration)
131 {
132 try {
133 $header = $this->getHeaderFromFile($fileToSave);
134 } catch (InsufficientFileAccessPermissionsException $e) {
135 throw new FileWriteException($e->getMessage(), 1512584488, $e);
136 }
137
138 $yaml = Yaml::dump($configuration, 99, 2);
139
140 if ($fileToSave instanceof File) {
141 try {
142 $fileToSave->setContents($header . LF . $yaml);
143 } catch (InsufficientFileAccessPermissionsException $e) {
144 throw new FileWriteException($e->getMessage(), 1512582753, $e);
145 }
146 } else {
147 $byteCount = @file_put_contents($fileToSave, $header . LF . $yaml);
148
149 if ($byteCount === false) {
150 $error = error_get_last();
151 throw new FileWriteException($error['message'], 1512582929);
152 }
153 }
154
155 return $return;
156 }
157
158 /**
159 * Read the header part from the given file. That means, every line
160 * until the first non comment line is found.
161 *
162 * @param File|string $file
163 * @return string The header of the given YAML file
164 */
165 protected function getHeaderFromFile($file): string
166 {
167 $header = '';
168 if ($file instanceof File) {
169 $fileLines = explode(LF, $file->getContents());
170 } elseif (is_file($file)) {
171 $fileLines = file($file);
172 } else {
173 return '';
174 }
175
176 foreach ($fileLines as $line) {
177 if (preg_match('/^#/', $line)) {
178 $header .= $line;
179 } else {
180 break;
181 }
182 }
183 return $header;
184 }
185 }