PageRenderTime 60ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/_backkup/Matrix2.2.4/ee1/fieldtypes/matrix/ft.matrix.php

https://bitbucket.org/sims/heartbeets
PHP | 2366 lines | 1453 code | 510 blank | 403 comment | 245 complexity | 9c24bc1a6bbb390067f8ac5d8f1cc2d2 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php if (! defined('EXT')) exit('Invalid file request');
  2. /**
  3. * Matrix Fieldtype Class for EE1
  4. *
  5. * @package Matrix
  6. * @author Brandon Kelly <brandon@pixelandtonic.com>
  7. * @copyright Copyright (c) 2011 Pixel & Tonic, Inc
  8. */
  9. class Matrix_ft extends Fieldframe_Fieldtype {
  10. var $info = array(
  11. 'name' => 'Matrix',
  12. 'version' => '2.2.4',
  13. 'desc' => 'A customizable, expandable, and sortable table field',
  14. 'docs_url' => 'http://pixelandtonic.com/ffmatrix/docs',
  15. 'versions_xml_url' => 'http://pixelandtonic.com/ee/versions.xml'
  16. );
  17. var $requires = array(
  18. 'ff' => '1.4.3'
  19. );
  20. var $hooks = array(
  21. 'delete_entries_loop'
  22. );
  23. var $default_site_settings = array(
  24. 'license_key' => ''
  25. );
  26. var $default_field_settings = array(
  27. 'min_rows' => '0',
  28. 'max_rows' => '',
  29. 'col_ids' => array()
  30. );
  31. var $default_tag_params = array(
  32. 'dynamic_parameters' => '',
  33. 'row_id' => '',
  34. 'fixed_order' => '',
  35. 'orderby' => '',
  36. 'sort' => 'asc',
  37. 'offset' => '',
  38. 'limit' => '',
  39. 'backspace' => ''
  40. );
  41. var $postpone_saves = TRUE;
  42. /**
  43. * Fieldtype Constructor
  44. */
  45. function __construct()
  46. {
  47. global $FFM;
  48. $FFM = $this;
  49. }
  50. // --------------------------------------------------------------------
  51. /**
  52. * Theme URL
  53. */
  54. private function _theme_url()
  55. {
  56. if (! isset($this->_theme_url))
  57. {
  58. global $PREFS;
  59. $theme_folder_url = $PREFS->ini('theme_folder_url', 1);
  60. $this->_theme_url = $theme_folder_url.'third_party/matrix/';
  61. }
  62. return $this->_theme_url;
  63. }
  64. /**
  65. * Include Theme CSS
  66. */
  67. private function _include_theme_css($file)
  68. {
  69. $this->insert('head', '<link rel="stylesheet" type="text/css" href="'.$this->_theme_url().$file.'?'.$this->info['version'].'" />');
  70. }
  71. /**
  72. * Include Theme JS
  73. */
  74. private function _include_theme_js($file)
  75. {
  76. $this->insert('body', '<script type="text/javascript" src="'.$this->_theme_url().$file.'?'.$this->info['version'].'"></script>');
  77. }
  78. // --------------------------------------------------------------------
  79. /**
  80. * Add column
  81. */
  82. private function _add_col($data)
  83. {
  84. global $DB;
  85. // add the row to exp_matrix_cols
  86. $DB->query($DB->insert_string('exp_matrix_cols', $data));
  87. // get the col_id
  88. $col_id = $DB->insert_id;
  89. // add the column to exp_matrix_data
  90. $DB->query('ALTER TABLE exp_matrix_data ADD col_id_'.$col_id.' TEXT');
  91. return $col_id;
  92. }
  93. // --------------------------------------------------------------------
  94. /**
  95. * Update
  96. */
  97. function update($from)
  98. {
  99. global $DB, $FF;
  100. if ($from === FALSE)
  101. {
  102. // -------------------------------------------
  103. // Create the exp_matrix_cols table
  104. // -------------------------------------------
  105. if (! $DB->table_exists('exp_matrix_cols'))
  106. {
  107. $DB->query("CREATE TABLE exp_matrix_cols (
  108. `col_id` int(6) unsigned auto_increment,
  109. `site_id` int(4) unsigned default '1',
  110. `field_id` int(6) unsigned NULL,
  111. `col_name` varchar(32) NULL,
  112. `col_label` varchar(50) NULL,
  113. `col_instructions` text NULL,
  114. `col_type` varchar(50) default 'text',
  115. `col_required` char(1) default 'n',
  116. `col_search` char(1) default 'n',
  117. `col_order` int(3) unsigned NULL,
  118. `col_width` varchar(4) NULL,
  119. `col_settings` text NULL,
  120. PRIMARY KEY (`col_id`),
  121. KEY (`site_id`),
  122. KEY (`field_id`)
  123. )");
  124. }
  125. // -------------------------------------------
  126. // Create the exp_matrix_data table
  127. // -------------------------------------------
  128. if (! $DB->table_exists('exp_matrix_data'))
  129. {
  130. $DB->query("CREATE TABLE exp_matrix_data (
  131. `row_id` int(10) unsigned auto_increment,
  132. `site_id` int(4) unsigned default '1',
  133. `entry_id` int(10) unsigned NULL,
  134. `field_id` int(6) unsigned NULL,
  135. `row_order` int(4) unsigned NULL,
  136. PRIMARY KEY (`row_id`),
  137. KEY (`site_id`),
  138. KEY (`entry_id`),
  139. KEY (`row_order`)
  140. )");
  141. }
  142. // -------------------------------------------
  143. // FF Matrix Conversion
  144. // -------------------------------------------
  145. $ff_matrix = $DB->query('SELECT fieldtype_id, version FROM exp_ff_fieldtypes WHERE class = "ff_matrix"');
  146. if ($ff_matrix->num_rows)
  147. {
  148. // uninstall the old fieldtype
  149. $DB->query('DELETE FROM exp_ff_fieldtypes WHERE class = "ff_matrix"');
  150. // were there any FF Matrix fields?
  151. $fields = $DB->query('SELECT field_id, site_id, field_search, ff_settings FROM exp_weblog_fields WHERE field_type = "ftype_id_'.$ff_matrix->row['fieldtype_id'].'"');
  152. foreach ($fields->result as $field)
  153. {
  154. $settings = $FF->_unserialize($field['ff_settings']);
  155. $settings['col_ids'] = array();
  156. if (isset($settings['cols']))
  157. {
  158. if ($settings['cols'])
  159. {
  160. // -------------------------------------------
  161. // Add the rows to exp_matrix_cols
  162. // -------------------------------------------
  163. $col_ids_by_key = array();
  164. foreach ($settings['cols'] as $col_key => $col)
  165. {
  166. $col_type = $col['type'];
  167. $col_settings = isset($col['settings']) ? $col['settings'] : array();
  168. switch ($col_type)
  169. {
  170. case 'ff_matrix_select':
  171. $col_type = 'ff_select';
  172. break;
  173. case 'ff_matrix_text':
  174. case 'ff_matrix_textarea':
  175. $col_settings['multiline'] = ($col_type == 'ff_matrix_text' ? 'n' : 'y');
  176. $col_type = 'text';
  177. break;
  178. case 'ff_matrix_date':
  179. $col_type = 'date';
  180. break;
  181. }
  182. $col_id = $this->_add_col(array(
  183. 'site_id' => $field['site_id'],
  184. 'field_id' => $field['field_id'],
  185. 'col_name' => $col['name'],
  186. 'col_label' => $col['label'],
  187. 'col_type' => $col_type,
  188. 'col_search' => $field['field_search'],
  189. 'col_order' => $col_key,
  190. 'col_settings' => base64_encode(serialize($col_settings))
  191. ));
  192. $settings['col_ids'][] = $col_id;
  193. // map the col_id to the col_key for later
  194. $col_ids_by_key[$col_key] = $col_id;
  195. }
  196. // -------------------------------------------
  197. // Move the field data into exp_matrix_data
  198. // -------------------------------------------
  199. $field_id = 'field_id_'.$field['field_id'];
  200. $entries = $DB->query('SELECT entry_id, '.$field_id.' FROM exp_weblog_data WHERE '.$field_id.' != ""');
  201. foreach ($entries->result as $entry)
  202. {
  203. // unserialize the data
  204. $old_data = $FF->_unserialize($entry[$field_id]);
  205. foreach ($old_data as $row_count => $row)
  206. {
  207. $data = array(
  208. 'site_id' => $field['site_id'],
  209. 'entry_id' => $entry['entry_id'],
  210. 'field_id' => $field['field_id'],
  211. 'row_order' => $row_count+1
  212. );
  213. foreach ($row as $col_key => $cell_data)
  214. {
  215. // does this col exist?
  216. if (! isset($col_ids_by_key[$col_key])) continue;
  217. // get the col_id
  218. $col_id = $col_ids_by_key[$col_key];
  219. // serialize the cell data if necessary
  220. if (is_array($cell_data))
  221. {
  222. $cell_data = $FF->_serialize($cell_data);
  223. }
  224. // queue it up
  225. $data['col_id_'.$col_id] = $cell_data;
  226. }
  227. // add the row to exp_matrix_data
  228. $DB->query($DB->insert_string('exp_matrix_data', $data));
  229. }
  230. // clear out the old field data from exp_weblog_data
  231. $new_data = $this->_flatten_data($old_data);
  232. $DB->query($DB->update_string('exp_weblog_data', array($field_id => $new_data), 'entry_id = '.$entry['entry_id']));
  233. }
  234. }
  235. // remove 'cols' from field settings
  236. unset($settings['cols']);
  237. }
  238. // -------------------------------------------
  239. // Update the field
  240. // -------------------------------------------
  241. $settings = $FF->_serialize($settings);
  242. // save them back to the DB
  243. $DB->query($DB->update_string('exp_weblog_fields', array(
  244. 'field_type' => 'ftype_id_'.$this->_fieldtype_id,
  245. 'ff_settings' => $settings
  246. ), 'field_id = '.$field['field_id']));
  247. }
  248. }
  249. }
  250. }
  251. // --------------------------------------------------------------------
  252. /**
  253. * Display Site Settings
  254. */
  255. function display_site_settings()
  256. {
  257. global $DB, $DSP;
  258. $SD = new Fieldframe_SettingsDisplay();
  259. $r = $SD->block()
  260. . $SD->row(array(
  261. $SD->label('license_key'),
  262. $SD->text('license_key', $this->site_settings['license_key'])
  263. ));
  264. $fields_q = $DB->query('SELECT f.field_id, f.field_label, g.group_name
  265. FROM exp_weblog_fields AS f, exp_field_groups AS g
  266. WHERE f.field_type = "data_matrix"
  267. AND f.group_id = g.group_id
  268. ORDER BY g.group_name, f.field_order, f.field_label');
  269. if ($fields_q->num_rows)
  270. {
  271. $convert_r = '';
  272. $last_group_name = '';
  273. foreach ($fields_q->result as $row)
  274. {
  275. if ($row['group_name'] != $last_group_name)
  276. {
  277. $convert_r .= $DSP->qdiv('defaultBold', $row['group_name']);
  278. $last_group_name = $row['group_name'];
  279. }
  280. $convert_r .= '<label>'
  281. . $DSP->input_checkbox('convert[]', $row['field_id'])
  282. . $row['field_label']
  283. . '</label>'
  284. . '<br>';
  285. }
  286. $r .= $SD->row(array(
  287. $SD->label('convert_label', 'convert_desc'),
  288. $convert_r
  289. ));
  290. }
  291. $r .= $SD->block_c();
  292. return $r;
  293. }
  294. // --------------------------------------------------------------------
  295. /**
  296. * Save Site Settings
  297. */
  298. function save_site_settings($site_settings)
  299. {
  300. global $DB, $FF, $LANG, $REGX;
  301. if (isset($site_settings['convert']))
  302. {
  303. $setting_name_maps = array(
  304. 'short_name' => 'col_name',
  305. 'title' => 'col_label'
  306. );
  307. $cell_type_maps = array(
  308. 'text' => 'ff_matrix_text',
  309. 'textarea' => 'ff_matrix_textarea',
  310. 'select' => 'ff_matrix_select',
  311. 'date' => 'ff_matrix_date',
  312. 'checkbox' => 'ff_checkbox'
  313. );
  314. $fields = $DB->query('SELECT field_id, site_id, field_search, lg_field_conf FROM exp_weblog_fields WHERE field_id IN ('.implode(',', $site_settings['convert']).')');
  315. $sql = array();
  316. foreach ($fields->result as $field)
  317. {
  318. $field_data = array(
  319. 'field_type' => 'ftype_id_'.$this->_fieldtype_id
  320. );
  321. // get the conf string
  322. if (($old_conf = @unserialize($field['lg_field_conf'])) !== FALSE)
  323. {
  324. $conf = (is_array($old_conf) && isset($old_conf['string'])) ? $old_conf['string'] : '';
  325. }
  326. else
  327. {
  328. $conf = $field['lg_field_conf'];
  329. }
  330. // parse the conf string
  331. $field_settings = array(
  332. 'col_ids' => array()
  333. );
  334. $col_ids_by_name = array();
  335. foreach (preg_split('/[\r\n]{2,}/', trim($conf)) as $col_key => $col)
  336. {
  337. // default col settings
  338. $col_settings = array(
  339. 'col_name' => strtolower($LANG->line('cell')).'_'.($col_key+1),
  340. 'col_label' => $LANG->line('cell').' '.($col_key+1),
  341. 'col_type' => 'text'
  342. );
  343. $old = array();
  344. foreach (preg_split('/[\r\n]/', $col) as $line)
  345. {
  346. $parts = explode('=', $line);
  347. $old[$parts[0]] = $parts[1];
  348. }
  349. if (! $old['short_name']) continue;
  350. $col_type = 'text';
  351. $col_settings = array();
  352. if (isset($old['options']))
  353. {
  354. $options = explode('|', $old['options']);
  355. $col_settings['options'] = array();
  356. foreach ($options as $option)
  357. {
  358. $col_settings['options'][$option] = $option;
  359. }
  360. }
  361. if (isset($old['type']))
  362. {
  363. switch ($old['type'])
  364. {
  365. case 'text':
  366. $col_settings = array('multiline' => 'n');
  367. break;
  368. case 'textarea':
  369. $col_settings = array('multiline' => 'y');
  370. break;
  371. case 'select':
  372. $col_type = 'ff_select';
  373. break;
  374. case 'date':
  375. $col_type = 'date';
  376. break;
  377. case 'checkbox':
  378. $col_type = 'checkbox';
  379. break;
  380. }
  381. }
  382. $col_id = $this->_add_col(array(
  383. 'site_id' => $field['site_id'],
  384. 'field_id' => $field['field_id'],
  385. 'col_name' => $old['short_name'],
  386. 'col_label' => (isset($old['title']) ? $old['title'] : $LANG->line('cell').' '.($col_key+1)),
  387. 'col_type' => $col_type,
  388. 'col_search' => $field['field_search'],
  389. 'col_order' => $col_key,
  390. 'col_settings' => $FF->_serialize($col_settings)
  391. ));
  392. $field_settings['col_ids'][] = $col_id;
  393. // map the col_id to the short_name for later
  394. $col_ids_by_name[$old['short_name']] = $col_id;
  395. }
  396. // -------------------------------------------
  397. // Move the field data into exp_matrix_data
  398. // -------------------------------------------
  399. $field_id = 'field_id_'.$field['field_id'];
  400. $entries = $DB->query('SELECT entry_id, '.$field_id.' FROM exp_weblog_data WHERE '.$field_id.' != ""');
  401. foreach ($entries->result as $entry)
  402. {
  403. // unserialize the data
  404. $old_data = @unserialize($entry[$field_id]);
  405. if ($old_data !== FALSE)
  406. {
  407. foreach ($REGX->array_stripslashes($old_data) as $row_count => $row)
  408. {
  409. $data = array(
  410. 'site_id' => $field['site_id'],
  411. 'entry_id' => $entry['entry_id'],
  412. 'field_id' => $field['field_id'],
  413. 'row_order' => $row_count+1
  414. );
  415. $include_row = FALSE;
  416. foreach ($row as $name => $cell_data)
  417. {
  418. // does this col exist?
  419. if (! isset($col_ids_by_name[$name])) continue;
  420. // get the col_id
  421. $col_id = $col_ids_by_name[$name];
  422. // serialize the cell data if necessary
  423. if (is_array($cell_data))
  424. {
  425. $cell_data = $FF->_serialize($cell_data);
  426. }
  427. // queue it up
  428. $data['col_id_'.$col_id] = $cell_data;
  429. if ($cell_data) $include_row = TRUE;
  430. }
  431. if ($include_row)
  432. {
  433. // add the row to exp_matrix_data
  434. $DB->query($DB->insert_string('exp_matrix_data', $data));
  435. }
  436. if ($include_row) $entry_rows[] = $entry_row;
  437. }
  438. // clear out the old field data from exp_weblog_data
  439. $new_data = $this->_flatten_data($old_data);
  440. $DB->query($DB->update_string('exp_weblog_data', array($field_id => $new_data), 'entry_id = '.$entry['entry_id']));
  441. }
  442. }
  443. // -------------------------------------------
  444. // Update the field
  445. // -------------------------------------------
  446. $field_settings = $FF->_serialize($field_settings);
  447. // save them back to the DB
  448. $DB->query($DB->update_string('exp_weblog_fields', array(
  449. 'field_type' => 'ftype_id_'.$this->_fieldtype_id,
  450. 'ff_settings' => $settings
  451. ), 'field_id = '.$field['field_id']));
  452. }
  453. unset($site_settings['convert']);
  454. }
  455. return $site_settings;
  456. }
  457. // --------------------------------------------------------------------
  458. /**
  459. * Get Field Cols
  460. */
  461. private function _get_field_cols($col_ids)
  462. {
  463. global $PREFS, $DB;
  464. $col_ids = array_filter($col_ids);
  465. if (! $col_ids) return FALSE;
  466. // only look up the ones that aren't already cached
  467. $fetch_cols = array();
  468. foreach ($col_ids as $col_id)
  469. {
  470. if (! isset($this->field_cols[$col_id]))
  471. {
  472. $fetch_cols[] = $col_id;
  473. }
  474. }
  475. if ($fetch_cols)
  476. {
  477. $cols = $DB->query('SELECT col_id, col_type, col_label, col_name, col_instructions, col_width, col_required, col_search, col_settings
  478. FROM exp_matrix_cols
  479. WHERE col_id IN ('.implode(',', $fetch_cols).')
  480. ORDER BY col_order');
  481. // unserialize the settings and cache
  482. foreach ($cols->result as $col)
  483. {
  484. $col['col_settings'] = unserialize(base64_decode($col['col_settings']));
  485. if (! is_array($col['col_settings'])) $col['col_settings'] = array();
  486. $this->field_cols[$col['col_id']] = $col;
  487. }
  488. }
  489. // return the cached cols in the requested order
  490. $r = array();
  491. foreach ($col_ids as $col_id)
  492. {
  493. $r[] = $this->field_cols[$col_id];
  494. }
  495. return $r;
  496. }
  497. // --------------------------------------------------------------------
  498. /**
  499. * Get Fieldtypes
  500. *
  501. * @access private
  502. */
  503. function _get_celltypes()
  504. {
  505. global $FF;
  506. if (! isset($this->ftypes))
  507. {
  508. // Add the included celltypes
  509. require_once FT_PATH.'matrix/celltypes/text.php';
  510. require_once FT_PATH.'matrix/celltypes/date.php';
  511. $this->ftypes = array(
  512. 'text' => new Matrix_text(),
  513. 'date' => new Matrix_date()
  514. );
  515. // Get the FF fieldtyes with display_cell
  516. $ftypes = array();
  517. if (! isset($FF->ftypes)) $FF->_get_ftypes();
  518. foreach ($FF->ftypes as $class_name => $ftype)
  519. {
  520. if (method_exists($ftype, 'display_cell'))
  521. {
  522. $ftypes[$class_name] = $ftype;
  523. }
  524. }
  525. $FF->_sort_ftypes($ftypes);
  526. // Combine with the included celltypes
  527. $this->ftypes = array_merge($this->ftypes, $ftypes);
  528. }
  529. return $this->ftypes;
  530. }
  531. // --------------------------------------------------------------------
  532. /**
  533. * Namespace Settings
  534. */
  535. function _namespace_settings(&$settings, $namespace)
  536. {
  537. $settings = preg_replace('/(name=([\'\"]))([^\'"\[\]]+)([^\'"]*)(\2)/i', '$1'.$namespace.'[$3]$4$5', $settings);
  538. }
  539. // --------------------------------------------------------------------
  540. /**
  541. * Celltype Settings HTML
  542. */
  543. private function _celltype_settings_html($name, $namespace, $celltype, $cell_settings = array())
  544. {
  545. global $LANG;
  546. if (method_exists($celltype, 'display_cell_settings'))
  547. {
  548. if (! $celltype->info['no_lang']) $LANG->fetch_language_file($name);
  549. $cell_settings = array_merge((isset($celltype->default_cell_settings) ? $celltype->default_cell_settings : array()), $cell_settings);
  550. $returned = $celltype->display_cell_settings($cell_settings);
  551. // should we create the html for them?
  552. if (is_array($returned))
  553. {
  554. $r = '<table class="matrix-col-settings" cellspacing="0" cellpadding="0" border="0">';
  555. $total_cell_settings = count($returned);
  556. foreach ($returned as $cs_key => $cell_setting)
  557. {
  558. $tr_class = '';
  559. if ($cs_key == 0) $tr_class .= ' matrix-first';
  560. if ($cs_key == $total_cell_settings-1) $tr_class .= ' matrix-last';
  561. $r .= '<tr class="'.$tr_class.'">'
  562. . '<th class="matrix-first">'.$cell_setting[0].'</th>'
  563. . '<td class="matrix-last">'.$cell_setting[1].'</td>'
  564. . '</tr>';
  565. }
  566. $r .= '</table>';
  567. }
  568. else
  569. {
  570. $r = $returned;
  571. }
  572. $this->_namespace_settings($r, $namespace);
  573. }
  574. else
  575. {
  576. $r = '';
  577. }
  578. return $r;
  579. }
  580. // --------------------------------------------------------------------
  581. /**
  582. * Display Field Settings
  583. */
  584. function display_field_settings($field_settings)
  585. {
  586. global $FF, $DSP, $LANG;
  587. // include css and js
  588. $this->_include_theme_css('styles/matrix.css');
  589. $this->_include_theme_js('scripts/matrix.js');
  590. $this->_include_theme_js('scripts/matrix_text.js');
  591. $this->_include_theme_js('scripts/matrix_conf.js');
  592. // language
  593. $this->insert_js('MatrixConf.lang = { '
  594. . 'delete_col: "'.$LANG->line('delete_col').'" };');
  595. // -------------------------------------------
  596. // Get the celltypes
  597. // -------------------------------------------
  598. $celltypes = $this->_get_celltypes();
  599. $celltypes_select_options = array();
  600. $celltypes_js = array();
  601. foreach ($celltypes as $name => $celltype)
  602. {
  603. $celltypes_select_options[$name] = $celltype->info['name'];
  604. // default cell settings
  605. $celltypes_js[$name] = $this->_celltype_settings_html($name, 'ftype[ftype_id_'.$this->_fieldtype_id.'][cols][{COL_ID}][settings]', $celltype, array());
  606. }
  607. // -------------------------------------------
  608. // Get the columns
  609. // -------------------------------------------
  610. // is this an existing Matrix field?
  611. if ($FF->data['field_id'] && $FF->data['field_type'] == "ftype_id_{$this->_fieldtype_id}" && $field_settings['col_ids'])
  612. {
  613. $cols = $this->_get_field_cols($field_settings['col_ids']);
  614. $new = FALSE;
  615. }
  616. if (! isset($cols) || ! $cols)
  617. {
  618. $new = TRUE;
  619. // start off with a couple text cells
  620. $cols = array(
  621. array('col_id' => '0', 'col_label' => 'Cell 1', 'col_instructions' => '', 'col_name' => 'cell_1', 'col_type' => 'text', 'col_width' => '33%', 'col_required' => 'n', 'col_search' => 'n', 'col_settings' => array('maxl' => '', 'multiline' => 'n')),
  622. array('col_id' => '1', 'col_label' => 'Cell 2', 'col_instructions' => '', 'col_name' => 'cell_2', 'col_type' => 'text', 'col_width' => '', 'col_required' => 'n', 'col_search' => 'n', 'col_settings' => array('maxl' => '140', 'multiline' => 'y'))
  623. );
  624. }
  625. $cols_js = array();
  626. foreach ($cols as &$col)
  627. {
  628. $cols_js[] = array(
  629. 'id' => ($new ? 'col_new_' : 'col_id_') . $col['col_id'],
  630. 'type' => $col['col_type']
  631. );
  632. }
  633. $SD = new Fieldframe_SettingsDisplay();
  634. // -------------------------------------------
  635. // Minimum Rows
  636. // -------------------------------------------
  637. $r[] = array(
  638. $SD->label('min_rows'),
  639. $SD->text('min_rows', $field_settings['min_rows'], array('width' => '3em'))
  640. );
  641. // -------------------------------------------
  642. // Maximum Rows
  643. // -------------------------------------------
  644. $r[] = array(
  645. $SD->label('max_rows'),
  646. $SD->text('max_rows', $field_settings['max_rows'], array('width' => '3em'))
  647. );
  648. // -------------------------------------------
  649. // Matrix Configuration
  650. // -------------------------------------------
  651. $total_cols = count($cols);
  652. $table = '<div id="matrix-conf-container" style="margin-left: -6px;"><div id="matrix-conf">'
  653. . '<table class="matrix matrix-conf" cellspacing="0" cellpadding="0" border="0" style="background: #ecf1f4;">'
  654. . '<thead class="matrix">'
  655. . '<tr class="matrix matrix-first">'
  656. . '<td class="matrix-breakleft"></td>';
  657. // -------------------------------------------
  658. // Labels
  659. // -------------------------------------------
  660. foreach ($cols as $col_index => &$col)
  661. {
  662. $col_id = $new ? 'col_new_'.$col_index : 'col_id_'.$col['col_id'];
  663. $class = 'matrix';
  664. if ($col_index == 0) $class .= ' matrix-first';
  665. if ($col_index == $total_cols - 1) $class .= ' matrix-last';
  666. $table .= '<th class="'.$class.'" scope="col">'
  667. . '<input type="hidden" name="col_order[]" value="'.$col_id.'" />'
  668. . '<span>'.$col['col_label'].'</span>'
  669. . '</th>';
  670. }
  671. $table .= '</tr>'
  672. . '<tr class="matrix matrix-last">'
  673. . '<td class="matrix-breakleft"></td>';
  674. // -------------------------------------------
  675. // Instructions
  676. // -------------------------------------------
  677. foreach ($cols as $col_index => &$col)
  678. {
  679. $class = 'matrix';
  680. if ($col_index == 0) $class .= ' matrix-first';
  681. if ($col_index == $total_cols - 1) $class .= ' matrix-last';
  682. $table .= '<td class="'.$class.'">'.($col['col_instructions'] ? nl2br($col['col_instructions']) : '&nbsp;').'</td>';
  683. }
  684. $table .= '</tr>'
  685. . '</thead>'
  686. . '<tbody class="matrix">';
  687. // -------------------------------------------
  688. // Col Settings
  689. // -------------------------------------------
  690. $col_settings = array('type', 'label', 'name', 'instructions', 'width', 'search', 'settings');
  691. $total_settings = count($col_settings);
  692. foreach ($col_settings as $row_index => $col_setting)
  693. {
  694. $tr_class = 'matrix';
  695. if ($row_index == 0) $tr_class .= ' matrix-first';
  696. if ($row_index == $total_settings - 1) $tr_class .= ' matrix-last';
  697. $table .= '<tr class="'.$tr_class.'">'
  698. . '<th class="matrix-breakleft" scope="row">'.$LANG->line('col_'.$col_setting).'</th>';
  699. foreach ($cols as $col_index => &$col)
  700. {
  701. $col_id = $new ? 'col_new_'.$col_index : 'col_id_'.$col['col_id'];
  702. $setting_name = 'cols['.$col_id.']['.$col_setting.']';
  703. $td_class = 'matrix';
  704. if ($col_index == 0) $td_class .= ' matrix-first';
  705. if ($col_index == $total_cols - 1) $td_class .= ' matrix-last';
  706. switch ($col_setting)
  707. {
  708. case 'type':
  709. $shtml = $SD->select($setting_name, $col['col_'.$col_setting], $celltypes_select_options);
  710. break;
  711. case 'name':
  712. case 'width':
  713. $td_class .= ' matrix-text';
  714. $shtml = '<input type="text" class="matrix-textarea" name="'.$setting_name.'" value="'.$col['col_'.$col_setting].'" />';
  715. break;
  716. case 'required':
  717. case 'search':
  718. $shtml = '<input type="checkbox" name="'.$setting_name.'" value="y"'.($col['col_'.$col_setting] == 'y' ? ' checked="checked"' : '').' />';
  719. break;
  720. case 'settings':
  721. $cell_data = is_array($col['col_'.$col_setting]) ? $col['col_'.$col_setting] : array();
  722. if (! ($shtml = $this->_celltype_settings_html($col['col_type'], $setting_name, $celltypes[$col['col_type']], $cell_data)))
  723. {
  724. $td_class .= ' matrix-disabled';
  725. $shtml = '&nbsp;';
  726. }
  727. break;
  728. default:
  729. $td_class .= ' matrix-text';
  730. $shtml = '<textarea class="matrix-textarea" name="'.$setting_name.'" rows="1">'.$col['col_'.$col_setting].'</textarea>';
  731. }
  732. $table .= '<td class="'.$td_class.'">'.$shtml.'</td>';
  733. }
  734. $table .= '</tr>';
  735. }
  736. // -------------------------------------------
  737. // Delete Row buttons
  738. // -------------------------------------------
  739. $table .= '<tr>'
  740. . '<td class="matrix-breakleft"></td>';
  741. foreach ($cols as &$col)
  742. {
  743. $table .= '<td class="matrix-breakdown"><a class="matrix-btn" title="'.$LANG->line('delete_col').'"></a></td>';
  744. }
  745. $table .= '</tr>'
  746. . '</tbody>'
  747. . '</table>'
  748. . '<a class="matrix-btn matrix-add" title="'.$LANG->line('add_col').'"></a>'
  749. . '</div></div>';
  750. $r[] = array(
  751. $SD->label('matrix_configuration')
  752. . $table
  753. );
  754. // -------------------------------------------
  755. // Initialize the configurator js
  756. // -------------------------------------------
  757. $namespace = 'ftype[ftype_id_'.$this->_fieldtype_id.']';
  758. // add json lib if < PHP 5.2
  759. require_once FT_PATH.'matrix/includes/jsonwrapper/jsonwrapper.php';
  760. $js = 'MatrixConf.EE1 = true;' . NL
  761. . 'var matrixConf = new MatrixConf("'.$namespace.'", '.json_encode($celltypes_js).', '.json_encode($cols_js).', '.json_encode($col_settings).');';
  762. if ($new) $js .= NL.'matrixConf.totalNewCols = 2;';
  763. $this->insert_js($js);
  764. return array('rows' => $r);
  765. }
  766. // --------------------------------------------------------------------
  767. /**
  768. * Save Field Settings
  769. */
  770. function save_field_settings($post)
  771. {
  772. global $DB, $PREFS;
  773. $celltypes = $this->_get_celltypes();
  774. // -------------------------------------------
  775. // Delete any removed columns
  776. // -------------------------------------------
  777. if (isset($post['deleted_cols']))
  778. {
  779. foreach ($post['deleted_cols'] as $col_id)
  780. {
  781. $col_id = substr($col_id, 7);
  782. // delete the rows from exp_matrix_cols
  783. $DB->query('DELETE FROM exp_matrix_cols WHERE col_id = '.$col_id);
  784. // delete the actual column from exp_matrix_data
  785. $DB->query('ALTER TABLE exp_matrix_data DROP COLUMN `col_id_'.$col_id.'`');
  786. }
  787. }
  788. // -------------------------------------------
  789. // Add/update columns
  790. // -------------------------------------------
  791. $settings = array(
  792. 'min_rows' => (isset($post['min_rows']) && $post['min_rows'] ? $post['min_rows'] : '0'),
  793. 'max_rows' => (isset($post['max_rows']) && $post['max_rows'] ? $post['max_rows'] : ''),
  794. 'col_ids' => array()
  795. );
  796. $matrix_data_columns = array();
  797. foreach ($post['col_order'] as $col_order => $col_id)
  798. {
  799. $col = $post['cols'][$col_id];
  800. $cell_settings = isset($col['settings']) ? $col['settings'] : array();
  801. // give the celltype a chance to override
  802. $celltype = $celltypes[$col['type']];
  803. if (method_exists($celltype, 'save_cell_settings'))
  804. {
  805. $cell_settings = $celltype->save_cell_settings($cell_settings);
  806. }
  807. $col_data = array(
  808. 'col_name' => $col['name'],
  809. 'col_label' => str_replace('$', '&#36;', $col['label']),
  810. 'col_instructions' => str_replace('$', '&#36;', $col['instructions']),
  811. 'col_type' => $col['type'],
  812. 'col_required' => (isset($col['required']) && $col['required'] ? 'y' : 'n'),
  813. 'col_search' => (isset($col['search']) && $col['search'] ? 'y' : 'n'),
  814. 'col_width' => $col['width'],
  815. 'col_order' => $col_order,
  816. 'col_settings' => base64_encode(serialize($cell_settings))
  817. );
  818. $new = (substr($col_id, 0, 8) == 'col_new_');
  819. if ($new)
  820. {
  821. $col_data['site_id'] = $PREFS->ini('site_id');
  822. // insert the column
  823. $col_id = $this->_add_col($col_data);
  824. }
  825. else
  826. {
  827. $col_id = substr($col_id, 7);
  828. // just update the existing row
  829. $DB->query($DB->update_string('exp_matrix_cols', $col_data, 'col_id = '.$col_id));
  830. }
  831. // add the col_id to the field settings
  832. // - it's unfortunate that we can't just place the field_id in the matrix_cols
  833. // data, but alas, the future field_id is unknowable on new fields
  834. $settings['col_ids'][] = $col_id;
  835. }
  836. return $settings;
  837. }
  838. // --------------------------------------------------------------------
  839. /**
  840. * Display Field
  841. */
  842. function display_field($field_name, $field_data, $field_settings)
  843. {
  844. global $DB, $PREFS, $FF, $IN, $LANG;
  845. // -------------------------------------------
  846. // Include dependencies
  847. // - this needs to happen *before* we load the celltypes,
  848. // in case the celltypes are loading their own JS
  849. // -------------------------------------------
  850. if (! isset($this->included_dependencies))
  851. {
  852. // load the language file
  853. $LANG->fetch_language_file('matrix');
  854. // include css and js
  855. $this->_include_theme_css('styles/matrix.css');
  856. $this->_include_theme_js('scripts/matrix.js');
  857. // menu language
  858. $this->insert_js('Matrix.lang = { '
  859. . 'options: "'.$LANG->line('options').'", '
  860. . 'add_row_above: "'.$LANG->line('add_row_above').'", '
  861. . 'add_row_below: "'.$LANG->line('add_row_below').'", '
  862. . 'delete_row: "'.$LANG->line('delete_row').'" };');
  863. $this->included_dependencies = TRUE;
  864. }
  865. // -------------------------------------------
  866. // Initialize the field
  867. // -------------------------------------------
  868. $field_id = isset($FF->field_id) ? $FF->field_id : $FF->row['field_id'];
  869. $entry_id = isset($FF->row['entry_id']) ? $FF->row['entry_id'] : $IN->GBL('entry_id');
  870. $celltypes = $this->_get_celltypes();
  871. $min_rows = isset($field_settings['min_rows']) ? (int) $field_settings['min_rows'] : 0;
  872. $max_rows = isset($field_settings['max_rows']) ? (int) $field_settings['max_rows'] : 0;
  873. // default $min_rows to 1 if the field is required
  874. if (! $min_rows && $FF->row['field_required'] == 'y') $min_rows = 1;
  875. // single-row mode?
  876. $single_row_mode = ($min_rows == 1 && $max_rows == 1);
  877. $col_ids = isset($field_settings['col_ids']) ? $field_settings['col_ids'] : FALSE;
  878. if (! $col_ids) return;
  879. $cols = $this->_get_field_cols($col_ids);
  880. $total_cols = count($cols);
  881. if (! $total_cols) return;
  882. $col_settings = array();
  883. $select_col_ids = '';
  884. $show_instructions = FALSE;
  885. $cols_js = array();
  886. foreach ($cols as &$col)
  887. {
  888. // index the col by ID
  889. $select_col_ids .= ', col_id_'.$col['col_id'];
  890. // show instructions?
  891. if ($col['col_instructions']) $show_instructions = TRUE;
  892. // active cell type?
  893. if (! isset($celltypes[$col['col_type']]))
  894. {
  895. $col['col_type'] = 'text';
  896. }
  897. $celltype = $celltypes[$col['col_type']];
  898. // include this->settings in col settings
  899. $col_settings[$col['col_id']] = array_merge(
  900. (isset($celltype->default_cell_settings) ? $celltype->default_cell_settings : array()),
  901. (is_array($col['col_settings']) ? $col['col_settings'] : array())
  902. );
  903. $new_cell_html = $celltype->display_cell('{DEFAULT}', '', $col_settings[$col['col_id']]);
  904. $new_cell_settings = FALSE;
  905. $new_cell_class = FALSE;
  906. if (is_array($new_cell_html))
  907. {
  908. if (isset($new_cell_html['settings']))
  909. {
  910. $new_cell_settings = $new_cell_html['settings'];
  911. }
  912. if (isset($new_cell_html['class']))
  913. {
  914. $new_cell_class = $new_cell_html['class'];
  915. }
  916. $new_cell_html = $new_cell_html['data'];
  917. }
  918. // store the js-relevant stuff in $cols_js
  919. $cols_js[] = array(
  920. 'id' => 'col_id_'.$col['col_id'],
  921. 'name' => $col['col_name'],
  922. 'label' => $col['col_label'],
  923. 'required' => ($col['col_required'] == 'y' ? TRUE : FALSE),
  924. 'settings' => $col['col_settings'],
  925. 'type' => $col['col_type'],
  926. 'newCellHtml' => $new_cell_html,
  927. 'newCellSettings' => $new_cell_settings,
  928. 'newCellClass' => $new_cell_class
  929. );
  930. }
  931. // -------------------------------------------
  932. // Get the data
  933. // -------------------------------------------
  934. $data = array();
  935. // is this an existing entry?
  936. if ($entry_id)
  937. {
  938. $site_id = $PREFS->ini('site_id');
  939. $sql = 'SELECT row_id'.$select_col_ids.' FROM exp_matrix_data
  940. WHERE site_id = '.$site_id.' AND field_id = '.$field_id.' AND entry_id = '.$entry_id.'
  941. ORDER BY row_order';
  942. if ($max_rows)
  943. {
  944. $sql .= ' LIMIT '.$max_rows;
  945. }
  946. $query = $DB->query($sql);
  947. // is this a clone?
  948. $clone = ($IN->GBL('clone') == 'y');
  949. // re-index the query data
  950. foreach ($query->result as $count => $row)
  951. {
  952. $key = $clone ? 'row_new_'.$count : 'row_id_'.$row['row_id'];
  953. $data[$key] = $row;
  954. }
  955. }
  956. // -------------------------------------------
  957. // Reach the Minimum Rows count
  958. // -------------------------------------------
  959. $total_rows = count($data);
  960. if ($total_rows < $min_rows)
  961. {
  962. $extra_rows = $min_rows - $total_rows;
  963. for ($i = 0; $i < $extra_rows; $i++)
  964. {
  965. foreach ($cols as &$col)
  966. {
  967. $data['row_new_'.$i]['col_id_'.$col['col_id']] = '';
  968. }
  969. }
  970. $total_rows = $min_rows;
  971. }
  972. // -------------------------------------------
  973. // Table Head
  974. // -------------------------------------------
  975. $thead = '<thead class="matrix">';
  976. $headings = '';
  977. $instructions = '';
  978. // add left gutters if there can be more than one row
  979. if (! $single_row_mode)
  980. {
  981. $headings .= '<th class="matrix matrix-first matrix-tr-header"></th>';
  982. if ($show_instructions)
  983. {
  984. $instructions .= '<td class="matrix matrix-first matrix-tr-header"></td>';
  985. }
  986. }
  987. // add the labels and instructions
  988. foreach ($cols as $col_index => &$col)
  989. {
  990. $col_count = $col_index + 1;
  991. $class = 'matrix';
  992. if ($single_row_mode && $col_count == 1) $class .= ' matrix-first';
  993. if ($col_count == $total_cols) $class .= ' matrix-last';
  994. $headings .= '<th class="'.$class.'" scope="col" width="'.$col['col_width'].'">'.$col['col_label'].'</th>';
  995. if ($show_instructions)
  996. {
  997. $instructions .= '<td class="'.$class.'">'.nl2br($col['col_instructions']).'</td>';
  998. }
  999. }
  1000. $thead = '<thead class="matrix">'
  1001. . '<tr class="matrix matrix-first'.($show_instructions ? '' : ' matrix-last').'">' . $headings . '</tr>'
  1002. . ($show_instructions ? '<tr class="matrix matrix-last">' . $instructions . '</tr>' : '')
  1003. . '</thead>';
  1004. // -------------------------------------------
  1005. // Table Body
  1006. // -------------------------------------------
  1007. $rows_js = array();
  1008. $tbody = '<tbody class="matrix">';
  1009. $row_count = 0;
  1010. $total_new_rows = 0;
  1011. foreach ($data as $row_id => &$row)
  1012. {
  1013. $row_count ++;
  1014. // new?
  1015. $new = (substr($row_id, 0, 8) == 'row_new_');
  1016. if ($new) $total_new_rows++;
  1017. $row_js = array('id' => $row_id, 'cellSettings' => array());
  1018. $tr_class = 'matrix';
  1019. if ($row_count == 1) $tr_class .= ' matrix-first';
  1020. if ($row_count == $total_rows) $tr_class .= ' matrix-last';
  1021. $tbody .= '<tr class="'.$tr_class.'">';
  1022. // add left heading if there can be more than one row
  1023. if (! $single_row_mode)
  1024. {
  1025. $tbody .= '<th class="matrix matrix-first matrix-tr-header">'
  1026. . '<div><span>'.$row_count.'</span><a title="'.$LANG->line('options').'"></a></div>'
  1027. . '<input type="hidden" name="'.$field_name.'[row_order][]" value="'.$row_id.'" />'
  1028. . '</th>';
  1029. }
  1030. // add the cell data
  1031. foreach ($cols as $col_index => &$col)
  1032. {
  1033. $col_id = 'col_id_'.$col['col_id'];
  1034. $col_count = $col_index + 1;
  1035. $td_class = 'matrix';
  1036. // is this the first data cell?
  1037. if ($col_count == 1)
  1038. {
  1039. // is this also the first cell in the <tr>?
  1040. if ($single_row_mode) $td_class .= ' matrix-first';
  1041. // use .matrix-firstcell for active state
  1042. $td_class .= ' matrix-firstcell';
  1043. }
  1044. if ($col_count == $total_cols) $td_class .= ' matrix-last';
  1045. // get new instance of this celltype
  1046. $celltype = $celltypes[$col['col_type']];
  1047. $cell_name = $field_name.'['.$row_id.']['.$col_id.']';
  1048. $cell_data = $FF->_unserialize($row['col_id_'.$col['col_id']]);
  1049. // get the cell html
  1050. $cell_html = $celltype->display_cell($cell_name, $cell_data, $col_settings[$col['col_id']]);
  1051. // is the celltype sending settings too?
  1052. if (is_array($cell_html))
  1053. {
  1054. if (isset($cell_html['settings']))
  1055. {
  1056. $row_js['cellSettings'][$col_id] = $cell_html['settings'];
  1057. }
  1058. if (isset($cell_html['class']))
  1059. {
  1060. $td_class .= ' '.$cell_html['class'];
  1061. }
  1062. $cell_html = $cell_html['data'];
  1063. }
  1064. $tbody .= '<td class="'.$td_class.'">'.$cell_html.'</td>';
  1065. }
  1066. $tbody .= '</tr>';
  1067. $rows_js[] = $row_js;
  1068. }
  1069. $tbody .= '</tbody>';
  1070. // -------------------------------------------
  1071. // Plug it all together
  1072. // -------------------------------------------
  1073. $r = '<div id="'.$field_name.'" class="matrix" style="margin: 5px 8px 12px 0">'
  1074. . '<table class="matrix'.($data ? '' : ' matrix-nodata').'" cellspacing="0" cellpadding="0" border="0">'
  1075. . $thead
  1076. . $tbody
  1077. . '</table>';
  1078. if ($single_row_mode)
  1079. {
  1080. // no <th>s in the <tbody>, so we need to store the row_order outside of the table
  1081. $r .= '<input type="hidden" name="'.$field_name.'[row_order][]" value="'.$rows_js[0]['id'].'" />';
  1082. }
  1083. else
  1084. {
  1085. // add the '+' button
  1086. $r .= '<a class="matrix-btn matrix-add'.($max_rows && $max_rows == $total_rows ? ' matrix-btn-disabled' : '').'" title="'.$LANG->line('add_row').'"></a>';
  1087. }
  1088. $r .= '</div>';
  1089. // add json lib if < PHP 5.2
  1090. require_once FT_PATH.'matrix/includes/jsonwrapper/jsonwrapper.php';
  1091. $field_label = isset($FF->row['field_label']) ? $FF->row['field_label'] : '';
  1092. // initialize the field js
  1093. $js = 'jQuery(document).ready(function(){'
  1094. . 'var m = new Matrix("'.$field_name . '", '
  1095. . '"' . addslashes($field_label) . '", '
  1096. . json_encode($cols_js) . ', '
  1097. . json_encode($rows_js) . ', '
  1098. . $min_rows . ', '
  1099. . $max_rows
  1100. . ');' . NL
  1101. . 'm.totalNewRows = '.$total_new_rows.';'
  1102. . '})';
  1103. $this->insert_js($js);
  1104. return $r;
  1105. }
  1106. // --------------------------------------------------------------------
  1107. /**
  1108. * Flatten Data
  1109. */
  1110. private function _flatten_data($data)
  1111. {
  1112. $r = array();
  1113. if (is_array($data))
  1114. {
  1115. foreach ($data as $val)
  1116. {
  1117. $r[] = $this->_flatten_data($val);
  1118. }
  1119. }
  1120. else
  1121. {
  1122. $r[] = $data;
  1123. }
  1124. return implode(NL, array_filter($r));
  1125. }
  1126. // --------------------------------------------------------------------
  1127. /**
  1128. * Save Field
  1129. */
  1130. function save_field($data, $field_settings, $entry_id)
  1131. {
  1132. global $DB, $PREFS, $FF, $REGX;
  1133. // -------------------------------------------
  1134. // Get the celltypes and cols
  1135. // -------------------------------------------
  1136. $col_ids = isset($field_settings['col_ids']) ? $field_settings['col_ids'] : FALSE;
  1137. $cols = $this->_get_field_cols($col_ids);
  1138. $celltypes = $this->_get_celltypes();
  1139. // prep the cols
  1140. foreach ($cols as &$col)
  1141. {
  1142. $celltype = $celltypes[$col['col_type']];
  1143. $col['has_save_cell'] = method_exists($celltype, 'save_cell');
  1144. $col['has_post_save_cell'] = method_exists($celltype, 'post_save_cell');
  1145. if ($col['has_save_cell'] || $col['has_post_save_cell'])
  1146. {
  1147. $col['celltype_settings'] = array_merge((isset($celltype->default_cell_settings) ? $celltype->default_cell_settings : array()), $col['col_settings']);
  1148. }
  1149. }
  1150. // -------------------------------------------
  1151. // Delete the deleted rows
  1152. // -------------------------------------------
  1153. if (isset($data['deleted_rows']) && $data['deleted_rows'])
  1154. {
  1155. foreach ($data['deleted_rows'] as $row_name)
  1156. {
  1157. $delete_rows[] = substr($row_name, 7);
  1158. }
  1159. $this->_delete_rows($delete_rows);
  1160. }
  1161. // -------------------------------------------
  1162. // Add/update rows
  1163. // -------------------------------------------
  1164. if (isset($data['row_order']) && $data['row_order'] && $cols)
  1165. {
  1166. $r = '';
  1167. foreach ($data['row_order'] as $row_order => $row_name)
  1168. {
  1169. // get the row data
  1170. $row = isset($data[$row_name]) ? $data[$row_name] : array();
  1171. // is this a new row?
  1172. $new = (substr($row_name, 0, 8) == 'row_new_');
  1173. if (! $new)
  1174. {
  1175. $row_id = substr($row_name, 7);
  1176. }
  1177. // -------------------------------------------
  1178. // Prep the row's DB data
  1179. // -------------------------------------------
  1180. $vanilla_row_data = array();
  1181. $row_data = array(
  1182. 'row_order' => $row_order
  1183. );
  1184. foreach ($cols as &$col)
  1185. {
  1186. $cell_data = isset($row['col_id_'.$col['col_id']]) ? $row['col_id_'.$col['col_id']] : '';
  1187. // give the celltype a chance to do what it wants with it
  1188. if ($col['has_save_cell'])
  1189. {
  1190. $celltype = $celltypes[$col['col_type']];
  1191. // put these vars in place as to not break nGen File Field
  1192. $this->row_count = $row_name;
  1193. $this->col_id = 'col_id_'.$col['col_id'];
  1194. $cell_data = $celltype->save_cell($cell_data, $col['celltype_settings'], $entry_id);
  1195. unset($this->row_count, $this->col_id);
  1196. }
  1197. // save the vanilla cell data for post_save_cell()
  1198. $vanilla_row_data['col_id_'.$col['col_id']] = $cell_data;
  1199. // searchable?
  1200. if ($col['col_search'] == 'y')
  1201. {
  1202. $flattened_cell_data = $this->_flatten_data($cell_data);
  1203. if (strlen($flattened_cell_data))
  1204. {
  1205. $r .= $flattened_cell_data . NL;
  1206. }
  1207. }
  1208. // serialize the cell data if necessary
  1209. if (is_array($cell_data))
  1210. {
  1211. $cell_data = $FF->_serialize($cell_data);
  1212. }
  1213. else if (is_string($cell_data) && $PREFS->ini('auto_convert_high_ascii') == 'y')
  1214. {
  1215. $cell_data = $REGX->ascii_to_entities($cell_data);
  1216. }
  1217. $row_data['col_id_'.$col['col_id']] = $cell_data;
  1218. }
  1219. // -------------------------------------------
  1220. // Save or update the row
  1221. // -------------------------------------------
  1222. if ($new)
  1223. {
  1224. $row_data['site_id'] = $PREFS->ini('site_id');
  1225. $row_data['entry_id'] = $entry_id;
  1226. $row_data['field_id'] = $FF->field_id;
  1227. // insert the row
  1228. $DB->query($DB->insert_string('exp_matrix_data', $row_data));
  1229. // get the new row id
  1230. $row_id = $DB->insert_id;
  1231. }
  1232. else
  1233. {
  1234. // just update the existing row
  1235. $DB->query($DB->update_string('exp_matrix_data', $row_data, 'row_id = '.$row_id));
  1236. }
  1237. // -------------------------------------------
  1238. // post_save_cell()
  1239. // -------------------------------------------
  1240. foreach ($cols as &$col)
  1241. {
  1242. if ($col['has_post_save_cell'])
  1243. {
  1244. $celltype = $celltypes[$col['col_type']];
  1245. $this->col_id = $col['col_id'];
  1246. $this->col_name = 'col_id_'.$col['col_id'];
  1247. $this->row_id = $row_id;
  1248. $this->row_name = $row_name;
  1249. $cell_data = $vanilla_row_data['col_id_'.$col['col_id']];
  1250. $celltype->post_save_cell($cell_data, $col['celltype_settings'], $entry_id, $row_id);
  1251. unset($this->col_id, $this->col_name, $this->row_id, $this->row_name);
  1252. }
  1253. }
  1254. }
  1255. return $r ? $r : '1';
  1256. }
  1257. // no rows, so return blank
  1258. return '';
  1259. }
  1260. // --------------------------------------------------------------------
  1261. /**
  1262. * Delete Rows
  1263. */
  1264. private function _delete_rows($row_ids)
  1265. {
  1266. global $DB;
  1267. // -------------------------------------------
  1268. // Notify the celltypes
  1269. // -------------------------------------------
  1270. $celltypes = $this->_get_celltypes();
  1271. foreach ($celltypes as $name => $celltype)
  1272. {
  1273. if (method_exists($celltype, 'delete_rows'))
  1274. {
  1275. $celltype->delete_rows($row_ids);
  1276. }
  1277. }
  1278. // -------------------------------------------
  1279. // Delete the rows
  1280. // -------------------------------------------
  1281. $DB->query('DELETE FROM exp_matrix_data WHERE row_id IN ('.implode(',', $row_ids).')');
  1282. }
  1283. /**
  1284. * Delete Entries - Loop
  1285. */
  1286. function delete_entries_loop($entry_id, $weblog_id)
  1287. {
  1288. global $DB;
  1289. $rows = $DB->query('SELECT row_id FROM exp_matrix_data WHERE entry_id = '.$entry_id);
  1290. if ($rows->num_rows)
  1291. {
  1292. $row_ids = array();
  1293. foreach ($rows->result as $row)
  1294. {
  1295. $row_ids[] = $row['row_id'];
  1296. }
  1297. $this->_delete_rows($row_ids);
  1298. }
  1299. }
  1300. // --------------------------------------------------------------------
  1301. /**
  1302. * Data Query
  1303. */
  1304. private function _data_query($params, $cols, $select_mode = 'data', $select_aggregate = '')
  1305. {
  1306. global $PREFS, $DB, $FF, $FNS, $EXT;
  1307. if (! $cols) return FALSE;
  1308. // -------------------------------------------
  1309. // What's and Where's
  1310. // -------------------------------------------
  1311. $col_ids_by_name = array();
  1312. $select = 'row_id';
  1313. $where = '';
  1314. $use_where = FALSE;
  1315. foreach ($cols as &$col)
  1316. {
  1317. $col_id = 'col_id_'.$col['col_id'];
  1318. if ($select_mode == 'data') $select .= ', '.$col_id;
  1319. $col_ids_by_name[$col['col_name']] = $col['col_id'];
  1320. if (isset($params['search:'.$col['col_name']]))
  1321. {
  1322. $use_where = TRUE;
  1323. $terms = $params['search:'.$col['col_name']];
  1324. if (strncmp($terms, '=', 1) == 0)
  1325. {
  1326. // -------------------------------------------
  1327. // Exact Match e.g.: search:body="=pickle"
  1328. // -------------------------------------------
  1329. $terms = substr($terms, 1);
  1330. // special handling for IS_EMPTY
  1331. if (strpos($terms, 'IS_EMPTY') !== FALSE)
  1332. {
  1333. $terms = str_replace('IS_EMPTY', '', $terms);
  1334. $add_search = $FNS->sql_andor_string($terms, $col_id);
  1335. // remove the first AND output by $FNS->sql_andor_string() so we can parenthesize this clause
  1336. $add_search = substr($add_search, 3);
  1337. $not = (strncmp($terms, 'not ', 4) == 0);
  1338. $conj = ($add_search != '' && ! $not) ? 'OR' : 'AND';
  1339. if ($not)
  1340. {
  1341. $where .= 'AND ('.$add_search.' '.$conj.' '.$col_id.' != "") ';
  1342. }
  1343. else
  1344. {
  1345. $where .= 'AND ('.$add_search.' '.$conj.' '.$col_id.' = "") ';
  1346. }
  1347. }
  1348. else
  1349. {
  1350. $where .= $FNS->sql_andor_string($terms, $col_id).' ';
  1351. }
  1352. }
  1353. else
  1354. {
  1355. // -------------------------------------------
  1356. // "Contains" e.g.: search:body="pickle"
  1357. // -------------------------------------------
  1358. if (strncmp($terms, 'not ', 4) == 0)
  1359. {
  1360. $terms = substr($terms, 4);
  1361. $like = 'NOT LIKE';
  1362. }
  1363. else
  1364. {
  1365. $like = 'LIKE';
  1366. }
  1367. if (strpos($terms, '&&') !== FALSE)
  1368. {
  1369. $terms = explode('&&', $terms);
  1370. $andor = (strncmp($like, 'NOT', 3) == 0) ? 'OR' : 'AND';
  1371. }
  1372. else
  1373. {
  1374. $terms = explode('|', $terms);
  1375. $andor = (strncmp($like, 'NOT', 3) == 0) ? 'AND' : 'OR';
  1376. }
  1377. $where .= ' AND (';
  1378. foreach ($terms as $term)
  1379. {
  1380. if ($term == 'IS_EMPTY')
  1381. {
  1382. $where .= ' '.$col_id.' '.$like.' "" '.$andor;
  1383. }
  1384. else if (preg_match('/^[<>]=?/', $term, $match)) // less than/greater than
  1385. {
  1386. $term = substr($term, strlen($match[0]));
  1387. $where .= ' '.$col_id.' '.$match[0].' "'.$DB->escape_str($term).'" '.$andor;
  1388. }
  1389. else if (strpos($term, '\W') !== FALSE) // full word only, no partial matches
  1390. {
  1391. $not = ($like == 'LIKE') ? ' ' : ' NOT ';
  1392. // Note: MySQL's nutty POSIX regex word boundary is [[:>:]]
  1393. $term = '([[:<:]]|^)'.preg_quote(str_replace('\W', '', $term)).'([[:>:]]|$)';
  1394. $where .= ' '.$col_id.$not.'REGEXP "'.$DB->escape_str($term).'" '.$andor;
  1395. }
  1396. else
  1397. {
  1398. $where .= ' '.$col_id.' '.$like.' "%'.$DB->escape_like_str($term).'%" '.$andor;
  1399. }
  1400. }
  1401. $where = substr($where, 0, -strlen($andor)).') ';
  1402. }
  1403. }
  1404. }
  1405. // -------------------------------------------
  1406. // Row IDs
  1407. // -------------------------------------------
  1408. if ($fixed_order = (!! $params['fixed_order']))
  1409. {
  1410. $params['row_id'] = $params['fixed_order'];
  1411. }
  1412. if ($params['row_id'])
  1413. {
  1414. $use_where = TRUE;
  1415. if (strncmp($params['row_id'], 'not ', 4) == 0)
  1416. {
  1417. $not = 'NOT ';
  1418. $params['row_id'] = substr($params['row_id'], 4);
  1419. }
  1420. else
  1421. {
  1422. $not = '';
  1423. }
  1424. $row_ids = explode('|', $params['row_id']);
  1425. $where .= ' AND row_id '.$not.'IN (' . implode(',', $row_ids) . ')';
  1426. }
  1427. $sql = 'SELECT '.($select_mode == 'aggregate' ? $select_aggregate.' aggregate' : $select).'
  1428. FROM exp_matrix_data
  1429. WHERE field_id = '.$FF->field_id.'
  1430. AND entry_id = '.$FF->row['entry_id'].'
  1431. '.($use_where ? $where : '');

Large files files are truncated, but you can click here to view the full file