PageRenderTime 28ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php

https://gitlab.com/reasonat/test8
PHP | 407 lines | 251 code | 68 blank | 88 comment | 68 complexity | 501392f1e82961ae60a487176d78dbe7 MD5 | raw file
  1. <?php
  2. // @codingStandardsIgnoreFile
  3. namespace Drupal\Core\DependencyInjection;
  4. use Drupal\Component\FileCache\FileCacheFactory;
  5. use Drupal\Component\Serialization\Yaml;
  6. use Symfony\Component\DependencyInjection\Alias;
  7. use Symfony\Component\DependencyInjection\ContainerInterface;
  8. use Symfony\Component\DependencyInjection\Definition;
  9. use Symfony\Component\DependencyInjection\DefinitionDecorator;
  10. use Symfony\Component\DependencyInjection\Reference;
  11. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  12. /**
  13. * YamlFileLoader loads YAML files service definitions.
  14. *
  15. * Drupal does not use Symfony's Config component, and Symfony's dependency on
  16. * it cannot be removed easily. Therefore, this is a partial but mostly literal
  17. * copy of upstream, which does not depend on the Config component.
  18. *
  19. * @see \Symfony\Component\DependencyInjection\Loader\YamlFileLoader
  20. * @see https://github.com/symfony/symfony/pull/10920
  21. *
  22. * NOTE: 98% of this code is a literal copy of Symfony's YamlFileLoader.
  23. *
  24. * This file does NOT follow Drupal coding standards, so as to simplify future
  25. * synchronizations.
  26. */
  27. class YamlFileLoader
  28. {
  29. /**
  30. * @var \Drupal\Core\DependencyInjection\ContainerBuilder $container
  31. */
  32. protected $container;
  33. /**
  34. * File cache object.
  35. *
  36. * @var \Drupal\Component\FileCache\FileCacheInterface
  37. */
  38. protected $fileCache;
  39. public function __construct(ContainerBuilder $container)
  40. {
  41. $this->container = $container;
  42. $this->fileCache = FileCacheFactory::get('container_yaml_loader');
  43. }
  44. /**
  45. * Loads a Yaml file.
  46. *
  47. * @param mixed $file
  48. * The resource
  49. */
  50. public function load($file)
  51. {
  52. // Load from the file cache, fall back to loading the file.
  53. $content = $this->fileCache->get($file);
  54. if (!$content) {
  55. $content = $this->loadFile($file);
  56. $this->fileCache->set($file, $content);
  57. }
  58. // Not supported.
  59. //$this->container->addResource(new FileResource($path));
  60. // empty file
  61. if (null === $content) {
  62. return;
  63. }
  64. // imports
  65. // Not supported.
  66. //$this->parseImports($content, $file);
  67. // parameters
  68. if (isset($content['parameters'])) {
  69. if (!is_array($content['parameters'])) {
  70. throw new InvalidArgumentException(sprintf('The "parameters" key should contain an array in %s. Check your YAML syntax.', $file));
  71. }
  72. foreach ($content['parameters'] as $key => $value) {
  73. $this->container->setParameter($key, $this->resolveServices($value));
  74. }
  75. }
  76. // extensions
  77. // Not supported.
  78. //$this->loadFromExtensions($content);
  79. // services
  80. $this->parseDefinitions($content, $file);
  81. }
  82. /**
  83. * Parses definitions
  84. *
  85. * @param array $content
  86. * @param string $file
  87. */
  88. private function parseDefinitions($content, $file)
  89. {
  90. if (!isset($content['services'])) {
  91. return;
  92. }
  93. if (!is_array($content['services'])) {
  94. throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file));
  95. }
  96. foreach ($content['services'] as $id => $service) {
  97. $this->parseDefinition($id, $service, $file);
  98. }
  99. }
  100. /**
  101. * Parses a definition.
  102. *
  103. * @param string $id
  104. * @param array $service
  105. * @param string $file
  106. *
  107. * @throws InvalidArgumentException
  108. * When tags are invalid.
  109. */
  110. private function parseDefinition($id, $service, $file)
  111. {
  112. if (is_string($service) && 0 === strpos($service, '@')) {
  113. $this->container->setAlias($id, substr($service, 1));
  114. return;
  115. }
  116. if (!is_array($service)) {
  117. throw new InvalidArgumentException(sprintf('A service definition must be an array or a string starting with "@" but %s found for service "%s" in %s. Check your YAML syntax.', gettype($service), $id, $file));
  118. }
  119. if (isset($service['alias'])) {
  120. $public = !array_key_exists('public', $service) || (bool) $service['public'];
  121. $this->container->setAlias($id, new Alias($service['alias'], $public));
  122. return;
  123. }
  124. if (isset($service['parent'])) {
  125. $definition = new DefinitionDecorator($service['parent']);
  126. } else {
  127. $definition = new Definition();
  128. }
  129. if (isset($service['class'])) {
  130. $definition->setClass($service['class']);
  131. }
  132. if (isset($service['shared'])) {
  133. $definition->setShared($service['shared']);
  134. }
  135. if (isset($service['scope'])) {
  136. if ('request' !== $id) {
  137. @trigger_error(sprintf('The "scope" key of service "%s" in file "%s" is deprecated since version 2.8 and will be removed in 3.0.', $id, $file), E_USER_DEPRECATED);
  138. }
  139. $definition->setScope($service['scope'], false);
  140. }
  141. if (isset($service['synthetic'])) {
  142. $definition->setSynthetic($service['synthetic']);
  143. }
  144. if (isset($service['synchronized'])) {
  145. $definition->setSynchronized($service['synchronized'], 'request' !== $id);
  146. }
  147. if (isset($service['lazy'])) {
  148. $definition->setLazy($service['lazy']);
  149. }
  150. if (isset($service['public'])) {
  151. $definition->setPublic($service['public']);
  152. }
  153. if (isset($service['abstract'])) {
  154. $definition->setAbstract($service['abstract']);
  155. }
  156. if (array_key_exists('deprecated', $service)) {
  157. $definition->setDeprecated(true, $service['deprecated']);
  158. }
  159. if (isset($service['factory'])) {
  160. if (is_string($service['factory'])) {
  161. if (strpos($service['factory'], ':') !== false && strpos($service['factory'], '::') === false) {
  162. $parts = explode(':', $service['factory']);
  163. $definition->setFactory(array($this->resolveServices('@'.$parts[0]), $parts[1]));
  164. } else {
  165. $definition->setFactory($service['factory']);
  166. }
  167. } else {
  168. $definition->setFactory(array($this->resolveServices($service['factory'][0]), $service['factory'][1]));
  169. }
  170. }
  171. if (isset($service['factory_class'])) {
  172. $definition->setFactoryClass($service['factory_class']);
  173. }
  174. if (isset($service['factory_method'])) {
  175. $definition->setFactoryMethod($service['factory_method']);
  176. }
  177. if (isset($service['factory_service'])) {
  178. $definition->setFactoryService($service['factory_service']);
  179. }
  180. if (isset($service['file'])) {
  181. $definition->setFile($service['file']);
  182. }
  183. if (isset($service['arguments'])) {
  184. $definition->setArguments($this->resolveServices($service['arguments']));
  185. }
  186. if (isset($service['properties'])) {
  187. $definition->setProperties($this->resolveServices($service['properties']));
  188. }
  189. if (isset($service['configurator'])) {
  190. if (is_string($service['configurator'])) {
  191. $definition->setConfigurator($service['configurator']);
  192. } else {
  193. $definition->setConfigurator(array($this->resolveServices($service['configurator'][0]), $service['configurator'][1]));
  194. }
  195. }
  196. if (isset($service['calls'])) {
  197. if (!is_array($service['calls'])) {
  198. throw new InvalidArgumentException(sprintf('Parameter "calls" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
  199. }
  200. foreach ($service['calls'] as $call) {
  201. if (isset($call['method'])) {
  202. $method = $call['method'];
  203. $args = isset($call['arguments']) ? $this->resolveServices($call['arguments']) : array();
  204. } else {
  205. $method = $call[0];
  206. $args = isset($call[1]) ? $this->resolveServices($call[1]) : array();
  207. }
  208. $definition->addMethodCall($method, $args);
  209. }
  210. }
  211. if (isset($service['tags'])) {
  212. if (!is_array($service['tags'])) {
  213. throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
  214. }
  215. foreach ($service['tags'] as $tag) {
  216. if (!is_array($tag)) {
  217. throw new InvalidArgumentException(sprintf('A "tags" entry must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
  218. }
  219. if (!isset($tag['name'])) {
  220. throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file));
  221. }
  222. $name = $tag['name'];
  223. unset($tag['name']);
  224. foreach ($tag as $attribute => $value) {
  225. if (!is_scalar($value) && null !== $value) {
  226. throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s" in %s. Check your YAML syntax.', $id, $name, $attribute, $file));
  227. }
  228. }
  229. $definition->addTag($name, $tag);
  230. }
  231. }
  232. if (isset($service['decorates'])) {
  233. $renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null;
  234. $priority = isset($service['decoration_priority']) ? $service['decoration_priority'] : 0;
  235. $definition->setDecoratedService($service['decorates'], $renameId, $priority);
  236. }
  237. if (isset($service['autowire'])) {
  238. $definition->setAutowired($service['autowire']);
  239. }
  240. if (isset($service['autowiring_types'])) {
  241. if (is_string($service['autowiring_types'])) {
  242. $definition->addAutowiringType($service['autowiring_types']);
  243. } else {
  244. if (!is_array($service['autowiring_types'])) {
  245. throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be a string or an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
  246. }
  247. foreach ($service['autowiring_types'] as $autowiringType) {
  248. if (!is_string($autowiringType)) {
  249. throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file));
  250. }
  251. $definition->addAutowiringType($autowiringType);
  252. }
  253. }
  254. }
  255. $this->container->setDefinition($id, $definition);
  256. }
  257. /**
  258. * Loads a YAML file.
  259. *
  260. * @param string $file
  261. *
  262. * @return array The file content
  263. *
  264. * @throws InvalidArgumentException
  265. * When the given file is not a local file or when it does not exist.
  266. */
  267. protected function loadFile($file)
  268. {
  269. if (!stream_is_local($file)) {
  270. throw new InvalidArgumentException(sprintf('This is not a local file "%s".', $file));
  271. }
  272. if (!file_exists($file)) {
  273. throw new InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file));
  274. }
  275. return $this->validate(Yaml::decode(file_get_contents($file)), $file);
  276. }
  277. /**
  278. * Validates a YAML file.
  279. *
  280. * @param mixed $content
  281. * @param string $file
  282. *
  283. * @return array
  284. *
  285. * @throws InvalidArgumentException
  286. * When service file is not valid.
  287. */
  288. private function validate($content, $file)
  289. {
  290. if (null === $content) {
  291. return $content;
  292. }
  293. if (!is_array($content)) {
  294. throw new InvalidArgumentException(sprintf('The service file "%s" is not valid. It should contain an array. Check your YAML syntax.', $file));
  295. }
  296. if ($invalid_keys = array_diff_key($content, array('parameters' => 1, 'services' => 1))) {
  297. throw new InvalidArgumentException(sprintf('The service file "%s" is not valid: it contains invalid keys %s. Services have to be added under "services" and Parameters under "parameters".', $file, $invalid_keys));
  298. }
  299. return $content;
  300. }
  301. /**
  302. * Resolves services.
  303. *
  304. * @param string|array $value
  305. *
  306. * @return array|string|Reference
  307. */
  308. private function resolveServices($value)
  309. {
  310. if (is_array($value)) {
  311. $value = array_map(array($this, 'resolveServices'), $value);
  312. } elseif (is_string($value) && 0 === strpos($value, '@=')) {
  313. // Not supported.
  314. //return new Expression(substr($value, 2));
  315. throw new InvalidArgumentException(sprintf("'%s' is an Expression, but expressions are not supported.", $value));
  316. } elseif (is_string($value) && 0 === strpos($value, '@')) {
  317. if (0 === strpos($value, '@@')) {
  318. $value = substr($value, 1);
  319. $invalidBehavior = null;
  320. } elseif (0 === strpos($value, '@?')) {
  321. $value = substr($value, 2);
  322. $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
  323. } else {
  324. $value = substr($value, 1);
  325. $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
  326. }
  327. if ('=' === substr($value, -1)) {
  328. $value = substr($value, 0, -1);
  329. $strict = false;
  330. } else {
  331. $strict = true;
  332. }
  333. if (null !== $invalidBehavior) {
  334. $value = new Reference($value, $invalidBehavior, $strict);
  335. }
  336. }
  337. return $value;
  338. }
  339. }