Form.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Eav\Model;
  7. use Magento\Framework\App\RequestInterface;
  8. /**
  9. * EAV Entity Form Model
  10. *
  11. * @api
  12. * @SuppressWarnings(PHPMD.TooManyFields)
  13. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  14. * @since 100.0.2
  15. */
  16. abstract class Form
  17. {
  18. /**
  19. * Current module path name
  20. *
  21. * @var string
  22. */
  23. protected $_moduleName = '';
  24. /**
  25. * Current EAV entity type code
  26. *
  27. * @var string
  28. */
  29. protected $_entityTypeCode = '';
  30. /**
  31. * Current store instance
  32. *
  33. * @var \Magento\Store\Model\Store
  34. */
  35. protected $_store;
  36. /**
  37. * Current entity type instance
  38. *
  39. * @var \Magento\Eav\Model\Entity\Type
  40. */
  41. protected $_entityType;
  42. /**
  43. * Current entity instance
  44. *
  45. * @var \Magento\Framework\Model\AbstractModel
  46. */
  47. protected $_entity;
  48. /**
  49. * Current form code
  50. *
  51. * @var string
  52. */
  53. protected $_formCode;
  54. /**
  55. * Array of form attributes
  56. *
  57. * @var array
  58. */
  59. protected $_attributes;
  60. /**
  61. * Array of form system attributes
  62. *
  63. * @var array
  64. */
  65. protected $_systemAttributes;
  66. /**
  67. * Array of form user defined attributes
  68. *
  69. * @var array
  70. */
  71. protected $_userAttributes;
  72. /**
  73. * Array of form attributes that is not omitted
  74. *
  75. * @var array
  76. */
  77. protected $_allowedAttributes = null;
  78. /**
  79. * Is AJAX request flag
  80. *
  81. * @var bool
  82. */
  83. protected $_isAjax = false;
  84. /**
  85. * Whether the invisible form fields need to be filtered/ignored
  86. *
  87. * @var bool
  88. */
  89. protected $_ignoreInvisible = true;
  90. /**
  91. * @var \Magento\Framework\Validator
  92. */
  93. protected $_validator = null;
  94. /**
  95. * @var \Magento\Store\Model\StoreManagerInterface
  96. */
  97. protected $_storeManager;
  98. /**
  99. * @var \Magento\Eav\Model\Config
  100. */
  101. protected $_eavConfig;
  102. /**
  103. * @var \Magento\Framework\Module\Dir\Reader
  104. */
  105. protected $_modulesReader;
  106. /**
  107. * @var \Magento\Eav\Model\AttributeDataFactory
  108. */
  109. protected $_attrDataFactory;
  110. /**
  111. * @var \Magento\Framework\Validator\UniversalFactory $universalFactory
  112. */
  113. protected $_universalFactory;
  114. /**
  115. * @var RequestInterface
  116. */
  117. protected $_httpRequest;
  118. /**
  119. * @var \Magento\Framework\Validator\ConfigFactory
  120. */
  121. protected $_validatorConfigFactory;
  122. /**
  123. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  124. * @param \Magento\Eav\Model\Config $eavConfig
  125. * @param \Magento\Framework\Module\Dir\Reader $modulesReader
  126. * @param \Magento\Eav\Model\AttributeDataFactory $attrDataFactory
  127. * @param \Magento\Framework\Validator\UniversalFactory $universalFactory
  128. * @param RequestInterface $httpRequest
  129. * @param \Magento\Framework\Validator\ConfigFactory $validatorConfigFactory
  130. *
  131. * @throws \Magento\Framework\Exception\LocalizedException
  132. */
  133. public function __construct(
  134. \Magento\Store\Model\StoreManagerInterface $storeManager,
  135. \Magento\Eav\Model\Config $eavConfig,
  136. \Magento\Framework\Module\Dir\Reader $modulesReader,
  137. \Magento\Eav\Model\AttributeDataFactory $attrDataFactory,
  138. \Magento\Framework\Validator\UniversalFactory $universalFactory,
  139. RequestInterface $httpRequest,
  140. \Magento\Framework\Validator\ConfigFactory $validatorConfigFactory
  141. ) {
  142. if (empty($this->_moduleName)) {
  143. throw new \Magento\Framework\Exception\LocalizedException(__('The current module pathname is undefined.'));
  144. }
  145. if (empty($this->_entityTypeCode)) {
  146. throw new \Magento\Framework\Exception\LocalizedException(
  147. __('The current module EAV entity is undefined.')
  148. );
  149. }
  150. $this->_storeManager = $storeManager;
  151. $this->_eavConfig = $eavConfig;
  152. $this->_modulesReader = $modulesReader;
  153. $this->_attrDataFactory = $attrDataFactory;
  154. $this->_universalFactory = $universalFactory;
  155. $this->_httpRequest = $httpRequest;
  156. $this->_validatorConfigFactory = $validatorConfigFactory;
  157. }
  158. /**
  159. * Get EAV Entity Form Attribute Collection
  160. *
  161. * @return mixed
  162. */
  163. protected function _getFormAttributeCollection()
  164. {
  165. return $this->_universalFactory->create(
  166. str_replace('_', '\\', $this->_moduleName) . '\\Model\\ResourceModel\\Form\\Attribute\\Collection'
  167. );
  168. }
  169. /**
  170. * Get EAV Entity Form Attribute Collection with applied filters
  171. *
  172. * @return \Magento\Eav\Model\ResourceModel\Form\Attribute\Collection
  173. */
  174. protected function _getFilteredFormAttributeCollection()
  175. {
  176. return $this->_getFormAttributeCollection()->setStore(
  177. $this->getStore()
  178. )->setEntityType(
  179. $this->getEntityType()
  180. )->addFormCodeFilter(
  181. $this->getFormCode()
  182. )->setSortOrder();
  183. }
  184. /**
  185. * Set current store
  186. *
  187. * @param \Magento\Store\Model\Store|string|int $store
  188. * @return $this
  189. * @codeCoverageIgnore
  190. */
  191. public function setStore($store)
  192. {
  193. $this->_store = $this->_storeManager->getStore($store);
  194. return $this;
  195. }
  196. /**
  197. * Set entity instance
  198. *
  199. * @param \Magento\Framework\Model\AbstractModel $entity
  200. * @return $this
  201. */
  202. public function setEntity(\Magento\Framework\Model\AbstractModel $entity)
  203. {
  204. $this->_entity = $entity;
  205. if ($entity->getEntityTypeId()) {
  206. $this->setEntityType($entity->getEntityTypeId());
  207. }
  208. return $this;
  209. }
  210. /**
  211. * Set entity type instance
  212. *
  213. * @param \Magento\Eav\Model\Entity\Type|string|int $entityType
  214. * @return $this
  215. */
  216. public function setEntityType($entityType)
  217. {
  218. $this->_entityType = $this->_eavConfig->getEntityType($entityType);
  219. return $this;
  220. }
  221. /**
  222. * Set form code
  223. *
  224. * @param string $formCode
  225. * @return $this
  226. */
  227. public function setFormCode($formCode)
  228. {
  229. $this->_formCode = $formCode;
  230. return $this;
  231. }
  232. /**
  233. * Return current store instance
  234. *
  235. * @return \Magento\Store\Model\Store
  236. */
  237. public function getStore()
  238. {
  239. if ($this->_store === null) {
  240. $this->_store = $this->_storeManager->getStore();
  241. }
  242. return $this->_store;
  243. }
  244. /**
  245. * Return current form code
  246. *
  247. * @throws \Magento\Framework\Exception\LocalizedException
  248. * @return string
  249. */
  250. public function getFormCode()
  251. {
  252. if (empty($this->_formCode)) {
  253. throw new \Magento\Framework\Exception\LocalizedException(__('The form code is not defined.'));
  254. }
  255. return $this->_formCode;
  256. }
  257. /**
  258. * Return entity type instance
  259. * Return EAV entity type if entity type is not defined
  260. *
  261. * @return \Magento\Eav\Model\Entity\Type
  262. */
  263. public function getEntityType()
  264. {
  265. if ($this->_entityType === null) {
  266. $this->setEntityType($this->_entityTypeCode);
  267. }
  268. return $this->_entityType;
  269. }
  270. /**
  271. * Return current entity instance
  272. *
  273. * @throws \Magento\Framework\Exception\LocalizedException
  274. * @return \Magento\Framework\Model\AbstractModel
  275. */
  276. public function getEntity()
  277. {
  278. if ($this->_entity === null) {
  279. throw new \Magento\Framework\Exception\LocalizedException(__('The entity instance is not defined.'));
  280. }
  281. return $this->_entity;
  282. }
  283. /**
  284. * Return array of form attributes
  285. *
  286. * @return array
  287. */
  288. public function getAttributes()
  289. {
  290. if ($this->_attributes === null) {
  291. $this->_attributes = [];
  292. $this->_userAttributes = [];
  293. /** @var $attribute \Magento\Eav\Model\Attribute */
  294. foreach ($this->_getFilteredFormAttributeCollection() as $attribute) {
  295. $this->_attributes[$attribute->getAttributeCode()] = $attribute;
  296. if ($attribute->getIsUserDefined()) {
  297. $this->_userAttributes[$attribute->getAttributeCode()] = $attribute;
  298. } else {
  299. $this->_systemAttributes[$attribute->getAttributeCode()] = $attribute;
  300. }
  301. if (!$this->_isAttributeOmitted($attribute)) {
  302. $this->_allowedAttributes[$attribute->getAttributeCode()] = $attribute;
  303. }
  304. }
  305. }
  306. return $this->_attributes;
  307. }
  308. /**
  309. * Return attribute instance by code or false
  310. *
  311. * @param string $attributeCode
  312. * @return \Magento\Eav\Model\Entity\Attribute|bool
  313. */
  314. public function getAttribute($attributeCode)
  315. {
  316. $attributes = $this->getAttributes();
  317. if (isset($attributes[$attributeCode])) {
  318. return $attributes[$attributeCode];
  319. }
  320. return false;
  321. }
  322. /**
  323. * Return array of form user defined attributes
  324. *
  325. * @return array
  326. */
  327. public function getUserAttributes()
  328. {
  329. if ($this->_userAttributes === null) {
  330. // load attributes
  331. $this->getAttributes();
  332. }
  333. return $this->_userAttributes;
  334. }
  335. /**
  336. * Return array of form system attributes
  337. *
  338. * @return array
  339. */
  340. public function getSystemAttributes()
  341. {
  342. if ($this->_systemAttributes === null) {
  343. // load attributes
  344. $this->getAttributes();
  345. }
  346. return $this->_systemAttributes;
  347. }
  348. /**
  349. * Get not omitted attributes
  350. *
  351. * @return array
  352. */
  353. public function getAllowedAttributes()
  354. {
  355. if ($this->_allowedAttributes === null) {
  356. // load attributes
  357. $this->getAttributes();
  358. }
  359. return $this->_allowedAttributes;
  360. }
  361. /**
  362. * Return attribute data model by attribute
  363. *
  364. * @param \Magento\Eav\Model\Entity\Attribute $attribute
  365. * @return \Magento\Eav\Model\Attribute\Data\AbstractData
  366. */
  367. protected function _getAttributeDataModel(\Magento\Eav\Model\Entity\Attribute $attribute)
  368. {
  369. $dataModel = $this->_attrDataFactory->create($attribute, $this->getEntity());
  370. $dataModel->setIsAjaxRequest($this->getIsAjaxRequest());
  371. return $dataModel;
  372. }
  373. /**
  374. * Prepare request with data and returns it
  375. *
  376. * @param array $data
  377. * @return RequestInterface
  378. */
  379. public function prepareRequest(array $data)
  380. {
  381. $request = clone $this->_httpRequest;
  382. $request->clearParams();
  383. $request->setParams($data);
  384. return $request;
  385. }
  386. /**
  387. * Extract data from request and return associative data array
  388. *
  389. * @param RequestInterface $request
  390. * @param string $scope the request scope
  391. * @param bool $scopeOnly search value only in scope or search value in global too
  392. * @return array
  393. */
  394. public function extractData(RequestInterface $request, $scope = null, $scopeOnly = true)
  395. {
  396. $data = [];
  397. /** @var $attribute \Magento\Eav\Model\Attribute */
  398. foreach ($this->getAllowedAttributes() as $attribute) {
  399. $dataModel = $this->_getAttributeDataModel($attribute);
  400. $dataModel->setRequestScope($scope);
  401. $dataModel->setRequestScopeOnly($scopeOnly);
  402. $data[$attribute->getAttributeCode()] = $dataModel->extractValue($request);
  403. }
  404. return $data;
  405. }
  406. /**
  407. * Get validator
  408. *
  409. * @param array $data
  410. * @return \Magento\Framework\Validator
  411. */
  412. protected function _getValidator(array $data)
  413. {
  414. if ($this->_validator === null) {
  415. $configFiles = $this->_modulesReader->getConfigurationFiles('validation.xml');
  416. /** @var $validatorFactory \Magento\Framework\Validator\Config */
  417. $validatorFactory = $this->_validatorConfigFactory->create(['configFiles' => $configFiles]);
  418. $builder = $validatorFactory->createValidatorBuilder('eav_entity', 'form');
  419. $builder->addConfiguration(
  420. 'eav_data_validator',
  421. ['method' => 'setAttributes', 'arguments' => [$this->getAllowedAttributes()]]
  422. );
  423. $builder->addConfiguration(
  424. 'eav_data_validator',
  425. ['method' => 'setData', 'arguments' => [$data]]
  426. );
  427. $this->_validator = $builder->createValidator();
  428. }
  429. return $this->_validator;
  430. }
  431. /**
  432. * Validate data array and return true or array of errors
  433. *
  434. * @param array $data
  435. * @return bool|array
  436. */
  437. public function validateData(array $data)
  438. {
  439. $validator = $this->_getValidator($data);
  440. if (!$validator->isValid($this->getEntity())) {
  441. $messages = [];
  442. foreach ($validator->getMessages() as $errorMessages) {
  443. $messages = array_merge($messages, (array)$errorMessages);
  444. }
  445. return $messages;
  446. }
  447. return true;
  448. }
  449. /**
  450. * Compact data array to current entity
  451. *
  452. * @param array $data
  453. * @return $this
  454. */
  455. public function compactData(array $data)
  456. {
  457. /** @var $attribute \Magento\Eav\Model\Attribute */
  458. foreach ($this->getAllowedAttributes() as $attribute) {
  459. $dataModel = $this->_getAttributeDataModel($attribute);
  460. $dataModel->setExtractedData($data);
  461. if (!isset($data[$attribute->getAttributeCode()])) {
  462. $data[$attribute->getAttributeCode()] = false;
  463. }
  464. $dataModel->compactValue($data[$attribute->getAttributeCode()]);
  465. }
  466. return $this;
  467. }
  468. /**
  469. * Restore data array from SESSION to current entity
  470. *
  471. * @param array $data
  472. * @return $this
  473. */
  474. public function restoreData(array $data)
  475. {
  476. /** @var $attribute \Magento\Eav\Model\Attribute */
  477. foreach ($this->getAllowedAttributes() as $attribute) {
  478. $dataModel = $this->_getAttributeDataModel($attribute);
  479. $dataModel->setExtractedData($data);
  480. if (!isset($data[$attribute->getAttributeCode()])) {
  481. $data[$attribute->getAttributeCode()] = false;
  482. }
  483. $dataModel->restoreValue($data[$attribute->getAttributeCode()]);
  484. }
  485. return $this;
  486. }
  487. /**
  488. * Return array of entity formatted values
  489. *
  490. * @param string $format
  491. * @return array
  492. */
  493. public function outputData($format = \Magento\Eav\Model\AttributeDataFactory::OUTPUT_FORMAT_TEXT)
  494. {
  495. $data = [];
  496. /** @var $attribute \Magento\Eav\Model\Attribute */
  497. foreach ($this->getAllowedAttributes() as $attribute) {
  498. $dataModel = $this->_getAttributeDataModel($attribute);
  499. $dataModel->setExtractedData($data);
  500. $data[$attribute->getAttributeCode()] = $dataModel->outputValue($format);
  501. }
  502. return $data;
  503. }
  504. /**
  505. * Restore entity original data
  506. *
  507. * @return $this
  508. */
  509. public function resetEntityData()
  510. {
  511. /** @var $attribute \Magento\Eav\Model\Attribute */
  512. foreach ($this->getAllowedAttributes() as $attribute) {
  513. $value = $this->getEntity()->getOrigData($attribute->getAttributeCode());
  514. $this->getEntity()->setData($attribute->getAttributeCode(), $value);
  515. }
  516. return $this;
  517. }
  518. /**
  519. * Set is AJAX Request flag
  520. *
  521. * @param bool $flag
  522. * @return $this
  523. */
  524. public function setIsAjaxRequest($flag = true)
  525. {
  526. $this->_isAjax = (bool)$flag;
  527. return $this;
  528. }
  529. /**
  530. * Return is AJAX Request
  531. *
  532. * @return bool
  533. * @SuppressWarnings(PHPMD.BooleanGetMethodName)
  534. */
  535. public function getIsAjaxRequest()
  536. {
  537. return $this->_isAjax;
  538. }
  539. /**
  540. * Set default attribute values for new entity
  541. *
  542. * @return $this
  543. */
  544. public function initDefaultValues()
  545. {
  546. if (!$this->getEntity()->getId()) {
  547. /** @var $attribute \Magento\Eav\Model\Attribute */
  548. foreach ($this->getAttributes() as $attribute) {
  549. $default = $attribute->getDefaultValue();
  550. if ($default != '') {
  551. $this->getEntity()->setData($attribute->getAttributeCode(), $default);
  552. }
  553. }
  554. }
  555. return $this;
  556. }
  557. /**
  558. * Combined getter/setter whether to omit invisible attributes during rendering/validation
  559. *
  560. * @param mixed $setValue
  561. * @return bool|$this
  562. */
  563. public function ignoreInvisible($setValue = null)
  564. {
  565. if (null !== $setValue) {
  566. $this->_ignoreInvisible = (bool)$setValue;
  567. return $this;
  568. }
  569. return $this->_ignoreInvisible;
  570. }
  571. /**
  572. * Whether the specified attribute needs to skip rendering/validation
  573. *
  574. * @param \Magento\Eav\Model\Attribute $attribute
  575. * @return bool
  576. */
  577. protected function _isAttributeOmitted($attribute)
  578. {
  579. if ($this->_ignoreInvisible && !$attribute->getIsVisible()) {
  580. return true;
  581. }
  582. return false;
  583. }
  584. }