Field.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. <?php
  2. /**
  3. * Represents a Field Element on the UI that can be configured via xml.
  4. *
  5. * Copyright © Magento, Inc. All rights reserved.
  6. * See COPYING.txt for license details.
  7. */
  8. namespace Magento\Config\Model\Config\Structure\Element;
  9. /**
  10. * @api
  11. * @since 100.0.2
  12. */
  13. class Field extends \Magento\Config\Model\Config\Structure\AbstractElement
  14. {
  15. /**
  16. * Default value for useEmptyValueOption for service option
  17. */
  18. const DEFAULT_INCLUDE_EMPTY_VALUE_OPTION = false;
  19. /**
  20. * Backend model factory
  21. *
  22. * @var \Magento\Config\Model\Config\BackendFactory
  23. */
  24. protected $_backendFactory;
  25. /**
  26. * Source model factory
  27. *
  28. * @var \Magento\Config\Model\Config\SourceFactory
  29. */
  30. protected $_sourceFactory;
  31. /**
  32. * Comment model factory
  33. *
  34. * @var \Magento\Config\Model\Config\CommentFactory
  35. */
  36. protected $_commentFactory;
  37. /**
  38. *
  39. * @var \Magento\Config\Model\Config\Structure\Element\Dependency\Mapper
  40. */
  41. protected $_dependencyMapper;
  42. /**
  43. * Block factory
  44. *
  45. * @var \Magento\Framework\View\Element\BlockFactory
  46. */
  47. protected $_blockFactory;
  48. /**
  49. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  50. * @param \Magento\Framework\Module\Manager $moduleManager
  51. * @param \Magento\Config\Model\Config\BackendFactory $backendFactory
  52. * @param \Magento\Config\Model\Config\SourceFactory $sourceFactory
  53. * @param \Magento\Config\Model\Config\CommentFactory $commentFactory
  54. * @param \Magento\Framework\View\Element\BlockFactory $blockFactory
  55. * @param Dependency\Mapper $dependencyMapper
  56. */
  57. public function __construct(
  58. \Magento\Store\Model\StoreManagerInterface $storeManager,
  59. \Magento\Framework\Module\Manager $moduleManager,
  60. \Magento\Config\Model\Config\BackendFactory $backendFactory,
  61. \Magento\Config\Model\Config\SourceFactory $sourceFactory,
  62. \Magento\Config\Model\Config\CommentFactory $commentFactory,
  63. \Magento\Framework\View\Element\BlockFactory $blockFactory,
  64. \Magento\Config\Model\Config\Structure\Element\Dependency\Mapper $dependencyMapper
  65. ) {
  66. parent::__construct($storeManager, $moduleManager);
  67. $this->_backendFactory = $backendFactory;
  68. $this->_sourceFactory = $sourceFactory;
  69. $this->_commentFactory = $commentFactory;
  70. $this->_blockFactory = $blockFactory;
  71. $this->_dependencyMapper = $dependencyMapper;
  72. }
  73. /**
  74. * Retrieve field label
  75. *
  76. * @param string $labelPrefix
  77. * @return string
  78. */
  79. public function getLabel($labelPrefix = '')
  80. {
  81. $label = '';
  82. if ($labelPrefix) {
  83. $label .= $this->_translateLabel($labelPrefix) . ' ';
  84. }
  85. $label .= parent::getLabel();
  86. return $label;
  87. }
  88. /**
  89. * Retrieve field hint
  90. *
  91. * @return string
  92. */
  93. public function getHint()
  94. {
  95. return $this->_getTranslatedAttribute('hint');
  96. }
  97. /**
  98. * Retrieve comment
  99. *
  100. * @param string $currentValue
  101. * @return string
  102. */
  103. public function getComment($currentValue = '')
  104. {
  105. $comment = '';
  106. if (isset($this->_data['comment'])) {
  107. if (is_array($this->_data['comment'])) {
  108. if (isset($this->_data['comment']['model'])) {
  109. $model = $this->_commentFactory->create($this->_data['comment']['model']);
  110. $comment = $model->getCommentText($currentValue);
  111. }
  112. } else {
  113. $comment = parent::getComment();
  114. }
  115. }
  116. return $comment;
  117. }
  118. /**
  119. * Retrieve tooltip text
  120. *
  121. * @return string
  122. */
  123. public function getTooltip()
  124. {
  125. if (isset($this->_data['tooltip'])) {
  126. return $this->_getTranslatedAttribute('tooltip');
  127. } elseif (isset($this->_data['tooltip_block'])) {
  128. return $this->_blockFactory->createBlock($this->_data['tooltip_block'])->toHtml();
  129. }
  130. return '';
  131. }
  132. /**
  133. * Retrieve field type
  134. *
  135. * @return string
  136. */
  137. public function getType()
  138. {
  139. return isset($this->_data['type']) ? $this->_data['type'] : 'text';
  140. }
  141. /**
  142. * Get required elements paths for the field
  143. *
  144. * @param string $fieldPrefix
  145. * @param string $elementType
  146. * @return string[]
  147. */
  148. protected function _getRequiredElements($fieldPrefix = '', $elementType = 'group')
  149. {
  150. $elements = [];
  151. if (isset($this->_data['requires'][$elementType])) {
  152. if (isset($this->_data['requires'][$elementType]['id'])) {
  153. $elements[] = $this->_getPath($this->_data['requires'][$elementType]['id'], $fieldPrefix);
  154. } else {
  155. foreach ($this->_data['requires'][$elementType] as $element) {
  156. $elements[] = $this->_getPath($element['id'], $fieldPrefix);
  157. }
  158. }
  159. }
  160. return $elements;
  161. }
  162. /**
  163. * Get required groups paths for the field
  164. *
  165. * @param string $fieldPrefix
  166. * @return string[]
  167. */
  168. public function getRequiredGroups($fieldPrefix = '')
  169. {
  170. return $this->_getRequiredElements($fieldPrefix, 'group');
  171. }
  172. /**
  173. * Get required fields paths for the field
  174. *
  175. * @param string $fieldPrefix
  176. * @return string[]
  177. */
  178. public function getRequiredFields($fieldPrefix = '')
  179. {
  180. return $this->_getRequiredElements($fieldPrefix, 'field');
  181. }
  182. /**
  183. * Retrieve frontend css class
  184. *
  185. * @return string
  186. */
  187. public function getFrontendClass()
  188. {
  189. return isset($this->_data['frontend_class']) ? $this->_data['frontend_class'] : '';
  190. }
  191. /**
  192. * Check whether field has backend model
  193. *
  194. * @return bool
  195. */
  196. public function hasBackendModel()
  197. {
  198. return array_key_exists('backend_model', $this->_data) && $this->_data['backend_model'];
  199. }
  200. /**
  201. * Retrieve backend model
  202. *
  203. * @return \Magento\Framework\App\Config\ValueInterface
  204. */
  205. public function getBackendModel()
  206. {
  207. return $this->_backendFactory->create($this->_data['backend_model']);
  208. }
  209. /**
  210. * Retrieve field section id
  211. *
  212. * @return string
  213. */
  214. public function getSectionId()
  215. {
  216. $parts = explode('/', $this->getConfigPath() ?: $this->getPath());
  217. return current($parts);
  218. }
  219. /**
  220. * Retrieve field group path
  221. *
  222. * @return string
  223. */
  224. public function getGroupPath()
  225. {
  226. return dirname($this->getConfigPath() ?: $this->getPath());
  227. }
  228. /**
  229. * Retrieve config path
  230. *
  231. * @return null|string
  232. */
  233. public function getConfigPath()
  234. {
  235. return isset($this->_data['config_path']) ? $this->_data['config_path'] : null;
  236. }
  237. /**
  238. * Check whether field should be shown in default scope
  239. *
  240. * @return bool
  241. */
  242. public function showInDefault()
  243. {
  244. return isset($this->_data['showInDefault']) && (int)$this->_data['showInDefault'];
  245. }
  246. /**
  247. * Check whether field should be shown in website scope
  248. *
  249. * @return bool
  250. */
  251. public function showInWebsite()
  252. {
  253. return isset($this->_data['showInWebsite']) && (int)$this->_data['showInWebsite'];
  254. }
  255. /**
  256. * Check whether field should be shown in store scope
  257. *
  258. * @return bool
  259. */
  260. public function showInStore()
  261. {
  262. return isset($this->_data['showInStore']) && (int)$this->_data['showInStore'];
  263. }
  264. /**
  265. * Check if the field can be restored to default
  266. *
  267. * @return bool
  268. * @since 100.1.0
  269. */
  270. public function canRestore()
  271. {
  272. return isset($this->_data['canRestore']) && (int)$this->_data['canRestore'];
  273. }
  274. /**
  275. * Populate form element with field data
  276. *
  277. * @param \Magento\Framework\Data\Form\Element\AbstractElement $formField
  278. * @return void
  279. */
  280. public function populateInput($formField)
  281. {
  282. $originalData = [];
  283. foreach ($this->_data as $key => $value) {
  284. if (!is_array($value)) {
  285. $originalData[$key] = $value;
  286. }
  287. }
  288. $formField->setOriginalData($originalData);
  289. }
  290. /**
  291. * Check whether field has validation class
  292. *
  293. * @return bool
  294. */
  295. public function hasValidation()
  296. {
  297. return isset($this->_data['validate']);
  298. }
  299. /**
  300. * Retrieve field validation class
  301. *
  302. * @return string
  303. */
  304. public function getValidation()
  305. {
  306. return isset($this->_data['validate']) ? $this->_data['validate'] : null;
  307. }
  308. /**
  309. * Check whether field can be empty
  310. *
  311. * @return bool
  312. */
  313. public function canBeEmpty()
  314. {
  315. return isset($this->_data['can_be_empty']);
  316. }
  317. /**
  318. * Check whether field has source model
  319. *
  320. * @return bool
  321. */
  322. public function hasSourceModel()
  323. {
  324. return isset($this->_data['source_model']);
  325. }
  326. /**
  327. * Check whether field has options or source model
  328. *
  329. * @return bool
  330. */
  331. public function hasOptions()
  332. {
  333. return isset($this->_data['source_model']) || isset($this->_data['options']);
  334. }
  335. /**
  336. * Retrieve static options or source model option list
  337. *
  338. * @return array
  339. */
  340. public function getOptions()
  341. {
  342. if (isset($this->_data['source_model'])) {
  343. $sourceModel = $this->_data['source_model'];
  344. $optionArray = $this->_getOptionsFromSourceModel($sourceModel);
  345. return $optionArray;
  346. } elseif (isset($this->_data['options']) && isset($this->_data['options']['option'])) {
  347. $options = $this->_data['options']['option'];
  348. $options = $this->_getStaticOptions($options);
  349. return $options;
  350. }
  351. return [];
  352. }
  353. /**
  354. * Get Static Options list
  355. *
  356. * @param array $options
  357. * @return array
  358. */
  359. protected function _getStaticOptions(array $options)
  360. {
  361. foreach (array_keys($options) as $key) {
  362. $options[$key]['label'] = $this->_translateLabel($options[$key]['label']);
  363. $options[$key]['value'] = $this->_fillInConstantPlaceholders($options[$key]['value']);
  364. }
  365. return $options;
  366. }
  367. /**
  368. * Translate a label
  369. *
  370. * @param string $label an option label that should be translated
  371. * @return \Magento\Framework\Phrase
  372. */
  373. private function _translateLabel($label)
  374. {
  375. return __($label);
  376. }
  377. /**
  378. * Takes a string and searches for placeholders ({{CONSTANT_NAME}}) to replace with a constant value.
  379. *
  380. * @param string $value an option value that may contain a placeholder for a constant value
  381. * @return mixed|string the value after being replaced by the constant if needed
  382. */
  383. private function _fillInConstantPlaceholders($value)
  384. {
  385. if (is_string($value) && preg_match('/^{{(\\\\[A-Z][\\\\A-Za-z\d_]+::[A-Z\d_]+)}}$/', $value, $matches)) {
  386. $value = constant($matches[1]);
  387. }
  388. return $value;
  389. }
  390. /**
  391. * Retrieve options list from source model
  392. *
  393. * @param string $sourceModel Source model class name or class::method
  394. * @return array
  395. */
  396. protected function _getOptionsFromSourceModel($sourceModel)
  397. {
  398. $method = false;
  399. if (preg_match('/^([^:]+?)::([^:]+?)$/', $sourceModel, $matches)) {
  400. array_shift($matches);
  401. list($sourceModel, $method) = array_values($matches);
  402. }
  403. $sourceModel = $this->_sourceFactory->create($sourceModel);
  404. if ($sourceModel instanceof \Magento\Framework\DataObject) {
  405. $sourceModel->setPath($this->getPath());
  406. }
  407. if ($method) {
  408. if ($this->getType() == 'multiselect') {
  409. $optionArray = $sourceModel->{$method}();
  410. } else {
  411. $optionArray = [];
  412. foreach ($sourceModel->{$method}() as $key => $value) {
  413. if (is_array($value)) {
  414. $optionArray[] = $value;
  415. } else {
  416. $optionArray[] = ['label' => $value, 'value' => $key];
  417. }
  418. }
  419. }
  420. } else {
  421. $optionArray = $sourceModel->toOptionArray($this->getType() == 'multiselect');
  422. }
  423. return $optionArray;
  424. }
  425. /**
  426. * Retrieve field dependencies
  427. *
  428. * @param string $fieldPrefix
  429. * @param string $storeCode
  430. * @return array
  431. */
  432. public function getDependencies($fieldPrefix, $storeCode)
  433. {
  434. $dependencies = [];
  435. if (false == isset($this->_data['depends']['fields'])) {
  436. return $dependencies;
  437. }
  438. $dependencies = $this->_dependencyMapper->getDependencies(
  439. $this->_data['depends']['fields'],
  440. $storeCode,
  441. $fieldPrefix
  442. );
  443. return $dependencies;
  444. }
  445. /**
  446. * Check whether element should be displayed for advanced users
  447. *
  448. * @return bool
  449. */
  450. public function isAdvanced()
  451. {
  452. return isset($this->_data['advanced']) && $this->_data['advanced'];
  453. }
  454. }