PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/campsite/src/classes/ArticleTypeField.php

https://github.com/joechrysler/Campsite
PHP | 877 lines | 585 code | 114 blank | 178 comment | 144 complexity | 91c26f8eccab17115f980c7db0e9c182 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, LGPL-2.1, Apache-2.0
  1. <?php
  2. /**
  3. * @package Campsite
  4. */
  5. /**
  6. * Includes
  7. */
  8. require_once($GLOBALS['g_campsiteDir'].'/classes/Log.php');
  9. require_once($GLOBALS['g_campsiteDir'].'/classes/Topic.php');
  10. require_once($GLOBALS['g_campsiteDir'].'/classes/CampCacheList.php');
  11. /**
  12. * @package Campsite
  13. */
  14. class ArticleTypeField extends DatabaseObject {
  15. const TYPE_TEXT = 'text';
  16. const TYPE_BODY = 'body';
  17. const TYPE_DATE = 'date';
  18. const TYPE_TOPIC = 'topic';
  19. const TYPE_SWITCH = 'switch';
  20. const TYPE_NUMERIC = 'numeric';
  21. const NUMERIC_DEFAULT_DIGITS = 65;
  22. const NUMERIC_DEFAULT_PRECISION = 2;
  23. var $m_dbTableName = 'ArticleTypeMetadata';
  24. var $m_keyColumnNames = array('type_name', 'field_name');
  25. var $m_columnNames = array(
  26. 'type_name',
  27. 'field_name',
  28. 'field_weight',
  29. 'is_hidden',
  30. 'comments_enabled',
  31. 'fk_phrase_id',
  32. 'field_type',
  33. 'field_type_param',
  34. 'is_content_field');
  35. private $m_rootTopicId = null;
  36. private $m_precision = null;
  37. public function __construct($p_articleTypeName = null, $p_fieldName = null)
  38. {
  39. $this->m_data['type_name'] = $p_articleTypeName;
  40. $this->m_data['field_name'] = $p_fieldName;
  41. if ($this->keyValuesExist()) {
  42. $this->fetch();
  43. }
  44. } // constructor
  45. /**
  46. * Returns the article type name.
  47. *
  48. * @return string
  49. */
  50. public function getArticleType()
  51. {
  52. return $this->m_data['type_name'];
  53. } // fn getArticleType
  54. /**
  55. * Rename the article type field.
  56. *
  57. * @param string p_newName
  58. *
  59. */
  60. public function rename($p_newName)
  61. {
  62. global $g_ado_db;
  63. if (!$this->exists() || !ArticleType::isValidFieldName($p_newName)) {
  64. return 0;
  65. }
  66. $types = self::DatabaseTypes(null, $this->m_precision);
  67. $queryStr = "ALTER TABLE `X". $this->m_data['type_name']."` CHANGE COLUMN `"
  68. . $this->getName() ."` `F$p_newName` ". $types[$this->getType()];
  69. $success = $g_ado_db->Execute($queryStr);
  70. if ($success) {
  71. $fieldName = $this->m_data['field_name'];
  72. $this->setProperty('field_name', $p_newName);
  73. if (function_exists("camp_load_translation_strings")) {
  74. camp_load_translation_strings("api");
  75. }
  76. $logText = getGS('The article type field "$1" has been renamed to "$2".',
  77. $fieldName, $p_newName);
  78. Log::Message($logText, null, 62);
  79. }
  80. } // fn rename
  81. /**
  82. * Fetch a single record from the database for the given key.
  83. *
  84. * @param array $p_recordSet
  85. * If the record has already been fetched and we just need to
  86. * assign the data to the object's internal member variable.
  87. *
  88. * @return boolean
  89. * TRUE on success, FALSE on failure
  90. */
  91. public function fetch($p_recordSet = null)
  92. {
  93. $success = parent::fetch($p_recordSet);
  94. if ($success && $this->getType() == self::TYPE_NUMERIC) {
  95. $params = explode('=', $this->m_data['field_type_param']);
  96. if (isset($params[0]) && $params[0] == 'precision') {
  97. $this->m_precision = (int) $params[1];
  98. }
  99. }
  100. return $success;
  101. }
  102. /**
  103. * Create a column in the table.
  104. * @param string $p_type
  105. * Can be one of: 'text', 'date', 'body', 'switch', 'numeric'.
  106. */
  107. public function create($p_type, array $p_params = array())
  108. {
  109. global $g_ado_db;
  110. $p_type = strtolower($p_type);
  111. $numericPrecision = isset($p_params['precision']) ? $p_params['precision'] : null;
  112. $types = self::DatabaseTypes(null, $numericPrecision);
  113. if ($this->getPrintName() != 'NULL' && !array_key_exists($p_type, $types)) {
  114. return false;
  115. }
  116. if ($p_type == self::TYPE_TOPIC && $this->getPrintName() != 'NULL') {
  117. if (!isset($p_params['root_topic_id']) && !is_numeric($p_params['root_topic_id'])) {
  118. return false;
  119. }
  120. $rootTopicId = (int)$p_params['root_topic_id'];
  121. $queryStr2 = "INSERT INTO TopicFields (ArticleType, FieldName, RootTopicId) "
  122. . "VALUES ('".$g_ado_db->escape($this->m_data['type_name']) . "', '"
  123. . $g_ado_db->escape($this->m_data['field_name']) . "', '$rootTopicId')";
  124. if (!$g_ado_db->Execute($queryStr2)) {
  125. return false;
  126. }
  127. }
  128. if ($this->getPrintName() != 'NULL') {
  129. $queryStr = "ALTER TABLE `X" . $this->m_data['type_name'] . "` ADD COLUMN `"
  130. . $this->getName() . '` ' . $types[$p_type];
  131. $success = $g_ado_db->Execute($queryStr);
  132. }
  133. if ($success || $this->getPrintName() == 'NULL') {
  134. $data = array();
  135. if ($this->getPrintName() != 'NULL') {
  136. if ($p_type == self::TYPE_BODY && isset($p_params['is_content'])) {
  137. $data['is_content_field'] = (int)$p_params['is_content'];
  138. }
  139. if ($p_type == self::TYPE_NUMERIC && isset($p_params['precision'])) {
  140. $data['field_type_param'] = 'precision=' . (int)$p_params['precision'];
  141. }
  142. $data['field_type'] = $p_type;
  143. $data['field_weight'] = $this->getNextOrder();
  144. }
  145. $success = parent::create($data);
  146. }
  147. if ($success) {
  148. if (function_exists("camp_load_translation_strings")) {
  149. camp_load_translation_strings("api");
  150. }
  151. $logtext = getGS('Article type field "$1" created', $this->m_data['field_name']);
  152. Log::Message($logtext, null, 71);
  153. CampCache::singleton()->clear('user');
  154. }
  155. return $success;
  156. } // fn create
  157. /**
  158. * Returns an array of types compatible with the given field type.
  159. * @return array
  160. */
  161. public static function TypesConvertibleTo($p_type)
  162. {
  163. switch ($p_type) {
  164. case self::TYPE_BODY:
  165. return array(self::TYPE_TEXT, self::TYPE_DATE, self::TYPE_TOPIC, self::TYPE_SWITCH, self::TYPE_NUMERIC);
  166. case self::TYPE_TEXT:
  167. return array(self::TYPE_DATE, self::TYPE_TOPIC, self::TYPE_SWITCH, self::TYPE_NUMERIC);
  168. case self::TYPE_DATE:
  169. return array();
  170. case self::TYPE_TOPIC:
  171. return array();
  172. case self::TYPE_SWITCH:
  173. return array();
  174. case self::TYPE_NUMERIC:
  175. return array();
  176. }
  177. return false;
  178. }
  179. public static function TypesConvertibleFrom($p_type)
  180. {
  181. $allTypes = self::DatabaseTypes();
  182. if (!array_key_exists($p_type, $allTypes)) {
  183. return false;
  184. }
  185. $convertibleFromTypes = array();
  186. foreach ($allTypes as $typeName=>$sqlDesc) {
  187. if (array_search($p_type, self::TypesConvertibleTo($typeName)) !== false) {
  188. $convertibleFromTypes[] = $typeName;
  189. }
  190. }
  191. return $convertibleFromTypes;
  192. }
  193. public function getConvertibleFromTypes()
  194. {
  195. return self::TypesConvertibleTo($this->getType());
  196. }
  197. public function getConvertibleToTypes()
  198. {
  199. return self::TypesConvertibleFrom($this->getType());
  200. }
  201. /**
  202. * Returns true if the given type can be converted to the current field type.
  203. * @param $p_type
  204. * @return boolean
  205. */
  206. public function isConvertibleFrom($p_type)
  207. {
  208. if (is_object($p_type) && get_class($p_type) == __CLASS__) {
  209. if ($this->getType() == 'topic' && $p_type->getType() == 'topic') {
  210. return $this->getTopicTypeRootElement() == $p_type->getTopicTypeRootElement();
  211. }
  212. $p_type = $p_type->getType();
  213. }
  214. return ($this->getType() == $p_type && $p_type != 'topic')
  215. || array_search($p_type, $this->getConvertibleFromTypes()) !== false;
  216. }
  217. public function isConvertibleTo($p_type)
  218. {
  219. return array_search($p_type, $this->getConvertibleToTypes());
  220. }
  221. /**
  222. * Changes the type of the field
  223. *
  224. * @param string p_type (text|date|body|topic|switch|numeric)
  225. */
  226. public function setType($p_type)
  227. {
  228. global $g_ado_db;
  229. $p_type = strtolower($p_type);
  230. $types = self::DatabaseTypes();
  231. if (!array_key_exists($p_type, $types)) {
  232. return false;
  233. }
  234. if ($this->getType() == $p_type) {
  235. return true;
  236. }
  237. if ($this->getType() == self::TYPE_TOPIC) {
  238. $queryStr = "DELETE FROM TopicFields WHERE ArticleType = '"
  239. . $g_ado_db->escape($this->m_data['type_name'])
  240. ."' AND FieldName = '". $g_ado_db->escape($this->m_data['field_name']) ."'";
  241. if (!$g_ado_db->Execute($queryStr)) {
  242. return false;
  243. }
  244. }
  245. $queryStr = "ALTER TABLE `X" . $this->m_data['type_name'] . "` MODIFY `"
  246. . $this->getName() . '` ' . $types[$p_type];
  247. $success = $g_ado_db->Execute($queryStr);
  248. if ($success) {
  249. $this->setProperty('field_type_param', null);
  250. $success = $this->setProperty('field_type', $p_type);
  251. $this->m_rootTopicId = null;
  252. }
  253. if ($success) {
  254. if (function_exists("camp_load_translation_strings")) {
  255. camp_load_translation_strings("api");
  256. }
  257. $logtext = getGS('Article type field "$1" changed', $this->m_data['field_name']);
  258. Log::Message($logtext, null, 71);
  259. }
  260. return $success;
  261. } // fn setType
  262. /**
  263. * Deletes the current article type field.
  264. */
  265. public function delete()
  266. {
  267. global $g_ado_db;
  268. if (!$this->exists()) {
  269. return false;
  270. }
  271. $orders = $this->getOrders();
  272. $translation = new Translation(null, $this->getPhraseId());
  273. $translation->deletePhrase();
  274. if ($this->getPrintName() != 'NULL') {
  275. $queryStr = "ALTER TABLE `X" . $this->m_data['type_name']
  276. . "` DROP COLUMN `" . $this->getName() . "`";
  277. $success = $g_ado_db->Execute($queryStr);
  278. }
  279. if ($success || $this->getPrintName() == 'NULL') {
  280. $myType = $this->getType();
  281. if ($myType == self::TYPE_TOPIC) {
  282. $queryStr = "DELETE FROM TopicFields WHERE ArticleType = '"
  283. . $g_ado_db->escape($this->m_data['type_name']) . "' and FieldName = '"
  284. . $g_ado_db->escape($this->m_data['field_name']) . "'";
  285. $g_ado_db->Execute($queryStr);
  286. $this->m_rootTopicId = null;
  287. }
  288. $fieldName = $this->m_data['field_name'];
  289. $success = parent::delete();
  290. }
  291. // reorder
  292. if ($success) {
  293. $newOrders = array();
  294. foreach ($orders as $k => $v) {
  295. if ($v != $this->m_data['field_name'])
  296. $newOrders[] = $v;
  297. }
  298. $newOrders = array_reverse($newOrders);
  299. $this->setOrders($newOrders);
  300. if (function_exists("camp_load_translation_strings")) {
  301. camp_load_translation_strings("api");
  302. }
  303. $logtext = getGS('Article type field "$1" deleted', $fieldName);
  304. Log::Message($logtext, null, 72);
  305. CampCache::singleton()->clear('user');
  306. }
  307. return $success;
  308. } // fn delete
  309. /**
  310. * @return string
  311. */
  312. public function getName()
  313. {
  314. return 'F'.$this->m_data['field_name'];
  315. } // fn getName
  316. /**
  317. * @return string
  318. */
  319. public function getPrintName()
  320. {
  321. return $this->m_data['field_name'];
  322. } // fn getPrintName
  323. /**
  324. * @return string
  325. */
  326. public function getType()
  327. {
  328. return $this->m_data['field_type'];
  329. } // fn getType
  330. public function getGenericType()
  331. {
  332. switch ($this->getType()) {
  333. case self::TYPE_BODY:
  334. case self::TYPE_TEXT:
  335. return 'string';
  336. case self::TYPE_DATE:
  337. return 'date';
  338. case self::TYPE_NUMERIC:
  339. return 'integer';
  340. case self::TYPE_SWITCH:
  341. return 'switch';
  342. case self::TYPE_TOPIC:
  343. return 'topic';
  344. }
  345. return null;
  346. }
  347. /**
  348. * @return string
  349. */
  350. public function getTopicTypeRootElement()
  351. {
  352. global $g_ado_db;
  353. if ($this->getType() == self::TYPE_TOPIC && is_null($this->m_rootTopicId)) {
  354. $queryStr = "SELECT RootTopicId FROM TopicFields WHERE ArticleType = '"
  355. . $g_ado_db->escape($this->getArticleType()) . "' and FieldName = '"
  356. . $g_ado_db->escape($this->getPrintName()) . "'";
  357. $this->m_rootTopicId = $g_ado_db->GetOne($queryStr);
  358. }
  359. return $this->m_rootTopicId;
  360. }
  361. /**
  362. * Get a human-readable representation of the column type.
  363. * @return string
  364. */
  365. public static function VerboseTypeName($p_typeName, $p_languageId = 1, $p_rootTopicId = null)
  366. {
  367. switch ($p_typeName) {
  368. case self::TYPE_BODY:
  369. return getGS('Multi-line Text with WYSIWYG');
  370. case self::TYPE_TEXT:
  371. return getGS('Single-line Text');
  372. case self::TYPE_DATE:
  373. return getGS('Date');
  374. case self::TYPE_TOPIC:
  375. if (is_null($p_rootTopicId)) {
  376. return getGS('Topic');
  377. }
  378. $topic = new Topic($p_rootTopicId);
  379. $translations = $topic->getTranslations();
  380. if (array_key_exists($p_languageId, $translations)) {
  381. return getGS('Topic') . ' (' . $translations[$p_languageId] . ')';
  382. } elseif ($p_languageId != 1 && array_key_exists(1, $translations)) {
  383. return getGS('Topic') . ' (' . $translations[1] . ')';
  384. } else {
  385. return getGS('Topic') . ' (' . end($translations) . ')';
  386. }
  387. break;
  388. case self::TYPE_SWITCH:
  389. return getGS('Switch');
  390. case self::TYPE_NUMERIC:
  391. return getGS('Numeric');
  392. default:
  393. return getGS("unknown");
  394. }
  395. } // fn VerboseTypeName
  396. public function getVerboseTypeName($p_languageId = 1)
  397. {
  398. $rootTopicId = $this->getType() == self::TYPE_TOPIC ? $this->getTopicTypeRootElement() : null;
  399. return self::VerboseTypeName($this->getType(), $p_languageId, $rootTopicId);
  400. }
  401. /**
  402. * Gets the language code of the current translation language; or none
  403. * if there is no translation.
  404. *
  405. * @param int p_lang
  406. *
  407. * @return string
  408. */
  409. public function getDisplayNameLanguageCode($p_lang = 0)
  410. {
  411. if (!$p_lang) {
  412. $lang = camp_session_get('LoginLanguageId', 1);
  413. } else {
  414. $lang = $p_lang;
  415. }
  416. $languageObj = new Language($lang);
  417. $translations = $this->getTranslations();
  418. if (!isset($translations[$lang])) {
  419. return '';
  420. }
  421. return '('. $languageObj->getCode() .')';
  422. } // fn getDisplayNameLanguageCode
  423. /**
  424. * Gets the translation for a given language; default language is the
  425. * session language. If no translation is set for that language, we
  426. * return the dbTableName.
  427. *
  428. * @param int p_lang
  429. *
  430. * @return string
  431. */
  432. public function getDisplayName($p_lang = 0)
  433. {
  434. if (!$p_lang) {
  435. $lang = camp_session_get('LoginLanguageId', 1);
  436. } else {
  437. $lang = $p_lang;
  438. }
  439. $translations = $this->getTranslations();
  440. if (!isset($translations[$lang])) {
  441. return $this->getPrintName();
  442. }
  443. return $translations[$lang];
  444. } // fn getDisplayName
  445. /**
  446. * Returns the is_hidden status of a field. Returns 'hidden' or 'shown'.
  447. *
  448. * @return string (shown|hidden)
  449. */
  450. public function getStatus()
  451. {
  452. if ($this->m_data['is_hidden']) {
  453. return 'hidden';
  454. } else {
  455. return 'shown';
  456. }
  457. } // fn getStatus
  458. /**
  459. * @param string p_status (hide|show)
  460. */
  461. public function setStatus($p_status)
  462. {
  463. if ($p_status == 'show') {
  464. $hidden = 0;
  465. } elseif ($p_status == 'hide') {
  466. $hidden = 1;
  467. } else {
  468. return null;
  469. }
  470. return $this->setProperty('is_hidden', $hidden);
  471. } // fn setStatus
  472. /**
  473. * Return an associative array of the metadata in ArticleFieldMetadata.
  474. *
  475. * @return array
  476. */
  477. public function getMetadata() {
  478. return $this->m_data;
  479. } // fn getMetadata
  480. /**
  481. * @return -1 OR int
  482. */
  483. public function getPhraseId()
  484. {
  485. if (isset($this->m_data['fk_phrase_id'])) {
  486. return $this->m_data['fk_phrase_id'];
  487. }
  488. return -1;
  489. } // fn getPhraseId()
  490. /**
  491. * Returns an array of translation strings for the field name.
  492. * @return array
  493. */
  494. public function getTranslations()
  495. {
  496. $return = array();
  497. $tmp = Translation::getTranslations($this->getPhraseId());
  498. foreach ($tmp as $k => $v) {
  499. $return[$k] = $v;
  500. }
  501. return $return;
  502. } // fn getTransltions
  503. /**
  504. * Returns true if the current field is hidden.
  505. * @return boolean
  506. */
  507. public function isHidden()
  508. {
  509. return $this->m_data['is_hidden'];
  510. }
  511. /**
  512. * Returns true if the current field is a content field.
  513. * @return boolean
  514. */
  515. public function isContent() {
  516. return $this->m_data['is_content_field'];
  517. }
  518. /**
  519. * Sets the content flag. Returns true on success, false otherwise.
  520. * @param $p_isContent
  521. * @return boolean
  522. */
  523. public function setIsContent($p_isContent)
  524. {
  525. return $this->setProperty('is_content_field', (int)$p_isContent);
  526. }
  527. /**
  528. * Quick lookup to see if the current language is already translated for this article type: used by delete and update in setName
  529. * returns 0 if no translation or the phrase_id if there is one.
  530. *
  531. * @param int p_languageId
  532. *
  533. * @return 0 or phrase id (int)
  534. */
  535. public function translationExists($p_languageId) {
  536. $translation = new Translation($p_languageId, $this->m_data['fk_phrase_id']);
  537. return $translation->exists();
  538. } // fn translationExists
  539. /**
  540. * Set the type name for the given language. A new entry in
  541. * the database will be created if the language did not exist.
  542. *
  543. * @param int $p_languageId
  544. * @param string $p_value
  545. *
  546. * @return boolean
  547. */
  548. public function setName($p_languageId, $p_value)
  549. {
  550. global $g_ado_db;
  551. if (!is_numeric($p_languageId)) {
  552. return false;
  553. }
  554. // if the string is empty, nuke it
  555. if (!is_string($p_value) || $p_value == '') {
  556. if ($phrase_id = $this->translationExists($p_languageId)) {
  557. $trans = new Translation($p_languageId, $phrase_id);
  558. $trans->delete();
  559. $changed = true;
  560. } else {
  561. $changed = false;
  562. }
  563. } else {
  564. $description = new Translation($p_languageId, $this->getProperty('fk_phrase_id'));
  565. if ($description->exists()) {
  566. $changed = $description->setText($p_value);
  567. } else {
  568. $changed = $description->create($p_value);
  569. if ($changed && is_null($this->getProperty('fk_phrase_id'))) {
  570. $this->setProperty('fk_phrase_id', $description->getPhraseId());
  571. }
  572. }
  573. }
  574. if ($changed) {
  575. if (function_exists("camp_load_translation_strings")) {
  576. camp_load_translation_strings("api");
  577. }
  578. $logtext = getGS('Field "$1" updated', $this->m_data['field_name']);
  579. Log::Message($logtext, null, 143);
  580. }
  581. return $changed;
  582. } // fn setName
  583. /**
  584. * Returns the highest weight + 1 or 0 for the starter
  585. *
  586. * @return int
  587. */
  588. public function getNextOrder()
  589. {
  590. global $g_ado_db;
  591. $queryStr = "SELECT field_weight FROM `" . $this->m_dbTableName
  592. . "` WHERE type_name = '" . $g_ado_db->escape($this->m_data['type_name']) . "'"
  593. . " AND field_name != 'NULL' ORDER BY field_weight DESC";
  594. $field_weight = $g_ado_db->GetOne($queryStr);
  595. if (!is_null($field_weight)) {
  596. $next = $field_weight + 1;
  597. } else {
  598. $next = 1;
  599. }
  600. return $next;
  601. } // fn getNextOrder
  602. /**
  603. * Get the ordering of all fields; initially, a field has a field_weight
  604. * of NULL when it is created. if we discover that a field has a field
  605. * weight of NULL, we give it the MAX+1 field_weight. Returns a NUMERIC
  606. * array of ORDER => FIELDNAME.
  607. *
  608. * @return array
  609. */
  610. public function getOrders()
  611. {
  612. global $g_ado_db;
  613. $queryStr = "SELECT field_weight, field_name FROM `" . $this->m_dbTableName
  614. . "` WHERE type_name = '" . $g_ado_db->escape($this->m_data['type_name'])
  615. . "' AND field_name != 'NULL' ORDER BY field_weight DESC";
  616. $queryArray = $g_ado_db->GetAll($queryStr);
  617. $orderArray = array();
  618. foreach ($queryArray as $row => $values) {
  619. if ($values['field_weight'] == NULL) {
  620. $values['field_weight'] = $this->getNextOrder();
  621. }
  622. $orderArray[$values['field_weight']] = $values['field_name'];
  623. }
  624. return $orderArray;
  625. } // fn getOrders
  626. /**
  627. * Saves the ordering of all the fields. Accepts an NUMERIC array of
  628. * ORDERRANK => FIELDNAME. (see getOrders)
  629. *
  630. * @param array orderArray
  631. */
  632. public function setOrders($orderArray)
  633. {
  634. global $g_ado_db;
  635. foreach ($orderArray as $order => $field) {
  636. $field = new ArticleTypeField($this->m_data['type_name'], $field);
  637. if ($field->exists()) {
  638. $field->setProperty('field_weight', $order);
  639. }
  640. }
  641. } // fn setOrders
  642. /**
  643. * Reorders the current field; accepts either "up" or "down"
  644. *
  645. * @param string move (up|down)
  646. */
  647. public function reorder($move)
  648. {
  649. $orders = $this->getOrders();
  650. $tmp = array_keys($orders, $this->m_data['field_name']);
  651. if (count($tmp) == 0) {
  652. return;
  653. }
  654. $pos = $tmp[0];
  655. reset($orders);
  656. list($max, $value) = each($orders);
  657. end($orders);
  658. list($min, $value) = each($orders);
  659. if ($pos <= $min && $move == 'up') {
  660. return;
  661. }
  662. if ($pos >= $max && $move == 'down') {
  663. return;
  664. }
  665. if ($move == 'down') {
  666. $tmp = $orders[$pos + 1];
  667. $orders[$pos + 1] = $orders[$pos];
  668. $orders[$pos] = $tmp;
  669. }
  670. if ($move == 'up') {
  671. $tmp = $orders[$pos - 1];
  672. $orders[$pos - 1] = $orders[$pos];
  673. $orders[$pos] = $tmp;
  674. }
  675. $this->setOrders($orders);
  676. } // fn reorder
  677. /**
  678. * Returns an array of fields from all article types that match
  679. * the given conditions.
  680. *
  681. * @param $p_name
  682. * if specified returns fields with the given name
  683. * @param $p_articleType
  684. * if specified returns fields of the given article type
  685. * @param $p_dataType
  686. * if specified returns the fields having the given data type
  687. *
  688. * @return array
  689. */
  690. public static function FetchFields($p_name = null, $p_articleType = null,
  691. $p_dataType = null, $p_negateName = false, $p_negateArticleType = false,
  692. $p_negateDataType = false, $p_selectHidden = true, $p_skipCache = false)
  693. {
  694. global $g_ado_db;
  695. if (!$p_skipCache && CampCache::IsEnabled()) {
  696. $paramsArray['name'] = (is_null($p_name)) ? 'null' : $p_name;
  697. $paramsArray['article_type'] = (is_null($p_articleType)) ? 'null' : $p_articleType;
  698. $paramsArray['data_type'] = (is_null($p_dataType)) ? 'null' : $p_dataType;
  699. $paramsArray['negate_name'] = ($p_negateName == false) ? 'false' : 'true';
  700. $paramsArray['negate_article_type'] = ($p_negateArticleType == false) ? 'false' : 'true';
  701. $paramsArray['negate_data_type'] = ($p_negateDataType == false) ? 'false' : 'true';
  702. $paramsArray['select_hidden'] = ($p_selectHidden == false)? 'false' : 'true';
  703. $cacheListObj = new CampCacheList($paramsArray, __METHOD__);
  704. $articleTypeFieldsList = $cacheListObj->fetchFromCache();
  705. if ($articleTypeFieldsList !== false
  706. && is_array($articleTypeFieldsList)) {
  707. return $articleTypeFieldsList;
  708. }
  709. }
  710. $whereClauses = array();
  711. if (isset($p_name)) {
  712. $operator = $p_negateName ? '<>' : '=';
  713. $whereClauses[] = "field_name $operator '" . $g_ado_db->escape($p_name) . "'";
  714. }
  715. if (isset($p_articleType)) {
  716. $operator = $p_negateArticleType ? '<>' : '=';
  717. $whereClauses[] = "type_name $operator '" . $g_ado_db->escape($p_articleType) . "'";
  718. }
  719. if (isset($p_dataType)) {
  720. $operator = $p_negateDataType ? '<>' : '=';
  721. $whereClauses[] = "field_type $operator '" . $g_ado_db->escape($p_dataType) . "'";
  722. }
  723. if (!$p_selectHidden) {
  724. $whereClauses[] = 'is_hidden = false';
  725. }
  726. $where = count($whereClauses) > 0 ? ' WHERE ' . implode(' and ', $whereClauses) : null;
  727. $query = "SELECT * FROM `ArticleTypeMetadata` $where ORDER BY type_name ASC, field_weight ASC";
  728. $rows = $g_ado_db->GetAll($query);
  729. $fields = array();
  730. foreach ($rows as $row) {
  731. $field = new ArticleTypeField($row['type_name'], $row['field_name']);
  732. if ($field->getPrintName() == '') {
  733. $field->delete();
  734. continue;
  735. }
  736. $fields[] = $field;
  737. }
  738. if (!$p_skipCache && CampCache::IsEnabled()) {
  739. $cacheListObj->storeInCache($fields);
  740. }
  741. return $fields;
  742. } // fn FetchFields
  743. /**
  744. * Returns an array of valid field data types.
  745. * @return array
  746. */
  747. public static function DatabaseTypes($p_numericDigits = null, $p_numericPrecision = null)
  748. {
  749. $p_numericDigits = is_null($p_numericDigits) ? self::NUMERIC_DEFAULT_DIGITS : $p_numericDigits;
  750. $p_numericPrecision = is_null($p_numericPrecision) ? self::NUMERIC_DEFAULT_PRECISION : $p_numericPrecision;
  751. settype($p_numericDigits, 'integer');
  752. settype($p_numericPrecision, 'integer');
  753. $numericDef = "NUMERIC($p_numericDigits, $p_numericPrecision) NOT NULL";
  754. $types = array(self::TYPE_TEXT=>'VARCHAR(255) NOT NULL',
  755. self::TYPE_BODY=>'MEDIUMBLOB NOT NULL',
  756. self::TYPE_DATE=>'DATE NOT NULL',
  757. self::TYPE_TOPIC=>'INTEGER UNSIGNED NOT NULL',
  758. self::TYPE_SWITCH=>'BOOLEAN NOT NULL',
  759. self::TYPE_NUMERIC=>$numericDef);
  760. return $types;
  761. }
  762. } // class ArticleTypeField
  763. ?>