PageRenderTime 63ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/packages/properties/property.class.php

https://bitbucket.org/navigatecms/navigatecms
PHP | 1434 lines | 1084 code | 229 blank | 121 comment | 232 complexity | 1d463d122644586eb2a9a7f6b939dace MD5 | raw file
Possible License(s): GPL-2.0, MIT, LGPL-2.1, BSD-3-Clause, AGPL-3.0, Apache-2.0

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

  1. <?php
  2. require_once(NAVIGATE_PATH.'/lib/packages/webdictionary/webdictionary.class.php');
  3. require_once(NAVIGATE_PATH.'/lib/packages/templates/template.class.php');
  4. class property
  5. {
  6. public $id;
  7. public $website;
  8. public $element;
  9. public $template;
  10. public $name;
  11. public $type;
  12. public $options;
  13. public $dvalue; // default value
  14. public $multilanguage; // "true", "false" or empty
  15. public $helper;
  16. public $width;
  17. public $position;
  18. public $enabled;
  19. // decimal properties extra fields
  20. public $precision;
  21. public $prefix;
  22. public $suffix;
  23. // value
  24. // decimal
  25. // option
  26. // multiple option
  27. // boolean
  28. // text (multilanguage)
  29. // textarea (default multilanguage)
  30. // date
  31. // date & time
  32. // link (default multilanguage)
  33. // image (optional multilanguage)
  34. // file
  35. // color
  36. // comment
  37. // rating
  38. // country
  39. // coordinates
  40. // video
  41. // source code (optional multilanguage)
  42. // rich text area (default multilanguage)
  43. // web user groups
  44. // category (Structure entry)
  45. // categories (Multiple structure entries)
  46. // element (a specific content element)
  47. // elements (a selection of content elements)
  48. // product (not yet!)
  49. public function load($id)
  50. {
  51. global $DB;
  52. global $website;
  53. if($DB->query('
  54. SELECT * FROM nv_properties
  55. WHERE id = '.intval($id).'
  56. AND website = '.$website->id)
  57. )
  58. {
  59. $data = $DB->result();
  60. $this->load_from_resultset($data); // there will be as many entries as languages enabled
  61. }
  62. }
  63. public function load_from_resultset($rs)
  64. {
  65. $main = $rs[0];
  66. $this->id = $main->id;
  67. $this->element = $main->element;
  68. $this->template = $main->template;
  69. $this->name = $main->name;
  70. $this->type = $main->type;
  71. $this->options = mb_unserialize($main->options);
  72. $this->dvalue = $main->dvalue;
  73. $this->multilanguage= $main->multilanguage;
  74. $this->helper = $main->helper;
  75. $this->width = $main->width;
  76. $this->position = $main->position;
  77. $this->enabled = $main->enabled;
  78. // decimal format extra fields
  79. $this->precision = $main->precision;
  80. $this->prefix = $main->prefix;
  81. $this->suffix = $main->suffix;
  82. if($this->type == 'date')
  83. $this->dvalue = core_ts2date($this->dvalue, false);
  84. else if($this->type == 'datetime')
  85. $this->dvalue = core_ts2date($this->dvalue, true);
  86. }
  87. public function load_from_post()
  88. {
  89. $this->element = $_REQUEST['property-element'];
  90. $this->template = $_REQUEST['property-template'];
  91. $this->name = $_REQUEST['property-name'];
  92. $this->type = $_REQUEST['property-type'];
  93. $this->dvalue = $_REQUEST['property-dvalue'];
  94. $this->multilanguage= ($_REQUEST['property-multilanguage']=='1'? 'true' : '');
  95. $this->helper = $_REQUEST['property-helper'];
  96. if(($this->type == 'date' || $this->type == 'datetime') && !empty($this->dvalue))
  97. $this->dvalue = core_date2ts($this->dvalue);
  98. if(empty($this->type))
  99. $this->type = 'value';
  100. if(empty($this->element) || $this->element == 'element')
  101. $this->element = 'item';
  102. if(isset($_REQUEST['property-position']))
  103. $this->position = $_REQUEST['property-position'];
  104. $this->enabled = intval($_REQUEST['property-enabled']);
  105. // parse property options
  106. $this->options = array();
  107. $options = $_REQUEST['property-options'];
  108. $options = explode("\n", $options);
  109. foreach($options as $option)
  110. {
  111. $option = explode('#', $option, 2);
  112. if(empty($option[1])) continue;
  113. $this->options[trim($option[0])] = trim($option[1]);
  114. }
  115. }
  116. public function load_from_theme($theme_option, $value=null, $source='website', $template='', $website_id=null)
  117. {
  118. global $website;
  119. global $theme;
  120. $ws = $website;
  121. $ws_theme = $theme;
  122. if(!empty($website_id) && $website_id!=$website->id)
  123. {
  124. $ws = new website();
  125. $ws->load($website_id);
  126. $ws_theme = new theme();
  127. $ws_theme->load($ws->theme);
  128. }
  129. if(is_string($theme_option))
  130. {
  131. // theme_option as ID, not object
  132. if($source=='website')
  133. {
  134. if(empty($ws_theme->options))
  135. $ws_theme->options = array();
  136. foreach($ws_theme->options as $to)
  137. {
  138. if($to->id==$theme_option || $to->name==$theme_option)
  139. {
  140. $theme_option = $to;
  141. @$theme_option->element = 'website';
  142. break;
  143. }
  144. }
  145. }
  146. else if($source=='template')
  147. {
  148. if(empty($ws_theme->templates))
  149. $ws_theme->templates = array();
  150. foreach($ws_theme->templates as $tt)
  151. {
  152. if($tt->type != $template)
  153. continue;
  154. if(empty($tt->properties))
  155. $tt->properties = array();
  156. foreach($tt->properties as $tp)
  157. {
  158. if($tp->id==$theme_option)
  159. {
  160. $theme_option = $tp;
  161. break;
  162. }
  163. }
  164. }
  165. if(empty($theme_option->element) || $theme_option->element == 'element')
  166. $theme_option->element = 'item';
  167. }
  168. }
  169. $this->id = $theme_option->id;
  170. $this->website = $ws->id;
  171. $this->element = $theme_option->element;
  172. $this->template = '';
  173. $this->name = $theme_option->name;
  174. $this->type = $theme_option->type;
  175. $this->options = (array)$theme_option->options;
  176. $this->dvalue = $theme_option->dvalue; // default value
  177. $this->width = $theme_option->width;
  178. $this->multilanguage = $theme_option->multilanguage;
  179. $this->helper = $theme_option->helper;
  180. $this->function = $theme_option->function;
  181. $this->conditional = $theme_option->conditional;
  182. $this->position = 0;
  183. $this->enabled = 1;
  184. // decimal format extra fields
  185. $this->precision = $theme_option->precision;
  186. $this->prefix = $theme_option->prefix;
  187. $this->suffix = $theme_option->suffix;
  188. if(substr($this->name, 0, 1)=='@') // get translation from theme dictionary
  189. $this->name = $ws_theme->t(substr($this->name, 1));
  190. if(substr($this->helper, 0, 1)=='@')
  191. $this->helper = $ws_theme->t(substr($this->helper, 1));
  192. $this->value = $value;
  193. if(!isset($value) && isset($ws->theme_options->{$this->id}))
  194. $this->value = $ws->theme_options->{$this->id};
  195. if(empty($this->value) && empty($this->id))
  196. $this->value = $this->dvalue;
  197. if(is_object($this->value))
  198. $this->value = (array)$this->value;
  199. }
  200. public function load_from_webuser($property_id, $webuser_id=null)
  201. {
  202. global $website;
  203. global $theme;
  204. global $webuser;
  205. $wu = $webuser;
  206. if(!empty($webuser_id))
  207. {
  208. $wu = new webuser();
  209. $wu->load($webuser_id);
  210. }
  211. $ws = $website;
  212. $ws_theme = $theme;
  213. if($wu->website != $website->id)
  214. {
  215. $ws = new website();
  216. $ws->load($wu->website);
  217. $ws_theme = new theme();
  218. $ws_theme->load($ws->theme);
  219. }
  220. if(empty($ws_theme->webusers['properties']))
  221. $ws_theme->webusers['properties'] = array();
  222. foreach($ws_theme->webusers['properties'] as $to)
  223. {
  224. if($to->id==$property_id || $to->name==$property_id)
  225. {
  226. $webuser_option = $to;
  227. $webuser_option->element = 'webuser';
  228. break;
  229. }
  230. }
  231. $this->id = $webuser_option->id;
  232. $this->website = $ws->id;
  233. $this->element = $webuser_option->element;
  234. $this->template = '';
  235. $this->name = $webuser_option->name;
  236. $this->type = $webuser_option->type;
  237. $this->options = (array)$webuser_option->options;
  238. $this->dvalue = $webuser_option->dvalue; // default value
  239. $this->width = $webuser_option->width;
  240. $this->multilanguage = $webuser_option->multilanguage;
  241. $this->helper = $webuser_option->helper;
  242. $this->function = $webuser_option->function;
  243. $this->conditional = $webuser_option->conditional;
  244. $this->position = 0;
  245. $this->enabled = 1;
  246. // decimal format extra fields
  247. $this->precision = $webuser_option->precision;
  248. $this->prefix = $webuser_option->prefix;
  249. $this->suffix = $webuser_option->suffix;
  250. if(substr($this->name, 0, 1)=='@') // get translation from theme dictionary
  251. $this->name = $ws_theme->t(substr($this->name, 1));
  252. if(substr($this->helper, 0, 1)=='@')
  253. $this->helper = $ws_theme->t(substr($this->helper, 1));
  254. $values = property::load_properties_associative('webuser', '', 'webuser', $wu->id);
  255. $this->value = $values[$this->id];
  256. if(is_null($this->value) && !empty($this->dvalue))
  257. {
  258. $this->value = $this->dvalue;
  259. }
  260. if(is_object($this->value))
  261. $this->value = (array)$this->value;
  262. }
  263. public function load_from_object($object, $value=null, $dictionary=null)
  264. {
  265. global $website;
  266. $this->id = $object->id;
  267. $this->website = $website->id;
  268. $this->element = $object->element;
  269. $this->template = '';
  270. $this->name = $object->name;
  271. $this->type = $object->type;
  272. $this->options = (array)$object->options;
  273. $this->dvalue = $object->dvalue; // default value
  274. $this->multilanguage = $object->multilanguage;
  275. $this->helper = $object->helper;
  276. $this->width = $object->width;
  277. $this->function = $object->function;
  278. $this->position = 0;
  279. $this->enabled = 1;
  280. $this->precision = $object->precision;
  281. $this->prefix = $object->prefix;
  282. $this->suffix = $object->suffix;
  283. if(!empty($dictionary))
  284. $this->name = $dictionary->t($this->name);
  285. $this->value = $value;
  286. if(empty($this->value) && empty($this->id))
  287. $this->value = $this->dvalue;
  288. if(is_object($this->value))
  289. $this->value = (array)$this->value;
  290. // translate option titles (when property type = option)
  291. if(!empty($this->options))
  292. {
  293. $options = array();
  294. foreach($this->options as $key => $value)
  295. {
  296. if(!empty($dictionary))
  297. $value = $dictionary->t($value);
  298. $options[$key] = $value;
  299. }
  300. $this->options = json_decode(json_encode($options));
  301. }
  302. }
  303. public function save()
  304. {
  305. global $DB;
  306. if(!empty($this->id))
  307. return $this->update();
  308. else
  309. return $this->insert();
  310. }
  311. public function delete()
  312. {
  313. global $DB;
  314. global $website;
  315. // remove all old entries
  316. if(!empty($this->id))
  317. {
  318. $DB->execute('
  319. DELETE FROM nv_properties
  320. WHERE id = '.intval($this->id).' AND
  321. website = '.$website->id
  322. );
  323. }
  324. return $DB->get_affected_rows();
  325. }
  326. public function insert()
  327. {
  328. global $DB;
  329. global $website;
  330. $ok = $DB->execute('
  331. INSERT INTO nv_properties
  332. (id, website, element, template, name, type,
  333. options, dvalue, multilanguage, helper, position, enabled)
  334. VALUES
  335. ( 0,
  336. :website,
  337. :element,
  338. :template,
  339. :name,
  340. :type,
  341. :options,
  342. :dvalue,
  343. :multilanguage,
  344. :helper,
  345. :position,
  346. :enabled
  347. )',
  348. array(
  349. ':website' => value_or_default($this->website, $website->id),
  350. ':element' => $this->element,
  351. ':template' => $this->template,
  352. ':name' => $this->name,
  353. ':type' => $this->type,
  354. ':options' => serialize($this->options),
  355. ':dvalue' => value_or_default($this->dvalue, ""),
  356. ':multilanguage' => $this->multilanguage,
  357. ':helper' => value_or_default($this->helper, ''),
  358. ':position' => value_or_default($this->position, 0),
  359. ':enabled' => value_or_default($this->enabled, 0)
  360. )
  361. );
  362. if(!$ok) throw new Exception($DB->get_last_error());
  363. $this->id = $DB->get_last_id();
  364. return true;
  365. }
  366. public function update()
  367. {
  368. global $DB;
  369. global $website;
  370. $ok = $DB->execute('
  371. UPDATE nv_properties
  372. SET
  373. element = :element,
  374. template = :template,
  375. name = :name,
  376. type = :type,
  377. options = :options,
  378. dvalue = :dvalue,
  379. multilanguage = :multilanguage,
  380. helper = :helper,
  381. position = :position,
  382. enabled = :enabled
  383. WHERE id = :id
  384. AND website = :website',
  385. array(
  386. ':element' => $this->element,
  387. ':template' => $this->template,
  388. ':name' => $this->name,
  389. ':type' => $this->type,
  390. ':options' => serialize($this->options),
  391. ':dvalue' => $this->dvalue,
  392. ':multilanguage' => $this->multilanguage,
  393. ':helper' => $this->helper,
  394. ':position' => value_or_default($this->position, 0),
  395. ':enabled' => value_or_default($this->enabled, 0),
  396. ':id' => $this->id,
  397. ':website' => $this->website
  398. )
  399. );
  400. if(!$ok) throw new Exception($DB->get_last_error());
  401. return true;
  402. }
  403. public static function elements($template, $element="", $website_id=null)
  404. {
  405. global $DB;
  406. global $website;
  407. global $theme;
  408. $data = array();
  409. if(empty($website_id))
  410. $website_id = $website->id;
  411. if(is_numeric($template))
  412. {
  413. // properties attached to a custom template (not a theme template)
  414. if(!empty($element))
  415. $element = ' AND element = '.protect($element);
  416. else
  417. $element = ' AND element != "block"';
  418. if($DB->query('
  419. SELECT *
  420. FROM nv_properties
  421. WHERE template = '.protect($template).'
  422. '.$element.'
  423. AND website = '.$website_id.'
  424. ORDER BY position ASC, id ASC'
  425. )
  426. )
  427. {
  428. $data = $DB->result();
  429. }
  430. }
  431. else
  432. {
  433. if($element == 'webuser')
  434. {
  435. // webuser properties (set in theme definition)
  436. $data = $theme->webusers['properties'];
  437. }
  438. else if($element == 'block')
  439. {
  440. // block type properties
  441. for($b=0; $b < count($theme->blocks); $b++)
  442. {
  443. if($theme->blocks[$b]->id == $template)
  444. {
  445. $data = $theme->blocks[$b]->properties;
  446. break;
  447. }
  448. }
  449. }
  450. else if($element == 'block_group_block')
  451. {
  452. // block group blocks properties
  453. for($b=0; $b < count($theme->block_groups); $b++)
  454. {
  455. if($theme->block_groups[$b]->id == $template)
  456. {
  457. $data = array();
  458. foreach($theme->block_groups[$b]->blocks as $bgb)
  459. {
  460. // note: properties in block group blocks can't have the same name
  461. if(isset($bgb->properties))
  462. $data = array_merge($data, $bgb->properties);
  463. }
  464. break;
  465. }
  466. }
  467. }
  468. else if($element == 'comment')
  469. {
  470. // properties of the comments of a certain template type
  471. $theme_template = new template();
  472. if(!empty($website_id))
  473. {
  474. // force loading website information
  475. $ws = new website();
  476. $ws->load($website_id);
  477. $ws_theme = $ws->theme;
  478. }
  479. $theme_template->load_from_theme($template, $ws_theme);
  480. $comments_properties = $theme_template->comments->properties;
  481. if(empty($comments_properties))
  482. $comments_properties = array();
  483. $data = array();
  484. for($p=0; $p < count($comments_properties); $p++)
  485. {
  486. $data[] = $comments_properties[$p];
  487. }
  488. }
  489. else
  490. {
  491. // properties of a theme template
  492. $theme_template = new template();
  493. if(!empty($website_id))
  494. {
  495. // force loading website information
  496. $ws = new website();
  497. $ws->load($website_id);
  498. $ws_theme = $ws->theme;
  499. }
  500. $theme_template->load_from_theme($template, $ws_theme);
  501. $template_properties = $theme_template->properties;
  502. if(empty($template_properties))
  503. $template_properties = array();
  504. $data = array();
  505. for($p=0; $p < count($template_properties); $p++)
  506. {
  507. // if we want all properties, no matter the element assigned or
  508. // if the property is not assigned to an element, we assume "item", or
  509. // if the property is assigned to an element, we check it
  510. // note: in this case, "element" is an alias of "item"
  511. if( empty($element) ||
  512. ($element == 'item' && empty($template_properties[$p]->element)) ||
  513. ($element == 'product' && empty($template_properties[$p]->element)) ||
  514. ($element == 'item' && $template_properties[$p]->element=="element") ||
  515. $template_properties[$p]->element == $element
  516. )
  517. $data[] = $template_properties[$p];
  518. }
  519. }
  520. }
  521. return $data;
  522. }
  523. public static function types()
  524. {
  525. $types = array(
  526. 'value' => t(193, 'Value'),
  527. 'decimal' => t(643, 'Decimal'),
  528. 'boolean' => t(206, 'Boolean'),
  529. 'option' => t(194, 'Option'),
  530. 'moption' => t(211, 'Multiple option'),
  531. 'text' => t(54, 'Text'),
  532. 'textarea' => t(195, 'Textarea'),
  533. 'rich_textarea' => t(488, 'Rich textarea'),
  534. 'date' => t(86, 'Date'),
  535. 'datetime' => t(196, 'Date & time'),
  536. 'link' => t(197, 'Link'),
  537. 'image' => t(157, 'Image'),
  538. 'file' => t(82, 'File'),
  539. 'video' => t(272, 'Video'),
  540. 'color' => t(441, 'Color'),
  541. 'comment' => t(205, 'Comment'),
  542. 'rating' => t(222, 'Rating'),
  543. 'country' => t(224, 'Country'),
  544. 'coordinates' => t(297, 'Coordinates'),
  545. 'product' => t(198, 'Product'),
  546. 'category' => t(78, 'Category'),
  547. 'categories' => t(330, 'Categories'),
  548. 'item' => t(180, 'Item'),
  549. 'source_code' => t(489, 'Source code'),
  550. 'webuser_groups'=> t(512, 'Selected web user groups')
  551. );
  552. return $types;
  553. }
  554. public static function reorder($element, $template, $order, $enableds=NULL)
  555. {
  556. global $DB;
  557. global $website;
  558. $item = explode("#", $order);
  559. for($i=0; $i < count($item); $i++)
  560. {
  561. if(empty($item[$i])) continue;
  562. $enabled = '';
  563. if(is_array($enableds))
  564. {
  565. $enabled = ', enabled = 0 ';
  566. for($e=0; $e < count($enableds); $e++)
  567. {
  568. if($enableds[$e]==$item[$i]) $enabled = ', enabled = 1 ';
  569. }
  570. }
  571. $ok = $DB->execute('UPDATE nv_properties
  572. SET position = '.($i+1).' '.$enabled.'
  573. WHERE id = '.$item[$i].'
  574. AND website = '.$website->id);
  575. if(!$ok) return array("error" => $DB->get_last_error());
  576. }
  577. return true;
  578. }
  579. public static function load_properties_associative($element, $template, $object_type, $object_id)
  580. {
  581. // maybe we have cache of the current website?
  582. global $properties;
  583. if(isset($properties[$object_type.'-'.$object_id]))
  584. $props = $properties[$object_type.'-'.$object_id];
  585. else
  586. $props = property::load_properties($element, $template, $object_type, $object_id);
  587. // now create the associative array by property name => value
  588. $associative_properties = array();
  589. if(!is_array($props)) $props = array();
  590. foreach($props as $property)
  591. {
  592. if(is_numeric($property->id))
  593. $associative_properties[$property->name] = $property->value;
  594. else
  595. $associative_properties[$property->id] = $property->value;
  596. }
  597. return $associative_properties;
  598. }
  599. public static function load_properties($element, $template, $object_type, $object_id, $item_uid=null)
  600. {
  601. global $DB;
  602. global $website;
  603. global $theme;
  604. if($object_type == 'block_group_block')
  605. {
  606. $block = block::block_group_block($template, $object_id);
  607. $e_properties = $block->properties;
  608. // we must find the block group ID to search the assigned property values
  609. // $object_id MUST BE the numeric ID of the block group
  610. if(!empty($template))
  611. {
  612. $block_group_id = $DB->query_single('MAX(id)', 'nv_block_groups', ' code = '.protect($template).' AND website = '.$website->id);
  613. $object_id = $block_group_id;
  614. if(empty($block_group_id))
  615. $object_id = 0;
  616. }
  617. }
  618. else if($object_type == 'extension_block')
  619. {
  620. // in this case, the parameters must match the following:
  621. // $element => (not used)
  622. // $template => type of the block in the extension definition
  623. // $object_type => "extension_block"
  624. // $object_id => type of the block_group (f.e. "sidebar" or the one defined in the theme definition); if null, we have to find the right value
  625. // $item_uid => the unique id assigned to the block in the block_group
  626. // find the extension block definition, to get the list of properties
  627. $extensions_blocks = extension::blocks();
  628. for($eb=0; $eb < count($extensions_blocks); $eb++)
  629. {
  630. if($extensions_blocks[$eb]->id == $template)
  631. {
  632. $e_properties = $extensions_blocks[$eb]->properties;
  633. break;
  634. }
  635. }
  636. if(empty($object_id))
  637. {
  638. // we need to find the block_group ID by checking the block uid
  639. $block_group_id = $DB->query_single('id', 'nv_block_groups', ' blocks LIKE '.protect('%'.$item_uid.'%').' AND website = '.$website->id);
  640. $object_id = $block_group_id;
  641. if(empty($block_group_id))
  642. $object_id = 0;
  643. }
  644. // we must find the REAL numeric block group ID (based on its code) to get the assigned property values
  645. // at the end, $object_id MUST BE the numeric ID of the block group (we have only its codename, not the numeric ID)
  646. else if(!empty($template))
  647. {
  648. $block_group_id = $DB->query_single('MAX(id)', 'nv_block_groups', ' code = '.protect($object_id).' AND website = '.$website->id);
  649. $object_id = $block_group_id;
  650. if(empty($block_group_id))
  651. $object_id = 0;
  652. }
  653. $object_type = "block_group-extension-block";
  654. }
  655. else if($object_type == 'webuser')
  656. {
  657. // the properties are set in the theme definition
  658. $e_properties = $theme->webusers['properties'];
  659. }
  660. else // item, structure, block, comment
  661. {
  662. // load properties associated with the element type
  663. $e_properties = property::elements($template, $object_type);
  664. }
  665. // load the values for multilanguage strings
  666. $dictionary = webdictionary::load_element_strings('property-'.$object_type, $object_id, $item_uid);
  667. // load the assigned (simple) properties values
  668. // check node_uid empty or NULL to mantain compatibility with Navigate CMS < 2.2
  669. $DB->query('
  670. SELECT * FROM nv_properties_items
  671. WHERE element = '.protect($object_type).'
  672. AND node_id = '.protect($object_id).
  673. (empty($item_uid)? '' : ' AND ( node_uid = '.protect($item_uid).' OR node_uid = "" OR node_uid IS NULL )').'
  674. AND website = '.$website->id,
  675. 'array'
  676. );
  677. $values = $DB->result();
  678. if(!is_array($values))
  679. $values = array();
  680. $o_properties = array();
  681. if(!is_array($e_properties))
  682. $e_properties = array();
  683. $p = 0;
  684. foreach($e_properties as $e_property)
  685. {
  686. if(is_object($e_property))
  687. $o_properties[$p] = clone $e_property;
  688. else
  689. $o_properties[$p] = $e_property;
  690. if(isset($o_properties[$p]->dvalue))
  691. $o_properties[$p]->value = $o_properties[$p]->dvalue;
  692. foreach($values as $value)
  693. {
  694. if($value['property_id'] == $o_properties[$p]->id)
  695. {
  696. $o_properties[$p]->value = $value['value'];
  697. if($value['value']=='[dictionary]')
  698. {
  699. $o_properties[$p]->value = array();
  700. foreach($website->languages_list as $lang)
  701. {
  702. $o_properties[$p]->value[$lang] = $dictionary[$lang]['property-'.$o_properties[$p]->id.'-'.$lang];
  703. }
  704. }
  705. }
  706. }
  707. if(substr($o_properties[$p]->name, 0, 1)=='@') // get translation from theme dictionary
  708. $o_properties[$p]->name = $theme->t(substr($o_properties[$p]->name, 1));
  709. if(is_object($o_properties[$p]->value))
  710. $o_properties[$p]->value = (array)$o_properties[$p]->value;
  711. $p++;
  712. }
  713. return $o_properties;
  714. }
  715. // called when using navigate cms
  716. public static function save_properties_from_post($object_type, $object_id, $template=null, $element=null, $object_uid=null)
  717. {
  718. global $DB;
  719. global $website;
  720. global $theme;
  721. $dictionary = array();
  722. // load properties associated with the element type
  723. if($object_type=='block_group_block')
  724. {
  725. $block = block::block_group_block($template, $element);
  726. $properties = $block->properties;
  727. if(!is_numeric($object_id))
  728. {
  729. $block_group_id = $DB->query_single('MAX(id)', 'nv_block_groups', ' code = '.protect($template).' AND website = '.$website->id);
  730. $object_id = $block_group_id;
  731. if(empty($block_group_id))
  732. $object_id = 0;
  733. }
  734. }
  735. else if($object_type=='extension_block')
  736. {
  737. // in this case, the parameters must match the following:
  738. // $element => (not used)
  739. // $template => type of the block in the extension definition
  740. // $object_type => "extension_block"
  741. // $object_id => type of the block_group (f.e. "sidebar" or the one defined in the theme definition)
  742. // $object_uid => the unique id assigned to the block in the block_group
  743. // find the extension block definition, to get the list of properties
  744. $extensions_blocks = extension::blocks();
  745. for($eb=0; $eb < count($extensions_blocks); $eb++)
  746. {
  747. if($extensions_blocks[$eb]->id == $template)
  748. {
  749. $properties = $extensions_blocks[$eb]->properties;
  750. break;
  751. }
  752. }
  753. // we must find the REAL numeric block group ID (based on its code) to get the assigned property values
  754. // $object_id MUST BE the numeric ID of the block group (we have only its codename, not the numeric ID)
  755. if(!empty($template))
  756. {
  757. $block_group_id = $DB->query_single('MAX(id)', 'nv_block_groups', ' code = '.protect($object_id).' AND website = '.$website->id);
  758. $object_id = $block_group_id;
  759. if(empty($block_group_id))
  760. $object_id = 0;
  761. }
  762. $object_type = "block_group-extension-block";
  763. }
  764. else if($object_type == 'webuser')
  765. {
  766. // the properties set in the theme definition
  767. $properties = $theme->webusers['properties'];
  768. }
  769. else
  770. {
  771. if(empty($template)) $template = $_REQUEST['property-template'];
  772. if(empty($element)) $element = $_REQUEST['property-element'];
  773. $properties = property::elements($template, $element);
  774. }
  775. if(!is_array($properties))
  776. $properties = array();
  777. foreach($properties as $property)
  778. {
  779. // ALWAYS SAVE the property value, even if it is empty
  780. $property_value = $_REQUEST['property-'.$property->id];
  781. // multilanguage property?
  782. if(in_array($property->type, array('text', 'textarea', 'link', 'rich_textarea')) || @$property->multilanguage=='true' || @$property->multilanguage===true)
  783. $property_value = '[dictionary]';
  784. // date/datetime property?
  785. if($property->type=='date' || $property->type=='datetime')
  786. $property_value = core_date2ts($_REQUEST['property-'.$property->id]);
  787. if($property->type=='moption' && !empty($_REQUEST['property-'.$property->id]))
  788. $property_value = implode(',', $_REQUEST['property-'.$property->id]);
  789. if($property->type=='coordinates')
  790. $property_value = $_REQUEST['property-'.$property->id.'-latitude'].'#'.$_REQUEST['property-'.$property->id.'-longitude'];
  791. if($property->type=='decimal')
  792. $property_value = core_string2decimal($_REQUEST['property-'.$property->id]);
  793. if($property->type=='webuser_groups' && !empty($_REQUEST['property-'.$property->id]))
  794. $property_value = 'g'.implode(',g', $_REQUEST['property-'.$property->id]);
  795. // boolean (checkbox): if not checked, form does not send the value
  796. if($property->type=='boolean' && !isset($_REQUEST['property-'.$property->id]))
  797. $property_value = 0;
  798. // item (select2): if no selection, the form does not send a value (HTML);
  799. // if we don't set an empty value, Navigate would take that as non-existant field and would set the default value,
  800. // which is different as the user may really want to set "empty" as the value
  801. if(($property->type=='element' || $property->type=='item') && !isset($_REQUEST['property-'.$property->id]))
  802. $property_value = "";
  803. // remove the old property row
  804. $DB->execute('
  805. DELETE
  806. FROM nv_properties_items
  807. WHERE property_id = '.protect($property->id).'
  808. AND element = '.protect($object_type).'
  809. AND node_id = '.protect($object_id).
  810. (empty($object_uid)? '' : ' AND node_uid = '.protect($object_uid)).'
  811. AND website = '.$website->id
  812. );
  813. // now insert the new row
  814. $DB->execute('
  815. INSERT INTO nv_properties_items
  816. (id, website, property_id, element, node_id, node_uid, name, value)
  817. VALUES
  818. ( 0,
  819. :website,
  820. :property_id,
  821. :type,
  822. :object_id,
  823. :object_uid,
  824. :name,
  825. :value
  826. )',
  827. array(
  828. ':website' => $website->id,
  829. ':property_id' => $property->id,
  830. ':type' => $object_type,
  831. ':object_id' => value_or_default($object_id, 0),
  832. ':object_uid' => value_or_default($object_uid, ""),
  833. ':name' => value_or_default($property->name, $property->id),
  834. ':value' => value_or_default($property_value, "")
  835. )
  836. );
  837. // save in the dictionary the multilanguage properties
  838. $default_language = '';
  839. if($property->multilanguage === 'false' || $property->multilanguage === false)
  840. $default_language = $website->languages_list[0];
  841. if(in_array($property->type, array('text', 'textarea', 'rich_textarea')) || @$property->multilanguage=='true' || @$property->multilanguage===true)
  842. {
  843. foreach($website->languages_list as $lang)
  844. {
  845. if(!empty($default_language)) // property is NOT multilanguage, use the first value for all languages
  846. $_REQUEST['property-'.$property->id.'-'.$lang] = $_REQUEST['property-'.$property->id.'-'.$default_language];
  847. $dictionary[$lang]['property-'.$property->id.'-'.$lang] = $_REQUEST['property-'.$property->id.'-'.$lang];
  848. }
  849. }
  850. else if($property->type == 'link')
  851. {
  852. foreach($website->languages_list as $lang)
  853. {
  854. $link = $_REQUEST['property-'.$property->id.'-'.$lang.'-link'].
  855. '##'.$_REQUEST['property-'.$property->id.'-'.$lang.'-title'].
  856. '##'.$_REQUEST['property-'.$property->id.'-'.$lang.'-target'];
  857. $dictionary[$lang]['property-'.$property->id.'-'.$lang] = $link;
  858. if(!empty($default_language)) // property is NOT multilanguage, use the first value for all languages
  859. $dictionary[$lang]['property-'.$property->id.'-'.$lang] = $dictionary[$lang]['property-'.$property->id.'-'.$default_language];
  860. }
  861. }
  862. }
  863. if(!empty($dictionary))
  864. {
  865. $property_element = $_REQUEST['property-element'];
  866. if($object_type=='block_group_block')
  867. $property_element = 'block_group_block';
  868. else if($object_type=='block_group-extension-block')
  869. $property_element = 'block_group-extension-block';
  870. webdictionary::save_element_strings('property-'.$property_element, $object_id, $dictionary, $website->id, $object_uid);
  871. }
  872. return true;
  873. }
  874. // save properties from an associative array (ID => VALUE)
  875. // multilanguage values (ID => array(LANG => VALUE, LANG => VALUE...)
  876. // moption values (ID => array(x,y,z...)
  877. // dates => timestamps
  878. // coordinates (ID => array("latitude" => ..., "longitude" => ...)
  879. // change only the given properties, not the other existing ones
  880. public static function save_properties_from_array($object_type, $object_id, $template, $properties_assoc=array(), $ws=null, $node_uid="")
  881. {
  882. global $DB;
  883. global $website;
  884. global $theme;
  885. if(empty($ws))
  886. $ws = $website;
  887. $dictionary = array();
  888. $property_object_type = $object_type; // object_type: item, structure, block, block_group_block
  889. if($object_type=='block_group_block')
  890. {
  891. // we have to identify the block subtype: block, block_type, block_group_block or extension_block
  892. // so we can get its properties definition
  893. if(!is_numeric($object_id))
  894. {
  895. // assume there can only be one block group of the same type
  896. $block_group_id = $DB->query_single('MAX(id)', 'nv_block_groups', ' code = '.protect($template).' AND website = '.$ws->id);
  897. $object_id = $block_group_id;
  898. if(empty($block_group_id))
  899. $object_id = 0;
  900. }
  901. if(!empty($node_uid))
  902. {
  903. $bg = new block_group();
  904. $bg->load($object_id);
  905. for($b=0; $b < count($bg->blocks); $b++)
  906. {
  907. if($bg->blocks[$b]['uid'] == $node_uid)
  908. {
  909. $block_id = $bg->blocks[$b]['id'];
  910. if($bg->blocks[$b]['type']=='extension')
  911. {
  912. // an extension block
  913. $property_object_type = 'block_group-extension-block';
  914. // load the extension, if installed in this instance
  915. $extension = new extension();
  916. $extension->load($bg->blocks[$b]['extension']);
  917. // find the property declaration in the extension definition
  918. if(isset($extension->definition->blocks))
  919. {
  920. for($eb = 0; $eb < count($extension->definition->blocks); $eb++)
  921. {
  922. if($extension->definition->blocks[$eb]->id == $block_id)
  923. {
  924. $block = $extension->definition->blocks[$eb];
  925. break;
  926. }
  927. }
  928. }
  929. else
  930. {
  931. // ignore this property, extension is not installed or it does not have the requested block definition
  932. continue;
  933. }
  934. }
  935. else
  936. {
  937. // a block group block
  938. $property_object_type = 'block_group_block';
  939. $block = block::block_group_block($template, $block_id);
  940. }
  941. // note: standard blocks don't "embed" their properties in a block group,
  942. // they have their own separate values
  943. break;
  944. }
  945. }
  946. }
  947. else
  948. {
  949. // compatibility with < Navigate 2.1 themes (to be removed)
  950. $properties_names = array_keys($properties_assoc);
  951. $block = block::block_group_block_by_property($properties_names[0]);
  952. }
  953. if(!isset($block->properties) || empty($block->properties))
  954. return false;
  955. $properties = $block->properties;
  956. }
  957. else
  958. {
  959. $properties = property::elements($template, $object_type);
  960. }
  961. if(!is_array($properties))
  962. $properties = array();
  963. foreach($properties as $property)
  964. {
  965. if(!isset($properties_assoc[$property->name]) && !isset($properties_assoc[$property->id]))
  966. continue;
  967. $values_dict = array();
  968. $value = '';
  969. // we try to find the property value by "property name", if empty then we try to find it via "property id"
  970. if(isset($properties_assoc[$property->name]))
  971. $value = $properties_assoc[$property->name];
  972. if(empty($value))
  973. $value = $properties_assoc[$property->id];
  974. // multilanguage property?
  975. if( in_array($property->type, array('text', 'textarea', 'link', 'rich_textarea')) ||
  976. @$property->multilanguage=='true' ||
  977. @$property->multilanguage===true
  978. )
  979. {
  980. if(isset($properties_assoc[$property->name]))
  981. $values_dict = $properties_assoc[$property->name];
  982. if(empty($values_dict))
  983. $values_dict = $properties_assoc[$property->id];
  984. $value = '[dictionary]';
  985. }
  986. if($property->type=='coordinates')
  987. {
  988. if(is_array($value))
  989. $value = $value['latitude'].'#'.$value['longitude'];
  990. // if it isn't an array, then we suppose it already has the right format
  991. }
  992. // property->type "decimal"; we don't need to reconvert, it should already be in the right format
  993. // (no thousands separator, dot as decimal separator)
  994. if($property->type=='webuser_groups' && !empty($value))
  995. $value = 'g'.implode(',g', $value);
  996. // boolean (checkbox): if not checked, form does not send the value
  997. if($property->type=='boolean' && empty($value))
  998. $value = 0;
  999. if(is_null($value))
  1000. $value = ""; // should not be needed because of value_or_default, but doing this here fixes some warnings
  1001. // remove the old property value row
  1002. $DB->execute('
  1003. DELETE FROM nv_properties_items
  1004. WHERE property_id = '.protect($property->id).'
  1005. AND element = '.protect($property_object_type).'
  1006. AND node_id = '.protect($object_id).
  1007. (empty($node_uid)? '' : ' AND node_uid = '.protect($node_uid)).'
  1008. AND website = '.$ws->id
  1009. );
  1010. // now we insert a new row
  1011. $DB->execute('
  1012. INSERT INTO nv_properties_items
  1013. (id, website, property_id, element, node_id, node_uid, name, value)
  1014. VALUES
  1015. ( 0,
  1016. :website,
  1017. :property_id,
  1018. :type,
  1019. :object_id,
  1020. :node_uid,
  1021. :name,
  1022. :value
  1023. )',
  1024. array(
  1025. ':website' => $ws->id,
  1026. ':property_id' => $property->id,
  1027. ':type' => $property_object_type,
  1028. ':object_id' => value_or_default($object_id, 0),
  1029. ':node_uid' => value_or_default($node_uid, ""),
  1030. ':name' => $property->name,
  1031. ':value' => value_or_default($value, "")
  1032. )
  1033. );
  1034. // $error = $DB->get_last_error();
  1035. // set the dictionary for the multilanguage properties
  1036. $default_language = '';
  1037. if(isset($property->multilanguage) && ($property->multilanguage === 'false' || $property->multilanguage === false))
  1038. $default_language = $ws->languages_list[0];
  1039. if(in_array($property->type, array('text', 'textarea', 'rich_textarea', 'link')) || @$property->multilanguage=='true' || @$property->multilanguage===true)
  1040. {
  1041. foreach($ws->languages_list as $lang)
  1042. {
  1043. if(!empty($default_language)) // property is NOT multilanguage, use the first value for all languages
  1044. $dictionary[$lang]['property-'.$property->id.'-'.$lang] = $values_dict[$default_language];
  1045. else
  1046. $dictionary[$lang]['property-'.$property->id.'-'.$lang] = $values_dict[$lang];
  1047. }
  1048. }
  1049. }
  1050. if(!empty($dictionary))
  1051. webdictionary::save_element_strings('property-'.$property_object_type, $object_id, $dictionary, $ws->id, $node_uid);
  1052. return true;
  1053. }
  1054. public static function remove_properties($element_type, $element_id, $website_id)
  1055. {
  1056. global $DB;
  1057. global $website;
  1058. if(empty($website_id))
  1059. $website_id = $website->id;
  1060. webdictionary::save_element_strings('property-'.$element_type, $element_id, array());
  1061. $DB->execute('
  1062. DELETE FROM nv_properties_items
  1063. WHERE website = '.$website_id.'
  1064. AND element = '.protect($element_type).'
  1065. AND node_id = '.intval($element_id).'
  1066. ');
  1067. }
  1068. public static function countries($lang="", $alpha3=false)
  1069. {
  1070. global $DB;
  1071. // static function can be called from navigate or from a webget (user then is not a navigate user)
  1072. if(empty($lang))
  1073. {
  1074. global $user;
  1075. $lang = $user->language;
  1076. }
  1077. $code = 'country_code';
  1078. if($alpha3)
  1079. $code = 'alpha3';
  1080. $DB->query('SELECT '.$code.' AS country_code, name
  1081. FROM nv_countries
  1082. WHERE lang = '.protect($lang).'
  1083. ORDER BY name ASC');
  1084. $rs = $DB->result();
  1085. if(empty($rs))
  1086. {
  1087. // failback, load English names
  1088. $DB->query('SELECT '.$code.' AS country_code, name
  1089. FROM nv_countries
  1090. WHERE lang = "en"
  1091. ORDER BY name ASC');
  1092. $rs = $DB->result();
  1093. }
  1094. $out = array();
  1095. foreach($rs as $country)
  1096. {
  1097. $out[$country->country_code] = $country->name;
  1098. }
  1099. return $out;
  1100. }
  1101. public static function languages()
  1102. {
  1103. global $DB;
  1104. $DB->query('SELECT code, name FROM nv_languages');
  1105. $languages_rs = $DB->result();
  1106. $out = array();
  1107. foreach($languages_rs as $lang)
  1108. $out[$lang->code] = $lang->name;
  1109. return $out;
  1110. }
  1111. public static function timezones($country=null, $lang="")
  1112. {
  1113. $out = array();
  1114. if(!empty($country))
  1115. $timezone_identifiers = DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, strtoupper($country));
  1116. else
  1117. $timezone_identifiers = DateTimeZone::listIdentifiers(); // DateTimeZone::ALL
  1118. foreach( $timezone_identifiers as $value )
  1119. {
  1120. //if ( preg_match( '/^(America|Antartica|Arctic|Asia|Atlantic|Europe|Indian|Pacific)\//', $value ) || true )
  1121. //{
  1122. $ex = explode("/", $value, 2); // obtain continent, city
  1123. $this_tz = new DateTimeZone($value);
  1124. $now = new DateTime("now", $this_tz);
  1125. $offset = $this_tz->getOffset($now);
  1126. $utc = $offset / 3600;
  1127. if($utc > 0) $utc = '+'.$utc;
  1128. else if($utc == 0) $utc = '-'.$utc;
  1129. $continent = $ex[0];
  1130. switch($continent)
  1131. {
  1132. case 'Africa':
  1133. $continent = t(284, 'Africa');
  1134. break;
  1135. case 'America':
  1136. $continent = t(310, 'America');
  1137. break;
  1138. case 'Antartica':
  1139. $continent = t(311, 'Antartica');
  1140. break;
  1141. case 'Arctic':
  1142. $continent = t(312, 'Arctic');
  1143. break;
  1144. case 'Asia':
  1145. $continent = t(313, 'Asia');
  1146. break;
  1147. case 'Atlantic':
  1148. $continent = t(314, 'Atlantic');
  1149. break;
  1150. case 'Europe':
  1151. $continent = t(315, 'Europe');
  1152. break;
  1153. case 'Indian':
  1154. $continent = t(316, 'Indian');
  1155. break;
  1156. case 'Pacific':
  1157. $continent = t(317, 'Pacific');
  1158. break;
  1159. default:
  1160. // leave it in english
  1161. }
  1162. $city = str_replace('_', ' ', $ex[1]);
  1163. if(!empty($city))
  1164. $out[$value] = $offset.'#'.'(UTC'.$utc.') '.$continent.'/'.$city;
  1165. else
  1166. $out[$value] = $offset.'#'.'(UTC'.$utc.') '.$value;
  1167. //}
  1168. }
  1169. asort($out, SORT_NUMERIC);
  1170. $rows = array();
  1171. foreach($out as $value => $text)
  1172. {
  1173. $rows[$value] = substr($text, strpos($text, '#')+1);
  1174. }
  1175. return $rows;
  1176. }
  1177. public static function find($type, $property, $value)
  1178. {
  1179. global $DB;
  1180. global $website;
  1181. $DB->query('
  1182. SELECT * FROM nv_properties_items
  1183. WHERE website = '.protect($website->id).'
  1184. AND property_id = '.protect($property).'
  1185. AND value = '.protect($value),
  1186. 'object');
  1187. return $DB->result();
  1188. }
  1189. public function backup($type='json')
  1190. {
  1191. global $DB;
  1192. global $website;
  1193. $out

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