Combine.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Rule\Model\Condition;
  7. /**
  8. * @api
  9. * @since 100.0.2
  10. */
  11. class Combine extends AbstractCondition
  12. {
  13. /**
  14. * @var \Magento\Rule\Model\ConditionFactory
  15. */
  16. protected $_conditionFactory;
  17. /**
  18. * @var \Psr\Log\LoggerInterface
  19. */
  20. protected $_logger;
  21. /**
  22. * @param Context $context
  23. * @param array $data
  24. */
  25. public function __construct(Context $context, array $data = [])
  26. {
  27. $this->_conditionFactory = $context->getConditionFactory();
  28. $this->_logger = $context->getLogger();
  29. parent::__construct($context, $data);
  30. $this->setType(
  31. \Magento\Rule\Model\Condition\Combine::class
  32. )->setAggregator(
  33. 'all'
  34. )->setValue(
  35. true
  36. )->setConditions(
  37. []
  38. )->setActions(
  39. []
  40. );
  41. $this->loadAggregatorOptions();
  42. $options = $this->getAggregatorOptions();
  43. if ($options) {
  44. reset($options);
  45. $this->setAggregator(key($options));
  46. }
  47. }
  48. /* start aggregator methods */
  49. /**
  50. * @return $this
  51. */
  52. public function loadAggregatorOptions()
  53. {
  54. $this->setAggregatorOption(['all' => __('ALL'), 'any' => __('ANY')]);
  55. return $this;
  56. }
  57. /**
  58. * @return array
  59. */
  60. public function getAggregatorSelectOptions()
  61. {
  62. $opt = [];
  63. foreach ($this->getAggregatorOption() as $key => $value) {
  64. $opt[] = ['value' => $key, 'label' => $value];
  65. }
  66. return $opt;
  67. }
  68. /**
  69. * @return string
  70. */
  71. public function getAggregatorName()
  72. {
  73. return $this->getAggregatorOption($this->getAggregator());
  74. }
  75. /**
  76. * @return object
  77. */
  78. public function getAggregatorElement()
  79. {
  80. if ($this->getAggregator() === null) {
  81. $options = $this->getAggregatorOption();
  82. if ($options) {
  83. reset($options);
  84. $this->setAggregator(key($options));
  85. }
  86. }
  87. return $this->getForm()->addField(
  88. $this->getPrefix() . '__' . $this->getId() . '__aggregator',
  89. 'select',
  90. [
  91. 'name' => $this->elementName . '[' . $this->getPrefix() . '][' . $this->getId() . '][aggregator]',
  92. 'values' => $this->getAggregatorSelectOptions(),
  93. 'value' => $this->getAggregator(),
  94. 'value_name' => $this->getAggregatorName(),
  95. 'data-form-part' => $this->getFormName()
  96. ]
  97. )->setRenderer(
  98. $this->_layout->getBlockSingleton(\Magento\Rule\Block\Editable::class)
  99. );
  100. }
  101. /* end aggregator methods */
  102. /**
  103. * @return $this
  104. */
  105. public function loadValueOptions()
  106. {
  107. $this->setValueOption([1 => __('TRUE'), 0 => __('FALSE')]);
  108. return $this;
  109. }
  110. /**
  111. * @param object $condition
  112. * @return $this
  113. */
  114. public function addCondition($condition)
  115. {
  116. $condition->setRule($this->getRule());
  117. $condition->setObject($this->getObject());
  118. $condition->setPrefix($this->getPrefix());
  119. $conditions = $this->getConditions();
  120. $conditions[] = $condition;
  121. if (!$condition->getId()) {
  122. $condition->setId($this->getId() . '--' . sizeof($conditions));
  123. }
  124. $this->setData($this->getPrefix(), $conditions);
  125. return $this;
  126. }
  127. /**
  128. * @return string
  129. */
  130. public function getValueElementType()
  131. {
  132. return 'select';
  133. }
  134. /**
  135. * Returns array containing conditions in the collection
  136. *
  137. * Output example:
  138. * array(
  139. * 'type'=>'combine',
  140. * 'operator'=>'ALL',
  141. * 'value'=>'TRUE',
  142. * 'conditions'=>array(
  143. * {condition::asArray},
  144. * {combine::asArray},
  145. * {quote_item_combine::asArray}
  146. * )
  147. * )
  148. *
  149. * @param array $arrAttributes
  150. * @return array
  151. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  152. */
  153. public function asArray(array $arrAttributes = [])
  154. {
  155. $out = parent::asArray();
  156. $out['aggregator'] = $this->getAggregator();
  157. foreach ($this->getConditions() as $condition) {
  158. $out['conditions'][] = $condition->asArray();
  159. }
  160. return $out;
  161. }
  162. /**
  163. * @param string $containerKey
  164. * @param string $itemKey
  165. * @return string
  166. */
  167. public function asXml($containerKey = 'conditions', $itemKey = 'condition')
  168. {
  169. $xml = "<aggregator>" .
  170. $this->getAggregator() .
  171. "</aggregator>" .
  172. "<value>" .
  173. $this->getValue() .
  174. "</value>" .
  175. "<{$containerKey}>";
  176. foreach ($this->getConditions() as $condition) {
  177. $xml .= "<{$itemKey}>" . $condition->asXml() . "</{$itemKey}>";
  178. }
  179. $xml .= "</{$containerKey}>";
  180. return $xml;
  181. }
  182. /**
  183. * @param array $arr
  184. * @param string $key
  185. * @return $this
  186. * @SuppressWarnings(PHPMD.NPathComplexity)
  187. */
  188. public function loadArray($arr, $key = 'conditions')
  189. {
  190. $this->setAggregator(
  191. isset($arr['aggregator']) ? $arr['aggregator'] : (isset($arr['attribute']) ? $arr['attribute'] : null)
  192. )->setValue(
  193. isset($arr['value']) ? $arr['value'] : (isset($arr['operator']) ? $arr['operator'] : null)
  194. );
  195. if (!empty($arr[$key]) && is_array($arr[$key])) {
  196. foreach ($arr[$key] as $conditionArr) {
  197. try {
  198. $condition = $this->_conditionFactory->create($conditionArr['type']);
  199. $this->addCondition($condition);
  200. $condition->loadArray($conditionArr, $key);
  201. } catch (\Exception $e) {
  202. $this->_logger->critical($e);
  203. }
  204. }
  205. }
  206. return $this;
  207. }
  208. /**
  209. * @param array|string $xml
  210. * @return $this
  211. */
  212. public function loadXml($xml)
  213. {
  214. if (is_string($xml)) {
  215. $xml = simplexml_load_string($xml);
  216. }
  217. $arr = parent::loadXml($xml);
  218. foreach ($xml->conditions->children() as $condition) {
  219. $arr['conditions'] = parent::loadXml($condition);
  220. }
  221. $this->loadArray($arr);
  222. return $this;
  223. }
  224. /**
  225. * @return string
  226. */
  227. public function asHtml()
  228. {
  229. $html = $this->getTypeElement()->getHtml() . __(
  230. 'If %1 of these conditions are %2:',
  231. $this->getAggregatorElement()->getHtml(),
  232. $this->getValueElement()->getHtml()
  233. );
  234. if ($this->getId() != '1') {
  235. $html .= $this->getRemoveLinkHtml();
  236. }
  237. return $html;
  238. }
  239. /**
  240. * @return $this
  241. */
  242. public function getNewChildElement()
  243. {
  244. return $this->getForm()->addField(
  245. $this->getPrefix() . '__' . $this->getId() . '__new_child',
  246. 'select',
  247. [
  248. 'name' => $this->elementName . '[' . $this->getPrefix() . '][' . $this->getId() . '][new_child]',
  249. 'values' => $this->getNewChildSelectOptions(),
  250. 'value_name' => $this->getNewChildName(),
  251. 'data-form-part' => $this->getFormName()
  252. ]
  253. )->setRenderer(
  254. $this->_layout->getBlockSingleton(\Magento\Rule\Block\Newchild::class)
  255. );
  256. }
  257. /**
  258. * @return string
  259. */
  260. public function asHtmlRecursive()
  261. {
  262. $html = $this->asHtml() .
  263. '<ul id="' .
  264. $this->getPrefix() .
  265. '__' .
  266. $this->getId() .
  267. '__children" class="rule-param-children">';
  268. foreach ($this->getConditions() as $cond) {
  269. $html .= '<li>' . $cond->asHtmlRecursive() . '</li>';
  270. }
  271. $html .= '<li>' . $this->getNewChildElement()->getHtml() . '</li></ul>';
  272. return $html;
  273. }
  274. /**
  275. * @param string $format
  276. * @return string
  277. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  278. */
  279. public function asString($format = '')
  280. {
  281. $str = __("If %1 of these conditions are %2:", $this->getAggregatorName(), $this->getValueName());
  282. return $str;
  283. }
  284. /**
  285. * @param int $level
  286. * @return string
  287. */
  288. public function asStringRecursive($level = 0)
  289. {
  290. $str = parent::asStringRecursive($level);
  291. foreach ($this->getConditions() as $cond) {
  292. $str .= "\n" . $cond->asStringRecursive($level + 1);
  293. }
  294. return $str;
  295. }
  296. /**
  297. * @param \Magento\Framework\Model\AbstractModel $model
  298. * @return bool
  299. */
  300. public function validate(\Magento\Framework\Model\AbstractModel $model)
  301. {
  302. return $this->_isValid($model);
  303. }
  304. /**
  305. * Validate by entity ID
  306. *
  307. * @param int $entityId
  308. * @return mixed
  309. */
  310. public function validateByEntityId($entityId)
  311. {
  312. return $this->_isValid($entityId);
  313. }
  314. /**
  315. * Is entity valid
  316. *
  317. * @param int|\Magento\Framework\Model\AbstractModel $entity
  318. * @return bool
  319. */
  320. protected function _isValid($entity)
  321. {
  322. if (!$this->getConditions()) {
  323. return true;
  324. }
  325. $all = $this->getAggregator() === 'all';
  326. $true = (bool)$this->getValue();
  327. foreach ($this->getConditions() as $cond) {
  328. if ($entity instanceof \Magento\Framework\Model\AbstractModel) {
  329. $validated = $cond->validate($entity);
  330. } else {
  331. $validated = $cond->validateByEntityId($entity);
  332. }
  333. if ($all && $validated !== $true) {
  334. return false;
  335. } elseif (!$all && $validated === $true) {
  336. return true;
  337. }
  338. }
  339. return $all ? true : false;
  340. }
  341. /**
  342. * @param \Magento\Framework\Data\Form $form
  343. * @return $this
  344. */
  345. public function setJsFormObject($form)
  346. {
  347. $this->setData('js_form_object', $form);
  348. foreach ($this->getConditions() as $condition) {
  349. $condition->setJsFormObject($form);
  350. }
  351. return $this;
  352. }
  353. /**
  354. * Get conditions, if current prefix is undefined use 'conditions' key
  355. *
  356. * @return array
  357. */
  358. public function getConditions()
  359. {
  360. $key = $this->getPrefix() ? $this->getPrefix() : 'conditions';
  361. return $this->getData($key);
  362. }
  363. /**
  364. * Set conditions, if current prefix is undefined use 'conditions' key
  365. *
  366. * @param array $conditions
  367. * @return $this
  368. */
  369. public function setConditions($conditions)
  370. {
  371. $key = $this->getPrefix() ? $this->getPrefix() : 'conditions';
  372. return $this->setData($key, $conditions);
  373. }
  374. /**
  375. * Getter for "Conditions Combination" select option for recursive combines
  376. *
  377. * @return array
  378. */
  379. protected function _getRecursiveChildSelectOption()
  380. {
  381. return ['value' => $this->getType(), 'label' => __('Conditions Combination')];
  382. }
  383. }