PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/core/Tracker/Field/Dropdown.php

https://gitlab.com/ElvisAns/tiki
PHP | 391 lines | 327 code | 50 blank | 14 comment | 25 complexity | 4088bf7c2aa305e64564a3a414df9704 MD5 | raw file
  1. <?php
  2. // (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
  3. //
  4. // All Rights Reserved. See copyright.txt for details and a complete list of authors.
  5. // Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
  6. // $Id$
  7. /**
  8. * Handler class for dropdown
  9. *
  10. * Letter key: ~d~ ~D~ ~R~ ~M~
  11. *
  12. */
  13. class Tracker_Field_Dropdown extends Tracker_Field_Abstract implements Tracker_Field_Synchronizable, Search_FacetProvider_Interface, Tracker_Field_Exportable, Tracker_Field_Filterable
  14. {
  15. public static function getTypes()
  16. {
  17. return [
  18. 'd' => [
  19. 'name' => tr('Dropdown'),
  20. 'description' => tr('Allow users to select only from a specified set of options'),
  21. 'help' => 'Drop-Down---Radio-Tracker-Field',
  22. 'prefs' => ['trackerfield_dropdown'],
  23. 'tags' => ['basic'],
  24. 'default' => 'y',
  25. 'supported_changes' => ['d', 'D', 'R', 'M', 'm', 't', 'a', 'L'],
  26. 'params' => [
  27. 'options' => [
  28. 'name' => tr('Option'),
  29. 'description' => tr('If an option contains an equal sign, the part before the equal sign will be used as the value, and the second part as the label'),
  30. 'filter' => 'text',
  31. 'count' => '*',
  32. 'legacy_index' => 0,
  33. ],
  34. ],
  35. ],
  36. 'D' => [
  37. 'name' => tr('Dropdown selector with "Other" field'),
  38. 'description' => tr('Allow users to select from a specified set of options or to enter an alternate option'),
  39. 'help' => 'Drop-Down---Radio-Tracker-Field',
  40. 'prefs' => ['trackerfield_dropdownother'],
  41. 'tags' => ['basic'],
  42. 'default' => 'n',
  43. 'supported_changes' => ['d', 'D', 'R', 'M', 'm', 't', 'a', 'L'],
  44. 'params' => [
  45. 'options' => [
  46. 'name' => tr('Option'),
  47. 'description' => tr('If an option contains an equal sign, the part before the equal sign will be used as the value, and the second part as the label.') . ' ' . tr('To change the label of the "Other" option, use "other=Label".'),
  48. 'filter' => 'text',
  49. 'count' => '*',
  50. 'legacy_index' => 0,
  51. ],
  52. ],
  53. ],
  54. 'R' => [
  55. 'name' => tr('Radio Buttons'),
  56. 'description' => tr('Allow users to select only from a specified set of options'),
  57. 'help' => 'Drop-Down---Radio-Tracker-Field',
  58. 'prefs' => ['trackerfield_radio'],
  59. 'tags' => ['basic'],
  60. 'default' => 'y',
  61. 'supported_changes' => ['d', 'D', 'R', 'M', 'm', 't', 'a', 'L'],
  62. 'params' => [
  63. 'options' => [
  64. 'name' => tr('Option'),
  65. 'description' => tr('If an option contains an equal sign, the part before the equal sign will be used as the value, and the second part as the label'),
  66. 'filter' => 'text',
  67. 'count' => '*',
  68. 'legacy_index' => 0,
  69. ],
  70. ],
  71. ],
  72. 'M' => [
  73. 'name' => tr('Multiselect'),
  74. 'description' => tr('Allow a user to select multiple values from a specified set of options'),
  75. 'help' => 'Multiselect-Tracker-Field',
  76. 'prefs' => ['trackerfield_multiselect'],
  77. 'tags' => ['basic'],
  78. 'default' => 'y',
  79. 'supported_changes' => ['M', 'm', 't', 'a', 'L'],
  80. 'params' => [
  81. 'options' => [
  82. 'name' => tr('Option'),
  83. 'description' => tr('If an option contains an equal sign, the part before the equal sign will be used as the value, and the second part as the label'),
  84. 'filter' => 'text',
  85. 'count' => '*',
  86. 'legacy_index' => 0,
  87. ],
  88. 'inputtype' => [
  89. 'name' => tr('Input Type'),
  90. 'description' => tr('User interface control to be used.'),
  91. 'default' => '',
  92. 'filter' => 'alpha',
  93. 'options' => [
  94. '' => tr('Multiple-selection checkboxes'),
  95. 'm' => tr('List box'),
  96. ],
  97. ],
  98. ],
  99. ],
  100. ];
  101. }
  102. public static function build($type, $trackerDefinition, $fieldInfo, $itemData)
  103. {
  104. return new Tracker_Field_Dropdown($fieldInfo, $itemData, $trackerDefinition);
  105. }
  106. public function getFieldData(array $requestData = [])
  107. {
  108. $ins_id = $this->getInsertId();
  109. if (! empty($requestData['other_' . $ins_id])) {
  110. $value = $requestData['other_' . $ins_id];
  111. } elseif (isset($requestData[$ins_id])) {
  112. $value = implode(',', (array) $requestData[$ins_id]);
  113. } elseif (isset($requestData[$ins_id . '_old'])) {
  114. $value = '';
  115. } else {
  116. $value = $this->getValue($this->getDefaultValue());
  117. }
  118. return [
  119. 'value' => $value,
  120. 'selected' => $value === '' ? [] : explode(',', $value),
  121. 'possibilities' => $this->getPossibilities(),
  122. ];
  123. }
  124. public function addValue($value)
  125. {
  126. $existing = explode(',', $this->getValue());
  127. if (! in_array($value, $existing)) {
  128. $existing[] = $value;
  129. }
  130. return implode(',', $existing);
  131. }
  132. public function removeValue($value)
  133. {
  134. $existing = explode(',', $this->getValue());
  135. $existing = array_filter($existing, function ($v) use ($value) {
  136. return $v != $value;
  137. });
  138. return implode(',', $existing);
  139. }
  140. public function renderInput($context = [])
  141. {
  142. return $this->renderTemplate('trackerinput/dropdown.tpl', $context);
  143. }
  144. public function renderInnerOutput($context = [])
  145. {
  146. if (! empty($context['list_mode']) && $context['list_mode'] === 'csv') {
  147. return implode(', ', $this->getConfiguration('selected', []));
  148. } else {
  149. $labels = array_map([$this, 'getValueLabel'], $this->getConfiguration('selected', []));
  150. return implode(', ', $labels);
  151. }
  152. }
  153. private function getValueLabel($value)
  154. {
  155. $possibilities = $this->getPossibilities();
  156. if (isset($possibilities[$value])) {
  157. return $possibilities[$value];
  158. } else {
  159. return $value;
  160. }
  161. }
  162. public function importRemote($value)
  163. {
  164. return $value;
  165. }
  166. public function exportRemote($value)
  167. {
  168. return $value;
  169. }
  170. public function importRemoteField(array $info, array $syncInfo)
  171. {
  172. return $info;
  173. }
  174. private function getPossibilities()
  175. {
  176. static $localCache = [];
  177. $string = $this->getConfiguration('options');
  178. if (! isset($localCache[$string])) {
  179. $options = $this->getOption('options');
  180. if (empty($options)) {
  181. return [];
  182. }
  183. $out = [];
  184. foreach ($options as $value) {
  185. $out[$this->getValuePortion($value)] = $this->getLabelPortion($value);
  186. }
  187. $localCache[$string] = $out;
  188. }
  189. return $localCache[$string];
  190. }
  191. private function getDefaultValue()
  192. {
  193. $options = $this->getOption('options');
  194. $parts = [];
  195. $last = false;
  196. foreach ($options as $opt) {
  197. if ($last === $opt) {
  198. $parts[] = $this->getValuePortion($opt);
  199. }
  200. $last = $opt;
  201. }
  202. return implode(',', $parts);
  203. }
  204. private function getValuePortion($value)
  205. {
  206. if (false !== $pos = strpos($value, '=')) {
  207. $value = substr($value, 0, $pos);
  208. }
  209. // Check if option is contains quotes, ex: "apple, banana, orange"
  210. if (preg_match('/^(").*\1$/', $value)) {
  211. $value = substr($value, 1, strlen($value) - 2);
  212. }
  213. return $value;
  214. }
  215. private function getLabelPortion($value)
  216. {
  217. if (false !== $pos = strpos($value, '=')) {
  218. $value = substr($value, $pos + 1);
  219. }
  220. if (preg_match('/^(").*\1$/', $value)) {
  221. $value = substr($value, 1, strlen($value) - 2);
  222. }
  223. return $value;
  224. }
  225. public function getDocumentPart(Search_Type_Factory_Interface $typeFactory)
  226. {
  227. $value = $this->getValue();
  228. $label = $this->getValueLabel($value);
  229. $baseKey = $this->getBaseKey();
  230. return [
  231. $baseKey => $typeFactory->identifier($value),
  232. "{$baseKey}_text" => $typeFactory->sortable($label),
  233. ];
  234. }
  235. public function getProvidedFields()
  236. {
  237. $baseKey = $this->getBaseKey();
  238. return [$baseKey, $baseKey . '_text'];
  239. }
  240. public function getGlobalFields()
  241. {
  242. $baseKey = $this->getBaseKey();
  243. return ["{$baseKey}_text" => true];
  244. }
  245. public function getFacets()
  246. {
  247. $baseKey = $this->getBaseKey();
  248. return [
  249. Search_Query_Facet_Term::fromField($baseKey)
  250. ->setLabel($this->getConfiguration('name'))
  251. ->setRenderMap($this->getPossibilities())
  252. ];
  253. }
  254. public function getTabularSchema()
  255. {
  256. $schema = new Tracker\Tabular\Schema($this->getTrackerDefinition());
  257. $permName = $this->getConfiguration('permName');
  258. $name = $this->getConfiguration('name');
  259. $possibilities = $this->getPossibilities();
  260. $invert = array_flip($possibilities);
  261. $withOther = ($this->getConfiguration('type') === 'D');
  262. $schema->addNew($permName, 'code')
  263. ->setLabel($name)
  264. ->setRenderTransform(function ($value) {
  265. return $value;
  266. })
  267. ->setParseIntoTransform(function (&$info, $value) use ($permName) {
  268. $info['fields'][$permName] = $value;
  269. })
  270. ;
  271. $schema->addNew($permName, 'text')
  272. ->setLabel($name)
  273. ->addIncompatibility($permName, 'code')
  274. ->addQuerySource('text', "tracker_field_{$permName}_text")
  275. ->setRenderTransform(function ($value, $extra) use ($possibilities, $withOther) {
  276. if (isset($possibilities[$value])) {
  277. return $possibilities[$value];
  278. } elseif ($withOther) {
  279. return $value;
  280. } else {
  281. return ''; // TODO something better?
  282. }
  283. })
  284. ->setParseIntoTransform(function (&$info, $value) use ($permName, $invert, $withOther) {
  285. if (isset($invert[$value])) {
  286. $info['fields'][$permName] = $invert[$value];
  287. } elseif ($withOther) {
  288. $info['fields'][$permName] = $value;
  289. }
  290. })
  291. ;
  292. return $schema;
  293. }
  294. public function getFilterCollection()
  295. {
  296. $filters = new Tracker\Filter\Collection($this->getTrackerDefinition());
  297. $permName = $this->getConfiguration('permName');
  298. $name = $this->getConfiguration('name');
  299. $baseKey = $this->getBaseKey();
  300. $possibilities = $this->getPossibilities();
  301. if ($this->getConfiguration('type') == 'D') {
  302. // TODO: make these and the ones in wikiplugin_trackerFilter_get_filters actually return accessible items
  303. // i.e. if I am not able to see an item, I should not see its value in the filter as well (WYSIWYCA problem)
  304. $all = TikiLib::lib('trk')->list_tracker_field_values($this->getTrackerDefinition()->getConfiguration('trackerId'), $this->getFieldId());
  305. foreach ($all as $val) {
  306. if (! isset($possibilities[$val])) {
  307. $possibilities[$val] = $val;
  308. }
  309. }
  310. }
  311. $possibilities['-Blank (no data)-'] = tr('-Blank (no data)-');
  312. $filters->addNew($permName, 'dropdown')
  313. ->setLabel($name)
  314. ->setControl(new Tracker\Filter\Control\DropDown("tf_{$permName}_dd", $possibilities))
  315. ->setApplyCondition(function ($control, Search_Query $query) use ($baseKey) {
  316. $value = $control->getValue();
  317. if ($value === '-Blank (no data)-') {
  318. $query->filterIdentifier('', $baseKey . '_text');
  319. } elseif ($value) {
  320. $query->filterIdentifier($value, $baseKey);
  321. }
  322. });
  323. $filters->addNew($permName, 'multiselect')
  324. ->setLabel($name)
  325. ->setControl(new Tracker\Filter\Control\MultiSelect("tf_{$permName}_ms", $possibilities))
  326. ->setApplyCondition(function ($control, Search_Query $query) use ($permName, $baseKey) {
  327. $values = $control->getValues();
  328. if (! empty($values)) {
  329. $sub = $query->getSubQuery("ms_$permName");
  330. foreach ($values as $v) {
  331. if ($v === '-Blank (no data)-') {
  332. $sub->filterIdentifier('', $baseKey . '_text');
  333. } elseif ($v) {
  334. $sub->filterContent((string) $v, $baseKey);
  335. }
  336. }
  337. }
  338. });
  339. return $filters;
  340. }
  341. }