PageRenderTime 67ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/app/code/core/Mage/Rule/Model/Condition/Abstract.php

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 606 lines | 448 code | 65 blank | 93 comment | 84 complexity | 3db3010af4aa1c0d09c4b900a9d68e71 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Rule
  23. * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Abstract class for quote rule condition
  28. *
  29. */
  30. abstract class Mage_Rule_Model_Condition_Abstract
  31. extends Varien_Object
  32. implements Mage_Rule_Model_Condition_Interface
  33. {
  34. /**
  35. * Defines which operators will be available for this condition
  36. *
  37. * @var string
  38. */
  39. protected $_inputType = null;
  40. /**
  41. * Default values for possible operator options
  42. * @var array
  43. */
  44. protected $_defaultOperatorOptions = null;
  45. /**
  46. * Default combinations of operator options, depending on input type
  47. * @var array
  48. */
  49. protected $_defaultOperatorInputByType = null;
  50. public function __construct()
  51. {
  52. parent::__construct();
  53. $this->loadAttributeOptions()->loadOperatorOptions()->loadValueOptions();
  54. if ($options = $this->getAttributeOptions()) {
  55. foreach ($options as $attr=>$dummy) { $this->setAttribute($attr); break; }
  56. }
  57. if ($options = $this->getOperatorOptions()) {
  58. foreach ($options as $operator=>$dummy) { $this->setOperator($operator); break; }
  59. }
  60. }
  61. /**
  62. * Default operator input by type map getter
  63. *
  64. * @return array
  65. */
  66. public function getDefaultOperatorInputByType()
  67. {
  68. if (null === $this->_defaultOperatorInputByType) {
  69. $this->_defaultOperatorInputByType = array(
  70. 'string' => array('==', '!=', '>=', '>', '<=', '<', '{}', '!{}', '()', '!()'),
  71. 'numeric' => array('==', '!=', '>=', '>', '<=', '<', '()', '!()'),
  72. 'date' => array('==', '>=', '<='),
  73. 'select' => array('==', '!='),
  74. 'boolean' => array('==', '!='),
  75. 'multiselect' => array('{}', '!{}', '()', '!()'),
  76. 'grid' => array('()', '!()'),
  77. );
  78. }
  79. return $this->_defaultOperatorInputByType;
  80. }
  81. /**
  82. * Default operator options getter
  83. * Provides all possible operator options
  84. *
  85. * @return array
  86. */
  87. public function getDefaultOperatorOptions()
  88. {
  89. if (null === $this->_defaultOperatorOptions) {
  90. $this->_defaultOperatorOptions = array(
  91. '==' => Mage::helper('rule')->__('is'),
  92. '!=' => Mage::helper('rule')->__('is not'),
  93. '>=' => Mage::helper('rule')->__('equals or greater than'),
  94. '<=' => Mage::helper('rule')->__('equals or less than'),
  95. '>' => Mage::helper('rule')->__('greater than'),
  96. '<' => Mage::helper('rule')->__('less than'),
  97. '{}' => Mage::helper('rule')->__('contains'),
  98. '!{}' => Mage::helper('rule')->__('does not contain'),
  99. '()' => Mage::helper('rule')->__('is one of'),
  100. '!()' => Mage::helper('rule')->__('is not one of')
  101. );
  102. }
  103. return $this->_defaultOperatorOptions;
  104. }
  105. public function getForm()
  106. {
  107. return $this->getRule()->getForm();
  108. }
  109. public function asArray(array $arrAttributes = array())
  110. {
  111. $out = array(
  112. 'type'=>$this->getType(),
  113. 'attribute'=>$this->getAttribute(),
  114. 'operator'=>$this->getOperator(),
  115. 'value'=>$this->getValue(),
  116. 'is_value_processed'=>$this->getIsValueParsed(),
  117. );
  118. return $out;
  119. }
  120. public function asXml()
  121. {
  122. $xml = "<type>".$this->getType()."</type>"
  123. ."<attribute>".$this->getAttribute()."</attribute>"
  124. ."<operator>".$this->getOperator()."</operator>"
  125. ."<value>".$this->getValue()."</value>";
  126. return $xml;
  127. }
  128. public function loadArray($arr)
  129. {
  130. $this->setType($arr['type']);
  131. $this->setAttribute(isset($arr['attribute']) ? $arr['attribute'] : false);
  132. $this->setOperator(isset($arr['operator']) ? $arr['operator'] : false);
  133. $this->setValue(isset($arr['value']) ? $arr['value'] : false);
  134. $this->setIsValueParsed(isset($arr['is_value_parsed']) ? $arr['is_value_parsed'] : false);
  135. // $this->loadAttributeOptions();
  136. // $this->loadOperatorOptions();
  137. // $this->loadValueOptions();
  138. return $this;
  139. }
  140. public function loadXml($xml)
  141. {
  142. if (is_string($xml)) {
  143. $xml = simplexml_load_string($xml);
  144. }
  145. $arr = (array)$xml;
  146. $this->loadArray($arr);
  147. return $this;
  148. }
  149. public function loadAttributeOptions()
  150. {
  151. return $this;
  152. }
  153. public function getAttributeOptions()
  154. {
  155. return array();
  156. }
  157. public function getAttributeSelectOptions()
  158. {
  159. $opt = array();
  160. foreach ($this->getAttributeOption() as $k=>$v) {
  161. $opt[] = array('value'=>$k, 'label'=>$v);
  162. }
  163. return $opt;
  164. }
  165. public function getAttributeName()
  166. {
  167. return $this->getAttributeOption($this->getAttribute());
  168. }
  169. public function loadOperatorOptions()
  170. {
  171. $this->setOperatorOption($this->getDefaultOperatorOptions());
  172. $this->setOperatorByInputType($this->getDefaultOperatorInputByType());
  173. return $this;
  174. }
  175. /**
  176. * This value will define which operators will be available for this condition.
  177. *
  178. * Possible values are: string, numeric, date, select, multiselect, grid, boolean
  179. *
  180. * @return string
  181. */
  182. public function getInputType()
  183. {
  184. if (null === $this->_inputType) {
  185. return 'string';
  186. }
  187. return $this->_inputType;
  188. }
  189. public function getOperatorSelectOptions()
  190. {
  191. if ($this->getAttribute() === 'category_ids') {
  192. $type = 'multiselect';
  193. } else {
  194. $type = $this->getInputType();
  195. }
  196. $opt = array();
  197. $operatorByType = $this->getOperatorByInputType();
  198. foreach ($this->getOperatorOption() as $k=>$v) {
  199. if (!$operatorByType || in_array($k, $operatorByType[$type])) {
  200. $opt[] = array('value'=>$k, 'label'=>$v);
  201. }
  202. }
  203. return $opt;
  204. }
  205. public function getOperatorName()
  206. {
  207. return $this->getOperatorOption($this->getOperator());
  208. }
  209. public function loadValueOptions()
  210. {
  211. // $this->setValueOption(array(
  212. // true => Mage::helper('rule')->__('TRUE'),
  213. // false => Mage::helper('rule')->__('FALSE'),
  214. // ));
  215. $this->setValueOption(array());
  216. return $this;
  217. }
  218. public function getValueSelectOptions()
  219. {
  220. $opt = array();
  221. foreach ($this->getValueOption() as $k=>$v) {
  222. $opt[] = array('value'=>$k, 'label'=>$v);
  223. }
  224. return $opt;
  225. }
  226. public function getValueParsed()
  227. {
  228. $value = $this->getData('value');
  229. $op = $this->getOperator();
  230. if (($op === '{}' || $op === '!{}' || $op==='()' || $op==='!()') && is_scalar($value)) {
  231. $value = preg_split('#\s*[,;]\s*#', $value, null, PREG_SPLIT_NO_EMPTY);
  232. $this->setValue($value);
  233. }
  234. return $value;
  235. }
  236. public function getValue()
  237. {
  238. if ($this->getInputType()=='date' && !$this->getIsValueParsed()) {
  239. // date format intentionally hard-coded
  240. $this->setValue(
  241. Mage::app()->getLocale()->date($this->getData('value'),
  242. Varien_Date::DATE_INTERNAL_FORMAT, null, false)->toString(Varien_Date::DATE_INTERNAL_FORMAT)
  243. );
  244. $this->setIsValueParsed(true);
  245. }
  246. return $this->getData('value');
  247. }
  248. public function getValueName()
  249. {
  250. $value = $this->getValue();
  251. if (is_null($value) || ''===$value) {
  252. return '...';
  253. }
  254. $options = $this->getValueSelectOptions();
  255. $valueArr = array();
  256. if (!empty($options)) {
  257. foreach ($options as $o) {
  258. if (is_array($value)) {
  259. if (in_array($o['value'], $value)) {
  260. $valueArr[] = $o['label'];
  261. }
  262. } else {
  263. if (is_array($o['value'])) {
  264. foreach ($o['value'] as $v) {
  265. if ($v['value']==$value) {
  266. return $v['label'];
  267. }
  268. }
  269. }
  270. if ($o['value']==$value) {
  271. return $o['label'];
  272. }
  273. }
  274. }
  275. }
  276. if (!empty($valueArr)) {
  277. $value = implode(', ', $valueArr);
  278. }
  279. return $value;
  280. }
  281. public function getNewChildSelectOptions()
  282. {
  283. return array(
  284. array('value'=>'', 'label'=>Mage::helper('rule')->__('Please choose a condition to add...')),
  285. );
  286. }
  287. public function getNewChildName()
  288. {
  289. return $this->getAddLinkHtml();
  290. }
  291. public function asHtml()
  292. {
  293. $html = $this->getTypeElementHtml()
  294. .$this->getAttributeElementHtml()
  295. .$this->getOperatorElementHtml()
  296. .$this->getValueElementHtml()
  297. .$this->getRemoveLinkHtml()
  298. .$this->getChooserContainerHtml();
  299. return $html;
  300. }
  301. public function asHtmlRecursive()
  302. {
  303. $html = $this->asHtml();
  304. return $html;
  305. }
  306. public function getTypeElement()
  307. {
  308. return $this->getForm()->addField($this->getPrefix().'__'.$this->getId().'__type', 'hidden', array(
  309. 'name'=>'rule['.$this->getPrefix().']['.$this->getId().'][type]',
  310. 'value'=>$this->getType(),
  311. 'no_span'=>true,
  312. 'class' => 'hidden',
  313. ));
  314. }
  315. public function getTypeElementHtml()
  316. {
  317. return $this->getTypeElement()->getHtml();
  318. }
  319. public function getAttributeElement()
  320. {
  321. if (is_null($this->getAttribute())) {
  322. foreach ($this->getAttributeOption() as $k=>$v) {
  323. $this->setAttribute($k);
  324. break;
  325. }
  326. }
  327. return $this->getForm()->addField($this->getPrefix().'__'.$this->getId().'__attribute', 'select', array(
  328. 'name'=>'rule['.$this->getPrefix().']['.$this->getId().'][attribute]',
  329. 'values'=>$this->getAttributeSelectOptions(),
  330. 'value'=>$this->getAttribute(),
  331. 'value_name'=>$this->getAttributeName(),
  332. ))->setRenderer(Mage::getBlockSingleton('rule/editable'));
  333. }
  334. public function getAttributeElementHtml()
  335. {
  336. return $this->getAttributeElement()->getHtml();
  337. }
  338. /**
  339. * Retrieve Condition Operator element Instance
  340. * If the operator value is empty - define first available operator value as default
  341. *
  342. * @return Varien_Data_Form_Element_Select
  343. */
  344. public function getOperatorElement()
  345. {
  346. $options = $this->getOperatorSelectOptions();
  347. if (is_null($this->getOperator())) {
  348. foreach ($options as $option) {
  349. $this->setOperator($option['value']);
  350. break;
  351. }
  352. }
  353. $elementId = sprintf('%s__%s__operator', $this->getPrefix(), $this->getId());
  354. $elementName = sprintf('rule[%s][%s][operator]', $this->getPrefix(), $this->getId());
  355. $element = $this->getForm()->addField($elementId, 'select', array(
  356. 'name' => $elementName,
  357. 'values' => $options,
  358. 'value' => $this->getOperator(),
  359. 'value_name' => $this->getOperatorName(),
  360. ));
  361. $element->setRenderer(Mage::getBlockSingleton('rule/editable'));
  362. return $element;
  363. }
  364. public function getOperatorElementHtml()
  365. {
  366. return $this->getOperatorElement()->getHtml();
  367. }
  368. /**
  369. * Value element type will define renderer for condition value element
  370. *
  371. * @see Varien_Data_Form_Element
  372. * @return string
  373. */
  374. public function getValueElementType()
  375. {
  376. return 'text';
  377. }
  378. public function getValueElementRenderer()
  379. {
  380. if (strpos($this->getValueElementType(), '/')!==false) {
  381. return Mage::getBlockSingleton($this->getValueElementType());
  382. }
  383. return Mage::getBlockSingleton('rule/editable');
  384. }
  385. public function getValueElement()
  386. {
  387. $elementParams = array(
  388. 'name' => 'rule['.$this->getPrefix().']['.$this->getId().'][value]',
  389. 'value' => $this->getValue(),
  390. 'values' => $this->getValueSelectOptions(),
  391. 'value_name' => $this->getValueName(),
  392. 'after_element_html' => $this->getValueAfterElementHtml(),
  393. 'explicit_apply' => $this->getExplicitApply(),
  394. );
  395. if ($this->getInputType()=='date') {
  396. // date format intentionally hard-coded
  397. $elementParams['input_format'] = Varien_Date::DATE_INTERNAL_FORMAT;
  398. $elementParams['format'] = Varien_Date::DATE_INTERNAL_FORMAT;
  399. }
  400. return $this->getForm()->addField($this->getPrefix().'__'.$this->getId().'__value',
  401. $this->getValueElementType(),
  402. $elementParams
  403. )->setRenderer($this->getValueElementRenderer());
  404. }
  405. public function getValueElementHtml()
  406. {
  407. return $this->getValueElement()->getHtml();
  408. }
  409. public function getAddLinkHtml()
  410. {
  411. $src = Mage::getDesign()->getSkinUrl('images/rule_component_add.gif');
  412. $html = '<img src="'.$src.'" class="rule-param-add v-middle" alt="" title="'.Mage::helper('rule')->__('Add').'"/>';
  413. return $html;
  414. }
  415. public function getRemoveLinkHtml()
  416. {
  417. $src = Mage::getDesign()->getSkinUrl('images/rule_component_remove.gif');
  418. $html = ' <span class="rule-param"><a href="javascript:void(0)" class="rule-param-remove" title="'.Mage::helper('rule')->__('Remove').'"><img src="'.$src.'" alt="" class="v-middle" /></a></span>';
  419. return $html;
  420. }
  421. public function getChooserContainerHtml()
  422. {
  423. $url = $this->getValueElementChooserUrl();
  424. $html = '';
  425. if ($url) {
  426. $html = '<div class="rule-chooser" url="'.$url.'"></div>';
  427. }
  428. return $html;
  429. }
  430. public function asString($format='')
  431. {
  432. $str = $this->getAttributeName().' '.$this->getOperatorName().' '.$this->getValueName();
  433. return $str;
  434. }
  435. public function asStringRecursive($level=0)
  436. {
  437. $str = str_pad('', $level*3, ' ', STR_PAD_LEFT).$this->asString();
  438. return $str;
  439. }
  440. /**
  441. * Validate product attrbute value for condition
  442. *
  443. * @param mixed $validatedValue product attribute value
  444. * @return bool
  445. */
  446. public function validateAttribute($validatedValue)
  447. {
  448. if (is_object($validatedValue)) {
  449. return false;
  450. }
  451. /**
  452. * Condition attribute value
  453. */
  454. $value = $this->getValueParsed();
  455. /**
  456. * Comparison operator
  457. */
  458. $op = $this->getOperator();
  459. // if operator requires array and it is not, or on opposite, return false
  460. if ((
  461. ($op == '()' || $op == '!()' || $op == '{}' || $op == '!{}')
  462. && !is_array($value)
  463. ) || (
  464. !($op == '()' || $op == '!()' || $op == '{}' || $op == '!{}' || $op == '==' || $op == '!=')
  465. && is_array($value)
  466. )) {
  467. return false;
  468. }
  469. $result = false;
  470. switch ($op) {
  471. case '==': case '!=':
  472. if (is_array($value)) {
  473. if (is_array($validatedValue)) {
  474. $result = array_intersect($value, $validatedValue);
  475. $result = !empty($result);
  476. } else {
  477. return false;
  478. }
  479. } else {
  480. if (is_array($validatedValue)) {
  481. $result = in_array($value, $validatedValue);
  482. } else {
  483. $result = $validatedValue == $value;
  484. }
  485. }
  486. break;
  487. case '<=': case '>':
  488. if (is_array($validatedValue) || is_null($validatedValue)) {
  489. $result = false;
  490. } else {
  491. $result = $validatedValue<=$value;
  492. }
  493. break;
  494. case '>=': case '<':
  495. if (is_array($validatedValue) || is_null($validatedValue)) {
  496. $result = false;
  497. } else {
  498. $result = $validatedValue>=$value;
  499. }
  500. break;
  501. case '{}': case '!{}':
  502. if (is_scalar($validatedValue) && is_array($value)) {
  503. foreach ($value as $item) {
  504. if (stripos($validatedValue,$item)!==false) {
  505. $result = true;
  506. break;
  507. }
  508. }
  509. } elseif (is_array($value)) {
  510. if (is_array($validatedValue)) {
  511. $result = array_intersect($value, $validatedValue);
  512. $result = !empty($result);
  513. } else {
  514. return false;
  515. }
  516. } else {
  517. if (is_array($validatedValue)) {
  518. $result = false;
  519. } else {
  520. $result = stripos((string)$validatedValue, (string)$value)!==false;
  521. }
  522. }
  523. break;
  524. case '()': case '!()':
  525. if (is_array($validatedValue)) {
  526. $result = count(array_intersect($validatedValue, (array)$value))>0;
  527. } else {
  528. $result = in_array($validatedValue, (array)$value);
  529. }
  530. break;
  531. }
  532. if ('!='==$op || '>'==$op || '<'==$op || '!{}'==$op || '!()'==$op) {
  533. $result = !$result;
  534. }
  535. return $result;
  536. }
  537. public function validate(Varien_Object $object)
  538. {
  539. return $this->validateAttribute($object->getData($this->getAttribute()));
  540. }
  541. }