views_handler_filter_numeric.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. <?php
  2. /**
  3. * @file
  4. * Definition of views_handler_filter_numeric.
  5. */
  6. /**
  7. * Simple filter to handle greater than/less than filters
  8. *
  9. * @ingroup views_filter_handlers
  10. */
  11. class views_handler_filter_numeric extends views_handler_filter {
  12. /**
  13. * Exposed filter options.
  14. */
  15. public $always_multiple = TRUE;
  16. /**
  17. * {@inheritdoc}
  18. */
  19. public function option_definition() {
  20. $options = parent::option_definition();
  21. $options['value'] = array(
  22. 'contains' => array(
  23. 'min' => array('default' => ''),
  24. 'max' => array('default' => ''),
  25. 'value' => array('default' => ''),
  26. ),
  27. );
  28. return $options;
  29. }
  30. /**
  31. * {@inheritdoc}
  32. */
  33. public function operators() {
  34. $operators = array(
  35. '<' => array(
  36. 'title' => t('Is less than'),
  37. 'method' => 'op_simple',
  38. 'short' => t('<'),
  39. 'values' => 1,
  40. ),
  41. '<=' => array(
  42. 'title' => t('Is less than or equal to'),
  43. 'method' => 'op_simple',
  44. 'short' => t('<='),
  45. 'values' => 1,
  46. ),
  47. '=' => array(
  48. 'title' => t('Is equal to'),
  49. 'method' => 'op_simple',
  50. 'short' => t('='),
  51. 'values' => 1,
  52. ),
  53. '!=' => array(
  54. 'title' => t('Is not equal to'),
  55. 'method' => 'op_simple',
  56. 'short' => t('!='),
  57. 'values' => 1,
  58. ),
  59. '>=' => array(
  60. 'title' => t('Is greater than or equal to'),
  61. 'method' => 'op_simple',
  62. 'short' => t('>='),
  63. 'values' => 1,
  64. ),
  65. '>' => array(
  66. 'title' => t('Is greater than'),
  67. 'method' => 'op_simple',
  68. 'short' => t('>'),
  69. 'values' => 1,
  70. ),
  71. 'between' => array(
  72. 'title' => t('Is between'),
  73. 'method' => 'op_between',
  74. 'short' => t('between'),
  75. 'values' => 2,
  76. ),
  77. 'not between' => array(
  78. 'title' => t('Is not between'),
  79. 'method' => 'op_between',
  80. 'short' => t('not between'),
  81. 'values' => 2,
  82. ),
  83. );
  84. // if the definition allows for the empty operator, add it.
  85. if (!empty($this->definition['allow empty'])) {
  86. $operators += array(
  87. 'empty' => array(
  88. 'title' => t('Is empty (NULL)'),
  89. 'method' => 'op_empty',
  90. 'short' => t('empty'),
  91. 'values' => 0,
  92. ),
  93. 'not empty' => array(
  94. 'title' => t('Is not empty (NOT NULL)'),
  95. 'method' => 'op_empty',
  96. 'short' => t('not empty'),
  97. 'values' => 0,
  98. ),
  99. );
  100. }
  101. // Add regexp support for MySQL.
  102. if (Database::getConnection()->databaseType() == 'mysql') {
  103. $operators += array(
  104. 'regular_expression' => array(
  105. 'title' => t('Regular expression'),
  106. 'short' => t('regex'),
  107. 'method' => 'op_regex',
  108. 'values' => 1,
  109. ),
  110. 'not_regular_expression' => array(
  111. 'title' => t('Not regular expression'),
  112. 'short' => t('not regex'),
  113. 'method' => 'op_not_regex',
  114. 'values' => 1,
  115. ),
  116. );
  117. }
  118. return $operators;
  119. }
  120. /**
  121. * Provide a list of all the numeric operators
  122. */
  123. public function operator_options($which = 'title') {
  124. $options = array();
  125. foreach ($this->operators() as $id => $info) {
  126. $options[$id] = $info[$which];
  127. }
  128. return $options;
  129. }
  130. /**
  131. * {@inheritdoc}
  132. */
  133. public function operator_values($values = 1) {
  134. $options = array();
  135. foreach ($this->operators() as $id => $info) {
  136. if ($info['values'] == $values) {
  137. $options[] = $id;
  138. }
  139. }
  140. return $options;
  141. }
  142. /**
  143. * Provide a simple textfield for equality
  144. */
  145. public function value_form(&$form, &$form_state) {
  146. $form['value']['#tree'] = TRUE;
  147. // We have to make some choices when creating this as an exposed
  148. // filter form. For example, if the operator is locked and thus
  149. // not rendered, we can't render dependencies; instead we only
  150. // render the form items we need.
  151. $which = 'all';
  152. $limit_operators = !empty($this->options['expose']['limit_operators']) && (count($this->options['expose']['available_operators']) > 0);
  153. $use_value = FALSE;
  154. $use_minmax = FALSE;
  155. if (!empty($form['operator'])) {
  156. $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
  157. }
  158. if (!empty($form_state['exposed'])) {
  159. $operator_values_with_1_values = $this->operator_values(1);
  160. $operator_values_with_2_values = $this->operator_values(2);
  161. if ($limit_operators) {
  162. // If limit operators is enabled, check that at least one operator
  163. // with two values is enabled to display the min max widgets
  164. foreach ($operator_values_with_2_values as $operator) {
  165. if (isset($this->options['expose']['available_operators'][$operator])) {
  166. $use_minmax = TRUE;
  167. break;
  168. }
  169. }
  170. // the same for operators with one value
  171. foreach ($operator_values_with_1_values as $operator) {
  172. if (isset($this->options['expose']['available_operators'][$operator])) {
  173. $use_value = TRUE;
  174. break;
  175. }
  176. }
  177. }
  178. else {
  179. $use_minmax = $use_value = TRUE;
  180. }
  181. $identifier = $this->options['expose']['identifier'];
  182. if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
  183. // exposed and locked.
  184. $which = in_array($this->operator, $operator_values_with_2_values) ? 'minmax' : 'value';
  185. }
  186. else {
  187. $source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
  188. }
  189. }
  190. else {
  191. $use_minmax = $use_value = TRUE;
  192. }
  193. if ($use_value) {
  194. if ($which == 'all') {
  195. $form['value']['value'] = array(
  196. '#type' => 'textfield',
  197. '#title' => empty($form_state['exposed']) ? t('Value') : '',
  198. '#size' => 30,
  199. '#default_value' => $this->value['value'],
  200. '#dependency' => array($source => $this->operator_values(1)),
  201. );
  202. if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['value'])) {
  203. $form_state['input'][$identifier]['value'] = $this->value['value'];
  204. }
  205. }
  206. elseif ($which == 'value') {
  207. // When exposed we drop the value-value and just do value if
  208. // the operator is locked.
  209. $form['value'] = array(
  210. '#type' => 'textfield',
  211. '#title' => empty($form_state['exposed']) ? t('Value') : '',
  212. '#size' => 30,
  213. '#default_value' => $this->value['value'],
  214. );
  215. if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
  216. $form_state['input'][$identifier] = $this->value['value'];
  217. }
  218. }
  219. }
  220. if ($which == 'all' || $which == 'minmax') {
  221. if ($use_minmax) {
  222. $form['value']['min'] = array(
  223. '#type' => 'textfield',
  224. '#title' => empty($form_state['exposed']) ? t('Min') : '',
  225. '#size' => 30,
  226. '#default_value' => $this->value['min'],
  227. );
  228. $form['value']['max'] = array(
  229. '#type' => 'textfield',
  230. '#title' => empty($form_state['exposed']) ? t('And max') : t('And'),
  231. '#size' => 30,
  232. '#default_value' => $this->value['max'],
  233. );
  234. if ($which == 'all') {
  235. $dependency = array(
  236. '#dependency' => array($source => $this->operator_values(2)),
  237. );
  238. $form['value']['min'] += $dependency;
  239. $form['value']['max'] += $dependency;
  240. }
  241. }
  242. if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['min']) && $use_minmax) {
  243. $form_state['input'][$identifier]['min'] = $this->value['min'];
  244. }
  245. if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['max']) && $use_minmax) {
  246. $form_state['input'][$identifier]['max'] = $this->value['max'];
  247. }
  248. if (!isset($form['value'])) {
  249. // Ensure there is something in the 'value'.
  250. $form['value'] = array(
  251. '#type' => 'value',
  252. '#value' => NULL
  253. );
  254. }
  255. }
  256. }
  257. /**
  258. * {@inheritdoc}
  259. */
  260. public function query() {
  261. $this->ensure_my_table();
  262. $field = "$this->table_alias.$this->real_field";
  263. $info = $this->operators();
  264. if (!empty($info[$this->operator]['method'])) {
  265. $this->{$info[$this->operator]['method']}($field);
  266. }
  267. }
  268. /**
  269. * {@inheritdoc}
  270. */
  271. public function op_between($field) {
  272. if ($this->operator == 'between') {
  273. $this->query->add_where($this->options['group'], $field, array($this->value['min'], $this->value['max']), 'BETWEEN');
  274. }
  275. else {
  276. $this->query->add_where($this->options['group'], db_or()->condition($field, $this->value['min'], '<=')->condition($field, $this->value['max'], '>='));
  277. }
  278. }
  279. /**
  280. * {@inheritdoc}
  281. */
  282. public function op_simple($field) {
  283. $this->query->add_where($this->options['group'], $field, $this->value['value'], $this->operator);
  284. }
  285. /**
  286. * {@inheritdoc}
  287. */
  288. public function op_empty($field) {
  289. if ($this->operator == 'empty') {
  290. $operator = "IS NULL";
  291. }
  292. else {
  293. $operator = "IS NOT NULL";
  294. }
  295. $this->query->add_where($this->options['group'], $field, NULL, $operator);
  296. }
  297. /**
  298. * {@inheritdoc}
  299. */
  300. public function op_regex($field) {
  301. $this->query->add_where($this->options['group'], $field, $this->value['value'], 'RLIKE');
  302. }
  303. /**
  304. * {@inheritdoc}
  305. */
  306. public function op_not_regex($field) {
  307. $this->query->add_where($this->options['group'], $field, $this->value['value'], 'NOT RLIKE');
  308. }
  309. /**
  310. * {@inheritdoc}
  311. */
  312. public function admin_summary() {
  313. if ($this->is_a_group()) {
  314. return t('grouped');
  315. }
  316. if (!empty($this->options['exposed'])) {
  317. return t('exposed');
  318. }
  319. $options = $this->operator_options('short');
  320. $output = check_plain($options[$this->operator]);
  321. if (in_array($this->operator, $this->operator_values(2))) {
  322. $output .= ' ' . t('@min and @max', array('@min' => $this->value['min'], '@max' => $this->value['max']));
  323. }
  324. elseif (in_array($this->operator, $this->operator_values(1))) {
  325. $output .= ' ' . check_plain($this->value['value']);
  326. }
  327. return $output;
  328. }
  329. /**
  330. * Do some minor translation of the exposed input.
  331. */
  332. public function accept_exposed_input($input) {
  333. if (empty($this->options['exposed'])) {
  334. return TRUE;
  335. }
  336. // Rewrite the input value so that it's in the correct format so that the
  337. // parent gets the right data.
  338. if (!empty($this->options['expose']['identifier'])) {
  339. $value = &$input[$this->options['expose']['identifier']];
  340. if (!is_array($value)) {
  341. $value = array(
  342. 'value' => $value,
  343. );
  344. }
  345. }
  346. $rc = parent::accept_exposed_input($input);
  347. if (empty($this->options['expose']['required'])) {
  348. // We have to do some of our own checking for non-required filters.
  349. $info = $this->operators();
  350. if (!empty($info[$this->operator]['values'])) {
  351. switch ($info[$this->operator]['values']) {
  352. case 1:
  353. if ($value['value'] === '') {
  354. return FALSE;
  355. }
  356. break;
  357. case 2:
  358. if ($value['min'] === '' && $value['max'] === '') {
  359. return FALSE;
  360. }
  361. break;
  362. }
  363. }
  364. }
  365. return $rc;
  366. }
  367. }