PageRenderTime 49ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/symphony/lib/toolkit/fields/field.input.php

http://github.com/symphonycms/symphony-2
PHP | 447 lines | 304 code | 74 blank | 69 comment | 37 complexity | a7141abee4fa4453570b5d978dab004e MD5 | raw file
  1. <?php
  2. /**
  3. * @package toolkit
  4. */
  5. /**
  6. * A simple Input field that essentially maps to HTML's `<input type='text'/>`.
  7. */
  8. class FieldInput extends Field implements ExportableField, ImportableField
  9. {
  10. public function __construct()
  11. {
  12. parent::__construct();
  13. $this->_name = __('Text Input');
  14. $this->_required = true;
  15. $this->entryQueryFieldAdapter = new EntryQueryInputAdapter($this);
  16. $this->set('required', 'no');
  17. }
  18. /*-------------------------------------------------------------------------
  19. Definition:
  20. -------------------------------------------------------------------------*/
  21. public function canFilter()
  22. {
  23. return true;
  24. }
  25. public function canPrePopulate()
  26. {
  27. return true;
  28. }
  29. public function isSortable()
  30. {
  31. return true;
  32. }
  33. public function allowDatasourceOutputGrouping()
  34. {
  35. return true;
  36. }
  37. public function allowDatasourceParamOutput()
  38. {
  39. return true;
  40. }
  41. /*-------------------------------------------------------------------------
  42. Setup:
  43. -------------------------------------------------------------------------*/
  44. public function createTable()
  45. {
  46. return Symphony::Database()
  47. ->create('tbl_entries_data_' . General::intval($this->get('id')))
  48. ->ifNotExists()
  49. ->fields([
  50. 'id' => [
  51. 'type' => 'int(11)',
  52. 'auto' => true,
  53. ],
  54. 'entry_id' => 'int(11)',
  55. 'handle' => [
  56. 'type' => 'varchar(255)',
  57. 'null' => true,
  58. ],
  59. 'value' => [
  60. 'type' => 'varchar(255)',
  61. 'null' => true,
  62. ],
  63. ])
  64. ->keys([
  65. 'id' => 'primary',
  66. 'entry_id' => 'unique',
  67. 'handle' => 'key',
  68. 'value' => 'key',
  69. ])
  70. ->execute()
  71. ->success();
  72. }
  73. /*-------------------------------------------------------------------------
  74. Utilities:
  75. -------------------------------------------------------------------------*/
  76. private function __applyValidationRules($data)
  77. {
  78. $rule = $this->get('validator');
  79. return ($rule ? General::validateString($data, $rule) : true);
  80. }
  81. private function __replaceAmpersands($value)
  82. {
  83. return preg_replace('/&(?!(#[0-9]+|#x[0-9a-f]+|amp|lt|gt);)/i', '&amp;', trim($value));
  84. }
  85. /*-------------------------------------------------------------------------
  86. Settings:
  87. -------------------------------------------------------------------------*/
  88. public function setFromPOST(array $settings = array())
  89. {
  90. parent::setFromPOST($settings);
  91. if ($this->get('validator') == '') {
  92. $this->remove('validator');
  93. }
  94. }
  95. public function displaySettingsPanel(XMLElement &$wrapper, $errors = null)
  96. {
  97. parent::displaySettingsPanel($wrapper, $errors);
  98. // Validation rule
  99. $this->buildValidationSelect($wrapper, $this->get('validator'), 'fields['.$this->get('sortorder').'][validator]', 'input', $errors);
  100. // Requirements and table display
  101. $this->appendStatusFooter($wrapper);
  102. }
  103. public function commit()
  104. {
  105. if (!parent::commit()) {
  106. return false;
  107. }
  108. $id = $this->get('id');
  109. if ($id === false) {
  110. return false;
  111. }
  112. $fields = array('validator'=>null);
  113. $fields['validator'] = ($fields['validator'] == 'custom' ? null : $this->get('validator'));
  114. return FieldManager::saveSettings($id, $fields);
  115. }
  116. /*-------------------------------------------------------------------------
  117. Publish:
  118. -------------------------------------------------------------------------*/
  119. public function displayPublishPanel(XMLElement &$wrapper, $data = null, $flagWithError = null, $fieldnamePrefix = null, $fieldnamePostfix = null, $entry_id = null)
  120. {
  121. $value = General::sanitize(isset($data['value']) ? $data['value'] : null);
  122. $label = Widget::Label($this->get('label'));
  123. if ($this->get('required') !== 'yes') {
  124. $label->appendChild(new XMLElement('i', __('Optional')));
  125. }
  126. $label->appendChild(Widget::Input('fields'.$fieldnamePrefix.'['.$this->get('element_name').']'.$fieldnamePostfix, (strlen($value) != 0 ? $value : null)));
  127. if ($flagWithError != null) {
  128. $wrapper->appendChild(Widget::Error($label, $flagWithError));
  129. } else {
  130. $wrapper->appendChild($label);
  131. }
  132. }
  133. public function checkPostFieldData($data, &$message, $entry_id = null)
  134. {
  135. $message = null;
  136. if (is_array($data) && isset($data['value'])) {
  137. $data = $data['value'];
  138. }
  139. if ($this->get('required') === 'yes' && strlen(trim($data)) == 0) {
  140. $message = __('ā€˜%sā€™ is a required field.', array($this->get('label')));
  141. return self::__MISSING_FIELDS__;
  142. }
  143. if (!$this->__applyValidationRules($data)) {
  144. $message = __('ā€˜%sā€™ contains invalid data. Please check the contents.', array($this->get('label')));
  145. return self::__INVALID_FIELDS__;
  146. }
  147. return self::__OK__;
  148. }
  149. public function processRawFieldData($data, &$status, &$message = null, $simulate = false, $entry_id = null)
  150. {
  151. $status = self::__OK__;
  152. if (strlen(trim($data)) == 0) {
  153. return array();
  154. }
  155. $result = array(
  156. 'value' => General::substr($data, 0, 255)
  157. );
  158. $result['handle'] = Lang::createHandle($result['value']);
  159. return $result;
  160. }
  161. /*-------------------------------------------------------------------------
  162. Output:
  163. -------------------------------------------------------------------------*/
  164. public function appendFormattedElement(XMLElement &$wrapper, $data, $encode = false, $mode = null, $entry_id = null)
  165. {
  166. $value = $data['value'];
  167. if ($encode === true) {
  168. $value = General::sanitize($value);
  169. } else {
  170. if (!General::validateXML($data['value'], $errors, false, new XSLTProcess)) {
  171. $value = html_entity_decode($data['value'], ENT_QUOTES, 'UTF-8');
  172. $value = $this->__replaceAmpersands($value);
  173. if (!General::validateXML($value, $errors, false, new XSLTProcess)) {
  174. $value = General::sanitize($data['value']);
  175. }
  176. }
  177. }
  178. $wrapper->appendChild(
  179. new XMLElement($this->get('element_name'), $value, array('handle' => $data['handle']))
  180. );
  181. }
  182. /*-------------------------------------------------------------------------
  183. Import:
  184. -------------------------------------------------------------------------*/
  185. public function getImportModes()
  186. {
  187. return array(
  188. 'getValue' => ImportableField::STRING_VALUE,
  189. 'getPostdata' => ImportableField::ARRAY_VALUE
  190. );
  191. }
  192. public function prepareImportValue($data, $mode, $entry_id = null)
  193. {
  194. $message = $status = null;
  195. $modes = (object)$this->getImportModes();
  196. if ($mode === $modes->getValue) {
  197. return $data;
  198. } elseif ($mode === $modes->getPostdata) {
  199. return $this->processRawFieldData($data, $status, $message, true, $entry_id);
  200. }
  201. return null;
  202. }
  203. /*-------------------------------------------------------------------------
  204. Export:
  205. -------------------------------------------------------------------------*/
  206. /**
  207. * Return a list of supported export modes for use with `prepareExportValue`.
  208. *
  209. * @return array
  210. */
  211. public function getExportModes()
  212. {
  213. return array(
  214. 'getHandle' => ExportableField::HANDLE,
  215. 'getUnformatted' => ExportableField::UNFORMATTED,
  216. 'getPostdata' => ExportableField::POSTDATA
  217. );
  218. }
  219. /**
  220. * Give the field some data and ask it to return a value using one of many
  221. * possible modes.
  222. *
  223. * @param mixed $data
  224. * @param integer $mode
  225. * @param integer $entry_id
  226. * @return string|null
  227. */
  228. public function prepareExportValue($data, $mode, $entry_id = null)
  229. {
  230. $modes = (object)$this->getExportModes();
  231. // Export handles:
  232. if ($mode === $modes->getHandle) {
  233. if (isset($data['handle'])) {
  234. return $data['handle'];
  235. } elseif (isset($data['value'])) {
  236. return Lang::createHandle($data['value']);
  237. }
  238. // Export unformatted:
  239. } elseif ($mode === $modes->getUnformatted || $mode === $modes->getPostdata) {
  240. return isset($data['value'])
  241. ? $data['value']
  242. : null;
  243. }
  244. return null;
  245. }
  246. /*-------------------------------------------------------------------------
  247. Filtering:
  248. -------------------------------------------------------------------------*/
  249. /**
  250. * @deprecated @since Symphony 3.0.0
  251. * @see Field::buildDSRetrievalSQL()
  252. */
  253. public function buildDSRetrievalSQL($data, &$joins, &$where, $andOperation = false)
  254. {
  255. if (Symphony::Log()) {
  256. Symphony::Log()->pushDeprecateWarningToLog(
  257. get_called_class() . '::buildDSRetrievalSQL()',
  258. 'EntryQueryFieldAdapter::filter()'
  259. );
  260. }
  261. $field_id = $this->get('id');
  262. if (self::isFilterRegex($data[0])) {
  263. $this->buildRegexSQL($data[0], array('value', 'handle'), $joins, $where);
  264. } elseif (self::isFilterSQL($data[0])) {
  265. $this->buildFilterSQL($data[0], array('value', 'handle'), $joins, $where);
  266. } elseif ($andOperation) {
  267. foreach ($data as $value) {
  268. $this->_key++;
  269. $value = $this->cleanValue($value);
  270. $joins .= "
  271. LEFT JOIN
  272. `tbl_entries_data_{$field_id}` AS t{$field_id}_{$this->_key}
  273. ON (e.id = t{$field_id}_{$this->_key}.entry_id)
  274. ";
  275. $where .= "
  276. AND (
  277. t{$field_id}_{$this->_key}.value = '{$value}'
  278. OR t{$field_id}_{$this->_key}.handle = '{$value}'
  279. )
  280. ";
  281. }
  282. } else {
  283. if (!is_array($data)) {
  284. $data = array($data);
  285. }
  286. foreach ($data as &$value) {
  287. $value = $this->cleanValue($value);
  288. }
  289. $this->_key++;
  290. $data = implode("', '", $data);
  291. $joins .= "
  292. LEFT JOIN
  293. `tbl_entries_data_{$field_id}` AS t{$field_id}_{$this->_key}
  294. ON (e.id = t{$field_id}_{$this->_key}.entry_id)
  295. ";
  296. $where .= "
  297. AND (
  298. t{$field_id}_{$this->_key}.value IN ('{$data}')
  299. OR t{$field_id}_{$this->_key}.handle IN ('{$data}')
  300. )
  301. ";
  302. }
  303. return true;
  304. }
  305. /*-------------------------------------------------------------------------
  306. Sorting:
  307. -------------------------------------------------------------------------*/
  308. /**
  309. * @deprecated @since Symphony 3.0.0
  310. * @see Field::buildSortingSQL()
  311. */
  312. public function buildSortingSQL(&$joins, &$where, &$sort, $order = 'ASC')
  313. {
  314. if (Symphony::Log()) {
  315. Symphony::Log()->pushDeprecateWarningToLog(
  316. get_called_class() . '::buildSortingSQL()',
  317. 'EntryQueryFieldAdapter::sort()'
  318. );
  319. }
  320. if ($this->isRandomOrder($order)) {
  321. $sort = 'ORDER BY RAND()';
  322. } else {
  323. $sort = sprintf(
  324. 'ORDER BY (
  325. SELECT %s
  326. FROM tbl_entries_data_%d AS `ed`
  327. WHERE entry_id = e.id
  328. ) %s, `e`.`id` %s',
  329. '`ed`.value',
  330. $this->get('id'),
  331. $order,
  332. $order
  333. );
  334. }
  335. }
  336. /**
  337. * @deprecated @since Symphony 3.0.0
  338. * @see Field::buildSortingSelectSQL()
  339. */
  340. public function buildSortingSelectSQL($sort, $order = 'ASC')
  341. {
  342. if (Symphony::Log()) {
  343. Symphony::Log()->pushDeprecateWarningToLog(
  344. get_called_class() . '::buildSortingSelectSQL()',
  345. 'EntryQueryFieldAdapter::sort()'
  346. );
  347. }
  348. return null;
  349. }
  350. /*-------------------------------------------------------------------------
  351. Grouping:
  352. -------------------------------------------------------------------------*/
  353. public function groupRecords($records)
  354. {
  355. if (!is_array($records) || empty($records)) {
  356. return;
  357. }
  358. $groups = array($this->get('element_name') => array());
  359. foreach ($records as $r) {
  360. $data = $r->getData($this->get('id'));
  361. $value = General::sanitize($data['value']);
  362. if (!isset($groups[$this->get('element_name')][$data['handle']])) {
  363. $groups[$this->get('element_name')][$data['handle']] = array(
  364. 'attr' => array('handle' => $data['handle'], 'value' => $value),
  365. 'records' => array(),
  366. 'groups' => array()
  367. );
  368. }
  369. $groups[$this->get('element_name')][$data['handle']]['records'][] = $r;
  370. }
  371. return $groups;
  372. }
  373. }