PageRenderTime 73ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/campsite/src/classes/Article.php

https://github.com/joechrysler/Campsite
PHP | 2949 lines | 1770 code | 339 blank | 840 comment | 277 complexity | eae368d1937328571a9f832ba82e3673 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, LGPL-2.1, Apache-2.0

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

  1. <?php
  2. /**
  3. * @package Campsite
  4. */
  5. /**
  6. * Includes
  7. */
  8. require_once($GLOBALS['g_campsiteDir'].'/db_connect.php');
  9. require_once($GLOBALS['g_campsiteDir'].'/classes/DatabaseObject.php');
  10. require_once($GLOBALS['g_campsiteDir'].'/classes/DbObjectArray.php');
  11. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleData.php');
  12. require_once($GLOBALS['g_campsiteDir'].'/classes/Log.php');
  13. require_once($GLOBALS['g_campsiteDir'].'/classes/Language.php');
  14. require_once($GLOBALS['g_campsiteDir'].'/classes/CampCacheList.php');
  15. /**
  16. * @package Campsite
  17. */
  18. class Article extends DatabaseObject {
  19. /**
  20. * The column names used for the primary key.
  21. * @var array
  22. */
  23. var $m_keyColumnNames = array('Number',
  24. 'IdLanguage');
  25. var $m_dbTableName = 'Articles';
  26. var $m_columnNames = array(
  27. // int - Publication ID
  28. 'IdPublication',
  29. // int -Issue ID
  30. 'NrIssue',
  31. // int - Section ID
  32. 'NrSection',
  33. // int - Article ID
  34. 'Number',
  35. // int - Language ID,
  36. 'IdLanguage',
  37. // string - Article Type
  38. 'Type',
  39. // int - User ID of user who manages the article in Campsite
  40. 'IdUser',
  41. // int - id of the author who wrote the article
  42. 'fk_default_author_id',
  43. // string - The title of the article.
  44. 'Name',
  45. // string
  46. // Whether the article is on the front page or not.
  47. // This is represented as 'N' or 'Y'.
  48. 'OnFrontPage',
  49. /**
  50. * Whether or not the article is on the section or not.
  51. * This is represented as 'N' or 'Y'.
  52. * @var string
  53. */
  54. 'OnSection',
  55. 'Published',
  56. 'PublishDate',
  57. 'UploadDate',
  58. 'Keywords',
  59. 'Public',
  60. 'IsIndexed',
  61. 'LockUser',
  62. 'LockTime',
  63. 'ShortName',
  64. 'ArticleOrder',
  65. 'comments_enabled',
  66. 'comments_locked',
  67. 'time_updated',
  68. 'object_id');
  69. var $m_languageName = null;
  70. private static $s_defaultOrder = array(array('field'=>'byPublication', 'dir'=>'ASC'),
  71. array('field'=>'byIssue', 'dir'=>'DESC'),
  72. array('field'=>'bySection', 'dir'=>'ASC'),
  73. array('field'=>'bySectionOrder', 'dir'=>'ASC'));
  74. private static $s_regularParameters = array('idpublication'=>'Articles.IdPublication',
  75. 'nrissue'=>'Articles.NrIssue',
  76. 'issue'=>'Articles.NrIssue',
  77. 'nrsection'=>'Articles.NrSection',
  78. 'section'=>'Articles.NrSection',
  79. 'idlanguage'=>'Articles.IdLanguage',
  80. 'name'=>'Articles.Name',
  81. 'number'=>'Articles.Number',
  82. 'upload_date'=>'DATE(Articles.UploadDate)',
  83. 'publish_date'=>'DATE(Articles.PublishDate)',
  84. 'type'=>'Articles.Type',
  85. 'keyword'=>'Articles.Keywords',
  86. 'onfrontpage'=>'Articles.OnFrontPage',
  87. 'onsection'=>'Articles.OnSection',
  88. 'public'=>'Articles.Public',
  89. 'published'=>'Articles.Published',
  90. 'workflow_status'=>'Articles.Published',
  91. 'issue_published'=>'Issues.Published',
  92. 'reads'=>'RequestObjects.request_count');
  93. /**
  94. * Construct by passing in the primary key to access the article in
  95. * the database.
  96. *
  97. * @param int $p_languageId
  98. * @param int $p_articleNumber
  99. * Not required when creating an article.
  100. */
  101. public function Article($p_languageId = null, $p_articleNumber = null)
  102. {
  103. parent::DatabaseObject($this->m_columnNames);
  104. $this->m_data['IdLanguage'] = $p_languageId;
  105. $this->m_data['Number'] = $p_articleNumber;
  106. if ($this->keyValuesExist()) {
  107. $this->fetch();
  108. }
  109. } // constructor
  110. /**
  111. * Fetch a single record from the database for the given key.
  112. *
  113. * @param array $p_recordSet
  114. * If the record has already been fetched and we just need to
  115. * assign the data to the object's internal member variable.
  116. *
  117. * @return boolean
  118. * TRUE on success, FALSE on failure
  119. */
  120. public function fetch($p_recordSet = null)
  121. {
  122. $res = parent::fetch($p_recordSet);
  123. if ($this->exists()) {
  124. settype($this->m_data['IdPublication'], 'integer');
  125. settype($this->m_data['NrIssue'], 'integer');
  126. settype($this->m_data['NrSection'], 'integer');
  127. settype($this->m_data['IdLanguage'], 'integer');
  128. settype($this->m_data['Number'], 'integer');
  129. settype($this->m_data['IdUser'], 'integer');
  130. settype($this->m_data['fk_default_author_id'], 'integer');
  131. settype($this->m_data['LockUser'], 'integer');
  132. settype($this->m_data['ArticleOrder'], 'integer');
  133. }
  134. return $res;
  135. }
  136. /**
  137. * A way for internal functions to call the superclass create function.
  138. * @param array $p_values
  139. */
  140. public function __create($p_values = null) { return parent::create($p_values); }
  141. /**
  142. * Create an article in the database. Use the SET functions to
  143. * change individual values.
  144. *
  145. * If you would like to "place" the article using the publication ID,
  146. * issue number, and section number, you can only do so if all three
  147. * of these parameters are present. Otherwise, the article will remain
  148. * unplaced.
  149. *
  150. * @param string $p_articleType
  151. * @param string $p_name
  152. * @param int $p_publicationId
  153. * @param int $p_issueNumber
  154. * @param int $p_sectionNumber
  155. * @return void
  156. */
  157. public function create($p_articleType, $p_name = null, $p_publicationId = null, $p_issueNumber = null, $p_sectionNumber = null)
  158. {
  159. global $g_ado_db;
  160. $this->m_data['Number'] = $this->__generateArticleNumber();
  161. $this->m_data['ArticleOrder'] = $this->m_data['Number'];
  162. // Create the record
  163. $values = array();
  164. if (!is_null($p_name)) {
  165. $values['Name'] = $p_name;
  166. }
  167. // Only categorize the article if all three arguments:
  168. // $p_publicationId, $p_issueNumber, and $p_sectionNumber
  169. // are present.
  170. if (is_numeric($p_publicationId)
  171. && is_numeric($p_issueNumber)
  172. && is_numeric($p_sectionNumber)
  173. && ($p_publicationId > 0)
  174. && ($p_issueNumber > 0)
  175. && ($p_sectionNumber > 0) ) {
  176. $values['IdPublication'] = (int)$p_publicationId;
  177. $values['NrIssue'] = (int)$p_issueNumber;
  178. $values['NrSection'] = (int)$p_sectionNumber;
  179. }
  180. $values['ShortName'] = $this->m_data['Number'];
  181. $values['Type'] = $p_articleType;
  182. $values['Public'] = 'Y';
  183. if (!is_null($p_publicationId) && $p_publicationId > 0) {
  184. $where = " WHERE IdPublication = $p_publicationId AND NrIssue = $p_issueNumber"
  185. . " and NrSection = $p_sectionNumber";
  186. } else {
  187. $where = '';
  188. }
  189. // compute article order number
  190. $queryStr = "SELECT MIN(ArticleOrder) AS min FROM Articles$where";
  191. $articleOrder = $g_ado_db->GetOne($queryStr);
  192. if (is_null($articleOrder) || !isset($values['NrSection'])) {
  193. $articleOrder = $this->m_data['Number'];
  194. } else {
  195. $increment = $articleOrder > 0 ? 1 : 2;
  196. $queryStr = "UPDATE Articles SET ArticleOrder = ArticleOrder + $increment $where";
  197. $g_ado_db->Execute($queryStr);
  198. $articleOrder = 1;
  199. }
  200. $values['ArticleOrder'] = $articleOrder;
  201. $success = parent::create($values);
  202. if (!$success) {
  203. return;
  204. }
  205. $this->fetch();
  206. $this->setProperty('UploadDate', 'NOW()', true, true);
  207. // Insert an entry into the article type table.
  208. $articleData = new ArticleData($this->m_data['Type'],
  209. $this->m_data['Number'],
  210. $this->m_data['IdLanguage']);
  211. $articleData->create();
  212. if (function_exists("camp_load_translation_strings")) {
  213. camp_load_translation_strings("api");
  214. }
  215. $logtext = getGS('Article #$1 "$2" ($3) created.',
  216. $this->m_data['Number'], $this->m_data['Name'], $this->getLanguageName());
  217. Log::Message($logtext, null, 31);
  218. } // fn create
  219. /**
  220. * Create a unique identifier for an article.
  221. * @access private
  222. */
  223. public function __generateArticleNumber()
  224. {
  225. global $g_ado_db;
  226. $queryStr = 'UPDATE AutoId SET ArticleId=LAST_INSERT_ID(ArticleId + 1)';
  227. $g_ado_db->Execute($queryStr);
  228. if ($g_ado_db->Affected_Rows() <= 0) {
  229. // If we were not able to get an ID.
  230. return 0;
  231. }
  232. return (int)$g_ado_db->Insert_ID();
  233. } // fn __generateArticleNumber
  234. /**
  235. * Create a copy of this article.
  236. *
  237. * @param int $p_destPublicationId -
  238. * The destination publication ID.
  239. * @param int $p_destIssueNumber -
  240. * The destination issue number.
  241. * @param int $p_destSectionNumber -
  242. * The destination section number.
  243. * @param int $p_userId -
  244. * The user creating the copy. If null, keep the same user ID as the original.
  245. * @param mixed $p_copyTranslations -
  246. * If false (default), only this article will be copied.
  247. * If true, all translations will be copied.
  248. * If an array is passed, the translations given will be copied.
  249. * Any translations that do not exist will be ignored.
  250. *
  251. * @return Article
  252. * If $p_copyTranslations is TRUE or an array, return an array of newly created articles.
  253. * If $p_copyTranslations is FALSE, return the new Article.
  254. */
  255. public function copy($p_destPublicationId = 0, $p_destIssueNumber = 0,
  256. $p_destSectionNumber = 0, $p_userId = null,
  257. $p_copyTranslations = false)
  258. {
  259. global $g_ado_db;
  260. // It is an optimization to put these here because in most cases
  261. // you dont need these files.
  262. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleImage.php');
  263. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleTopic.php');
  264. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleAttachment.php');
  265. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleAudioclip.php');
  266. $copyArticles = array();
  267. if ($p_copyTranslations) {
  268. // Get all translations for this article
  269. $copyArticles = $this->getTranslations();
  270. // Remove any translations that are not requested to be translated.
  271. if (is_array($p_copyTranslations)) {
  272. $tmpArray = array();
  273. foreach ($copyArticles as $tmpArticle) {
  274. if (in_array($tmpArticle->m_data['IdLanguage'], $p_copyTranslations)) {
  275. $tmpArray[] = $tmpArticle;
  276. }
  277. }
  278. $copyArticles = $tmpArray;
  279. }
  280. } else {
  281. $copyArticles[] = $this;
  282. }
  283. $newArticleNumber = $this->__generateArticleNumber();
  284. // Load translation file for log message.
  285. if (function_exists("camp_load_translation_strings")) {
  286. camp_load_translation_strings("api");
  287. }
  288. $articleOrder = null;
  289. $logtext = '';
  290. $newArticles = array();
  291. foreach ($copyArticles as $copyMe) {
  292. // Construct the duplicate article object.
  293. $articleCopy = new Article();
  294. $articleCopy->m_data['IdPublication'] = (int)$p_destPublicationId;
  295. $articleCopy->m_data['NrIssue'] = (int)$p_destIssueNumber;
  296. $articleCopy->m_data['NrSection'] = (int)$p_destSectionNumber;
  297. $articleCopy->m_data['IdLanguage'] = (int)$copyMe->m_data['IdLanguage'];
  298. $articleCopy->m_data['Number'] = (int)$newArticleNumber;
  299. $values = array();
  300. // Copy some attributes
  301. $values['ShortName'] = $newArticleNumber;
  302. $values['Type'] = $copyMe->m_data['Type'];
  303. $values['OnFrontPage'] = $copyMe->m_data['OnFrontPage'];
  304. $values['OnSection'] = $copyMe->m_data['OnSection'];
  305. $values['Public'] = $copyMe->m_data['Public'];
  306. $values['ArticleOrder'] = $articleOrder;
  307. $values['Keywords'] = $copyMe->m_data['Keywords'];
  308. // Change some attributes
  309. $values['Published'] = 'N';
  310. $values['IsIndexed'] = 'N';
  311. $values['LockUser'] = 0;
  312. $values['LockTime'] = 0;
  313. if (!is_null($p_userId)) {
  314. $values['IdUser'] = $p_userId;
  315. } else {
  316. $values['IdUser'] = $copyMe->m_data['IdUser'];
  317. }
  318. $values['Name'] = $articleCopy->getUniqueName($copyMe->m_data['Name']);
  319. $articleCopy->__create($values);
  320. $articleCopy->setProperty('UploadDate', 'NOW()', true, true);
  321. if (is_null($articleOrder)) {
  322. $g_ado_db->Execute('LOCK TABLES Articles WRITE');
  323. $articleOrder = $g_ado_db->GetOne('SELECT MAX(ArticleOrder) + 1 FROM Articles');
  324. $articleCopy->setProperty('ArticleOrder', $articleOrder);
  325. $g_ado_db->Execute('UNLOCK TABLES');
  326. }
  327. // Insert an entry into the article type table.
  328. $newArticleData = new ArticleData($articleCopy->m_data['Type'],
  329. $articleCopy->m_data['Number'],
  330. $articleCopy->m_data['IdLanguage']);
  331. $newArticleData->create();
  332. $origArticleData = $copyMe->getArticleData();
  333. $origArticleData->copyToExistingRecord($articleCopy->m_data['Number']);
  334. // Copy image pointers
  335. ArticleImage::OnArticleCopy($copyMe->m_data['Number'], $articleCopy->m_data['Number']);
  336. // Copy topic pointers
  337. ArticleTopic::OnArticleCopy($copyMe->m_data['Number'], $articleCopy->m_data['Number']);
  338. // Copy file pointers
  339. ArticleAttachment::OnArticleCopy($copyMe->m_data['Number'], $articleCopy->m_data['Number']);
  340. // Copy audioclip pointers
  341. ArticleAudioclip::OnArticleCopy($copyMe->m_data['Number'], $articleCopy->m_data['Number']);
  342. // Position the new article at the beginning of the section
  343. $articleCopy->positionAbsolute(1);
  344. $newArticles[] = $articleCopy;
  345. $languageObj = new Language($copyMe->getLanguageId());
  346. $logtext .= getGS('Article #$1 "$2" ($3) copied to Article #$4 (publication $5, issue $6, section $7).',
  347. $copyMe->getArticleNumber(), $copyMe->getName(), $languageObj->getCode(),
  348. $articleCopy->getArticleNumber(), $articleCopy->getPublicationId(),
  349. $articleCopy->getIssueNumber(), $articleCopy->getSectionNumber());
  350. }
  351. Log::Message($logtext, null, 155);
  352. if ($p_copyTranslations) {
  353. return $newArticles;
  354. } else {
  355. return array_pop($newArticles);
  356. }
  357. } // fn copy
  358. /**
  359. * This is a convenience function to move an article from
  360. * one section to another.
  361. *
  362. * @param int $p_destPublicationId -
  363. * The destination publication ID.
  364. * @param int $p_destIssueNumber -
  365. * The destination issue number.
  366. * @param int $p_destSectionNumber -
  367. * The destination section number.
  368. *
  369. * @return boolean
  370. */
  371. public function move($p_destPublicationId = 0, $p_destIssueNumber = 0,
  372. $p_destSectionNumber = 0)
  373. {
  374. global $g_ado_db;
  375. $columns = array();
  376. if ($this->m_data["IdPublication"] != $p_destPublicationId) {
  377. $columns["IdPublication"] = (int)$p_destPublicationId;
  378. }
  379. if ($this->m_data["NrIssue"] != $p_destIssueNumber) {
  380. $columns["NrIssue"] = (int)$p_destIssueNumber;
  381. }
  382. if ($this->m_data["NrSection"] != $p_destSectionNumber) {
  383. $columns["NrSection"] = (int)$p_destSectionNumber;
  384. }
  385. $success = false;
  386. if (count($columns) > 0) {
  387. $success = $this->update($columns);
  388. if ($success) {
  389. $g_ado_db->Execute('LOCK TABLES Articles WRITE');
  390. $articleOrder = $g_ado_db->GetOne('SELECT MAX(ArticleOrder) + 1 FROM Articles');
  391. $this->setProperty('ArticleOrder', $articleOrder);
  392. $g_ado_db->Execute('UNLOCK TABLES');
  393. $this->positionAbsolute(1);
  394. }
  395. }
  396. return $success;
  397. } // fn move
  398. /**
  399. * Return a unique name based on this article's name.
  400. * The name returned will have the form "original_article_name (duplicate #)"
  401. * @return string
  402. */
  403. public function getUniqueName($p_currentName)
  404. {
  405. global $g_ado_db;
  406. $origNewName = $p_currentName . " (".getGS("Duplicate");
  407. $newName = $origNewName .")";
  408. $count = 1;
  409. while (true) {
  410. $queryStr = 'SELECT * FROM Articles '
  411. .' WHERE IdPublication = '.$this->m_data['IdPublication']
  412. .' AND NrIssue = ' . $this->m_data['NrIssue']
  413. .' AND NrSection = ' . $this->m_data['NrSection']
  414. .' AND IdLanguage = ' . $this->m_data['IdLanguage']
  415. ." AND Name = '" . mysql_escape_string($newName) . "'";
  416. $row = $g_ado_db->GetRow($queryStr);
  417. if (count($row) > 0) {
  418. $newName = $origNewName.' '.++$count.')';
  419. } else {
  420. break;
  421. }
  422. }
  423. return $newName;
  424. } // fn getUniqueName
  425. /**
  426. * Create a copy of the article, but make it a translation
  427. * of the current one.
  428. *
  429. * @param int $p_languageId
  430. * @param int $p_userId
  431. * @param string $p_name
  432. * @return Article
  433. */
  434. public function createTranslation($p_languageId, $p_userId, $p_name)
  435. {
  436. // Construct the duplicate article object.
  437. $articleCopy = new Article();
  438. $articleCopy->m_data['IdPublication'] = $this->m_data['IdPublication'];
  439. $articleCopy->m_data['NrIssue'] = $this->m_data['NrIssue'];
  440. $articleCopy->m_data['NrSection'] = $this->m_data['NrSection'];
  441. $articleCopy->m_data['IdLanguage'] = $p_languageId;
  442. $articleCopy->m_data['Number'] = $this->m_data['Number'];
  443. $values = array();
  444. // Copy some attributes
  445. $values['ShortName'] = $this->m_data['ShortName'];
  446. $values['Type'] = $this->m_data['Type'];
  447. $values['OnFrontPage'] = $this->m_data['OnFrontPage'];
  448. $values['OnSection'] = $this->m_data['OnFrontPage'];
  449. $values['Public'] = $this->m_data['Public'];
  450. $values['ArticleOrder'] = $this->m_data['ArticleOrder'];
  451. $values['comments_enabled'] = $this->m_data['comments_enabled'];
  452. $values['comments_locked'] = $this->m_data['comments_locked'];
  453. // Change some attributes
  454. $values['Name'] = $p_name;
  455. $values['Published'] = 'N';
  456. $values['IsIndexed'] = 'N';
  457. $values['LockUser'] = 0;
  458. $values['LockTime'] = 0;
  459. $values['IdUser'] = $p_userId;
  460. // Create the record
  461. $success = $articleCopy->__create($values);
  462. if (!$success) {
  463. return false;
  464. }
  465. $articleCopy->setProperty('UploadDate', 'NOW()', true, true);
  466. // Insert an entry into the article type table.
  467. $articleCopyData = new ArticleData($articleCopy->m_data['Type'],
  468. $articleCopy->m_data['Number'], $articleCopy->m_data['IdLanguage']);
  469. $articleCopyData->create();
  470. $origArticleData = $this->getArticleData();
  471. $origArticleData->copyToExistingRecord($articleCopy->getArticleNumber(), $p_languageId);
  472. if (function_exists("camp_load_translation_strings")) {
  473. camp_load_translation_strings("api");
  474. }
  475. $logtext = getGS('Article #$1 "$2" ($3) translated to "$4" ($5)',
  476. $this->getArticleNumber(), $this->getTitle(), $this->getLanguageName(),
  477. $articleCopy->getTitle(), $articleCopy->getLanguageName());
  478. Log::Message($logtext, null, 31);
  479. return $articleCopy;
  480. } // fn createTranslation
  481. /**
  482. * Delete article from database. This will
  483. * only delete one specific translation of the article.
  484. *
  485. * @return boolean
  486. */
  487. public function delete()
  488. {
  489. // It is an optimization to put these here because in most cases
  490. // you dont need these files.
  491. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleImage.php');
  492. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleTopic.php');
  493. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleIndex.php');
  494. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleAttachment.php');
  495. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleAudioclip.php');
  496. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleComment.php');
  497. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticlePublish.php');
  498. // Delete scheduled publishing
  499. ArticlePublish::OnArticleDelete($this->m_data['Number'], $this->m_data['IdLanguage']);
  500. // Delete Article Comments
  501. ArticleComment::OnArticleDelete($this->m_data['Number'], $this->m_data['IdLanguage']);
  502. // is this the last translation?
  503. if (count($this->getLanguages()) <= 1) {
  504. // Delete image pointers
  505. ArticleImage::OnArticleDelete($this->m_data['Number']);
  506. // Delete topics pointers
  507. ArticleTopic::OnArticleDelete($this->m_data['Number']);
  508. // Delete file pointers
  509. ArticleAttachment::OnArticleDelete($this->m_data['Number']);
  510. // Delete audioclip pointers
  511. ArticleAudioclip::OnArticleDelete($this->m_data['Number']);
  512. // Delete indexes
  513. ArticleIndex::OnArticleDelete($this->getPublicationId(), $this->getIssueNumber(),
  514. $this->getSectionNumber(), $this->getLanguageId(), $this->getArticleNumber());
  515. }
  516. // Delete row from article type table.
  517. $articleData = new ArticleData($this->m_data['Type'],
  518. $this->m_data['Number'],
  519. $this->m_data['IdLanguage']);
  520. $articleData->delete();
  521. $tmpData = $this->m_data;
  522. $tmpData['languageName'] = $this->getLanguageName();
  523. // Delete row from Articles table.
  524. $deleted = parent::delete();
  525. if ($deleted) {
  526. if (function_exists("camp_load_translation_strings")) {
  527. camp_load_translation_strings("api");
  528. }
  529. $logtext = getGS('Article #$1 "$2" ($3) deleted.',
  530. $tmpData['Number'], $tmpData['Name'], $tmpData['languageName'])
  531. ." (".getGS("Publication")." ".$tmpData['IdPublication'].", "
  532. ." ".getGS("Issue")." ".$tmpData['NrIssue'].", "
  533. ." ".getGS("Section")." ".$tmpData['NrSection'].")";
  534. Log::Message($logtext, null, 32);
  535. }
  536. return $deleted;
  537. } // fn delete
  538. /**
  539. * Get the time the article was locked.
  540. *
  541. * @return string
  542. * In the form of YYYY-MM-DD HH:MM:SS
  543. */
  544. public function getLockTime()
  545. {
  546. return $this->m_data['LockTime'];
  547. } // fn getLockTime
  548. /**
  549. * Return TRUE if the article is locked, FALSE if it isnt.
  550. * @return boolean
  551. */
  552. public function isLocked()
  553. {
  554. if ( ($this->m_data['LockUser'] == 0) && ($this->m_data['LockTime'] == 0) ) {
  555. return false;
  556. } else {
  557. return true;
  558. }
  559. } // fn isLocked
  560. /**
  561. * Lock or unlock the article.
  562. *
  563. * Locking the article requires the user ID parameter.
  564. *
  565. * @param boolean $p_lock
  566. * @param int $p_userId
  567. * @return void
  568. */
  569. public function setIsLocked($p_lock, $p_userId = null)
  570. {
  571. // Check parameters
  572. if ($p_lock && !is_numeric($p_userId)) {
  573. return;
  574. }
  575. // Don't change the article timestamp when the
  576. // article is locked.
  577. $lastModified = $this->m_data['time_updated'];
  578. if ($p_lock) {
  579. $this->setProperty('LockUser', $p_userId);
  580. $this->setProperty('LockTime', 'NOW()', true, true);
  581. } else {
  582. $this->setProperty('LockUser', '0', false);
  583. $this->setProperty('LockTime', '0', false);
  584. $this->commit();
  585. }
  586. $this->setProperty('time_updated', $lastModified);
  587. } // fn setIsLocked
  588. /**
  589. * Return an array of Language objects, one for each
  590. * language the article is written in.
  591. *
  592. * @param boolean $p_excludeCurrent
  593. * If true, exclude the current language from the list.
  594. * @param array $p_order
  595. * The array of order directives in the format:
  596. * array('field'=>field_name, 'dir'=>order_direction)
  597. * field_name can take one of the following values:
  598. * bynumber, byname, byenglish_name, bycode
  599. * order_direction can take one of the following values:
  600. * asc, desc
  601. * @return array
  602. */
  603. public function getLanguages($p_excludeCurrent = false, array $p_order = array(),
  604. $p_published = false)
  605. {
  606. if (!$this->exists()) {
  607. return array();
  608. }
  609. $tmpLanguage = new Language();
  610. $columnNames = $tmpLanguage->getColumnNames(true);
  611. $queryStr = 'SELECT '.implode(',', $columnNames).' FROM Articles, Languages '
  612. .' WHERE Articles.IdLanguage = Languages.Id'
  613. .' AND IdPublication = ' . $this->m_data['IdPublication']
  614. .' AND NrIssue = ' . $this->m_data['NrIssue']
  615. .' AND NrSection = ' . $this->m_data['NrSection']
  616. .' AND Number = ' . $this->m_data['Number'];
  617. if ($p_excludeCurrent) {
  618. $queryStr .= ' AND Languages.Id != ' . $this->m_data['IdLanguage'];
  619. }
  620. if ($p_published) {
  621. $queryStr .= " AND Articles.Published = 'Y'";
  622. }
  623. $order = Article::ProcessLanguageListOrder($p_order);
  624. foreach ($order as $orderDesc) {
  625. $sqlOrder[] = $orderDesc['field'] . ' ' . $orderDesc['dir'];
  626. }
  627. if (count($sqlOrder) > 0) {
  628. $queryStr .= ' ORDER BY ' . implode(', ', $sqlOrder);
  629. }
  630. $languages = DbObjectArray::Create('Language', $queryStr);
  631. return $languages;
  632. } // fn getLanguages
  633. /**
  634. * Return an array of Article objects, one for each
  635. * type of language the article is written in.
  636. *
  637. * @param int $p_articleNumber
  638. * Optional. Use this if you call this function statically.
  639. *
  640. * @return array
  641. */
  642. public function getTranslations($p_articleNumber = null)
  643. {
  644. if (!is_null($p_articleNumber)) {
  645. $articleNumber = $p_articleNumber;
  646. } elseif (isset($this)) {
  647. $articleNumber = $this->m_data['Number'];
  648. } else {
  649. return array();
  650. }
  651. $queryStr = 'SELECT * FROM Articles '
  652. ." WHERE Number=$articleNumber";
  653. $articles = DbObjectArray::Create('Article', $queryStr);
  654. return $articles;
  655. } // fn getTranslations
  656. /**
  657. * A simple way to get the name of the language the article is
  658. * written in. The value is cached in case there are multiple
  659. * calls to this function.
  660. *
  661. * @return string
  662. */
  663. public function getLanguageName()
  664. {
  665. if (is_null($this->m_languageName)) {
  666. $language = new Language($this->m_data['IdLanguage']);
  667. $this->m_languageName = $language->getNativeName();
  668. }
  669. return $this->m_languageName;
  670. } // fn getLanguageName
  671. /**
  672. * Get the section that this article is in.
  673. * @return object
  674. */
  675. public function getSection()
  676. {
  677. $section = new Section($this->getPublicationId(), $this->getIssueNumber(),
  678. $this->getLanguageId(), $this->getSectionNumber());
  679. if (!$section->exists()) {
  680. $sections = Section::GetSections($this->getPublicationId(), $this->getIssueNumber());
  681. if (count($sections) > 0) {
  682. return $sections[0];
  683. }
  684. }
  685. return $section;
  686. } // fn getSection
  687. /**
  688. * Change the article's position in the order sequence
  689. * relative to its current position.
  690. *
  691. * @param string $p_direction -
  692. * Can be "up" or "down". "Up" means towards the beginning of the list,
  693. * and "down" means towards the end of the list.
  694. *
  695. * @param int $p_spacesToMove -
  696. * The number of spaces to move the article.
  697. *
  698. * @return boolean
  699. */
  700. public function positionRelative($p_direction, $p_spacesToMove = 1)
  701. {
  702. global $g_ado_db;
  703. CampCache::singleton()->clear('user');
  704. $this->fetch();
  705. $g_ado_db->Execute('LOCK TABLES Articles WRITE');
  706. // Get the article that is in the final position where this
  707. // article will be moved to.
  708. $compareOperator = ($p_direction == 'up') ? '<' : '>';
  709. $order = ($p_direction == 'up') ? 'desc' : 'asc';
  710. $queryStr = 'SELECT DISTINCT(Number), ArticleOrder FROM Articles '
  711. .' WHERE IdPublication='.$this->m_data['IdPublication']
  712. .' AND NrIssue='.$this->m_data['NrIssue']
  713. .' AND NrSection='.$this->m_data['NrSection']
  714. .' AND ArticleOrder '.$compareOperator.' '.$this->m_data['ArticleOrder']
  715. .' ORDER BY ArticleOrder ' . $order
  716. .' LIMIT '.($p_spacesToMove-1).', 1';
  717. $destRow = $g_ado_db->GetRow($queryStr);
  718. if (!$destRow) {
  719. // Special case: there was a bug when you duplicated articles that
  720. // caused them to have the same order number. So we check here if
  721. // there are any articles that match the order number of the current
  722. // article. The end result will be that this article will have
  723. // a different order number than all the articles it used to share it
  724. // with. However, the other articles will still have the same
  725. // order number, which means that the article may appear to 'jump'
  726. // across multiple articles.
  727. $queryStr = 'SELECT DISTINCT(Number), ArticleOrder FROM Articles '
  728. .' WHERE IdPublication='.$this->m_data['IdPublication']
  729. .' AND NrIssue='.$this->m_data['NrIssue']
  730. .' AND NrSection='.$this->m_data['NrSection']
  731. .' AND ArticleOrder='.$this->m_data['ArticleOrder']
  732. .' LIMIT '.($p_spacesToMove-1).', 1';
  733. $destRow = $g_ado_db->GetRow($queryStr);
  734. if (!$destRow) {
  735. $g_ado_db->Execute('UNLOCK TABLES');
  736. return false;
  737. }
  738. }
  739. // Shift all articles one space between the source and destination article.
  740. $operator = ($p_direction == 'up') ? '+' : '-';
  741. $minArticleOrder = min($destRow['ArticleOrder'], $this->m_data['ArticleOrder']);
  742. $maxArticleOrder = max($destRow['ArticleOrder'], $this->m_data['ArticleOrder']);
  743. $queryStr2 = 'UPDATE Articles SET ArticleOrder = ArticleOrder '.$operator.' 1 '
  744. .' WHERE IdPublication = '. $this->m_data['IdPublication']
  745. .' AND NrIssue = ' . $this->m_data['NrIssue']
  746. .' AND NrSection = ' . $this->m_data['NrSection']
  747. .' AND ArticleOrder >= '.$minArticleOrder
  748. .' AND ArticleOrder <= '.$maxArticleOrder;
  749. $g_ado_db->Execute($queryStr2);
  750. // Change position of this article to the destination position.
  751. $queryStr3 = 'UPDATE Articles SET ArticleOrder = ' . $destRow['ArticleOrder']
  752. .' WHERE IdPublication = '. $this->m_data['IdPublication']
  753. .' AND NrIssue = ' . $this->m_data['NrIssue']
  754. .' AND NrSection = ' . $this->m_data['NrSection']
  755. .' AND Number = ' . $this->m_data['Number'];
  756. $g_ado_db->Execute($queryStr3);
  757. $g_ado_db->Execute('UNLOCK TABLES');
  758. CampCache::singleton()->clear('user');
  759. // Re-fetch this article to get the updated article order.
  760. $this->fetch();
  761. return true;
  762. } // fn positionRelative
  763. /**
  764. * Move the article to the given position (i.e. reorder the article).
  765. * @param int $p_moveToPosition
  766. * @return boolean
  767. */
  768. public function positionAbsolute($p_moveToPosition = 1)
  769. {
  770. global $g_ado_db;
  771. CampCache::singleton()->clear('user');
  772. $this->fetch();
  773. $g_ado_db->Execute('LOCK TABLES Articles WRITE');
  774. // Get the article that is in the location we are moving
  775. // this one to.
  776. $queryStr = 'SELECT Number, IdLanguage, ArticleOrder FROM Articles '
  777. .' WHERE IdPublication='.$this->m_data['IdPublication']
  778. .' AND NrIssue='.$this->m_data['NrIssue']
  779. .' AND NrSection='.$this->m_data['NrSection']
  780. .' ORDER BY ArticleOrder ASC LIMIT '.($p_moveToPosition - 1).', 1';
  781. $destRow = $g_ado_db->GetRow($queryStr);
  782. if (!$destRow) {
  783. $g_ado_db->Execute('UNLOCK TABLES');
  784. return false;
  785. }
  786. if ($destRow['ArticleOrder'] == $this->m_data['ArticleOrder']) {
  787. $g_ado_db->Execute('UNLOCK TABLES');
  788. // Move the destination down one.
  789. $destArticle = new Article($destRow['IdLanguage'], $destRow['Number']);
  790. $destArticle->positionRelative("down", 1);
  791. return true;
  792. }
  793. if ($destRow['ArticleOrder'] > $this->m_data['ArticleOrder']) {
  794. $operator = '-';
  795. } else {
  796. $operator = '+';
  797. }
  798. // Reorder all the other articles in this section
  799. $minArticleOrder = min($destRow['ArticleOrder'], $this->m_data['ArticleOrder']);
  800. $maxArticleOrder = max($destRow['ArticleOrder'], $this->m_data['ArticleOrder']);
  801. $queryStr = 'UPDATE Articles '
  802. .' SET ArticleOrder = ArticleOrder '.$operator.' 1 '
  803. .' WHERE IdPublication='.$this->m_data['IdPublication']
  804. .' AND NrIssue='.$this->m_data['NrIssue']
  805. .' AND NrSection='.$this->m_data['NrSection']
  806. .' AND ArticleOrder >= '.$minArticleOrder
  807. .' AND ArticleOrder <= '.$maxArticleOrder;
  808. $g_ado_db->Execute($queryStr);
  809. // Reposition this article.
  810. $queryStr = 'UPDATE Articles '
  811. .' SET ArticleOrder='.$destRow['ArticleOrder']
  812. .' WHERE IdPublication='.$this->m_data['IdPublication']
  813. .' AND NrIssue='.$this->m_data['NrIssue']
  814. .' AND NrSection='.$this->m_data['NrSection']
  815. .' AND Number='.$this->m_data['Number'];
  816. $g_ado_db->Execute($queryStr);
  817. $g_ado_db->Execute('UNLOCK TABLES');
  818. CampCache::singleton()->clear('user');
  819. $this->fetch();
  820. return true;
  821. } // fn positionAbsolute
  822. /**
  823. * Return true if the given user has permission to modify the content of this article.
  824. *
  825. * 1) Publishers can always edit.
  826. * 2) Users who have the ChangeArticle right can edit as long as the
  827. * article is not published. i.e. they can edit ALL articles that are
  828. * new or submitted.
  829. * 3) The user created the article and the article is in the "New" state.
  830. *
  831. * @return boolean
  832. */
  833. public function userCanModify($p_user)
  834. {
  835. $userCreatedArticle = ($this->m_data['IdUser'] == $p_user->getUserId());
  836. $articleIsNew = ($this->m_data['Published'] == 'N');
  837. $articleIsNotPublished = (($this->m_data['Published'] == 'N') || ($this->m_data['Published'] == 'S'));
  838. if ($p_user->hasPermission('Publish')
  839. || ($p_user->hasPermission('ChangeArticle')
  840. && $articleIsNotPublished)
  841. || ($userCreatedArticle && $articleIsNew)) {
  842. return true;
  843. } else {
  844. return false;
  845. }
  846. } // fn userCanModify
  847. /**
  848. * Get the name of the dynamic article type table.
  849. *
  850. * @return string
  851. */
  852. public function getArticleTypeTableName()
  853. {
  854. return 'X'.$this->m_data['Type'];
  855. } // fn getArticleTypeTableName
  856. /**
  857. * Get the publication ID of the publication that contains this article.
  858. * @return int
  859. */
  860. public function getPublicationId()
  861. {
  862. return (int)$this->m_data['IdPublication'];
  863. } // fn getPublicationId
  864. /**
  865. * Set the publication ID.
  866. *
  867. * @param int $p_value
  868. * @return boolean
  869. */
  870. public function setPublicationId($p_value)
  871. {
  872. if (is_numeric($p_value)) {
  873. return $this->setProperty('IdPublication', (int)$p_value);
  874. } else {
  875. return false;
  876. }
  877. } // fn setPublicationId
  878. /**
  879. * Get the issue that the article resides within.
  880. *
  881. * @return int
  882. */
  883. public function getIssueNumber()
  884. {
  885. return (int)$this->m_data['NrIssue'];
  886. } // fn getIssueNumber
  887. /**
  888. * Set the issue number.
  889. *
  890. * @param int $p_value
  891. * @return boolean
  892. */
  893. public function setIssueNumber($p_value)
  894. {
  895. if (is_numeric($p_value)) {
  896. return $this->setProperty('NrIssue', (int)$p_value);
  897. } else {
  898. return false;
  899. }
  900. } // fn setIssueNumber
  901. /**
  902. * Get the section number that contains this article.
  903. *
  904. * @return int
  905. */
  906. public function getSectionNumber()
  907. {
  908. return (int)$this->m_data['NrSection'];
  909. } // fn getSectionNumber
  910. /**
  911. * Set the section number.
  912. *
  913. * @param int $p_value
  914. * @return boolean
  915. */
  916. public function setSectionNumber($p_value)
  917. {
  918. if (is_numeric($p_value)) {
  919. return $this->setProperty('NrSection', (int)$p_value);
  920. } else {
  921. return false;
  922. }
  923. } // fn setSectionNumber
  924. /**
  925. * Return the language the article was written in.
  926. *
  927. * @return int
  928. */
  929. public function getLanguageId()
  930. {
  931. return (int)$this->m_data['IdLanguage'];
  932. } // fn getLanguageId
  933. /**
  934. * Return the article number. The article number is
  935. * not necessarily unique. Articles that have been translated into
  936. * multiple languages all have the same article number.
  937. * Therefore to uniquely identify an article you need both
  938. * the article number and the language ID.
  939. *
  940. * @return int
  941. */
  942. public function getArticleNumber()
  943. {
  944. return (int)$this->m_data['Number'];
  945. } // fn getArticleNumber
  946. /**
  947. * Get the title of the article.
  948. *
  949. * @return string
  950. */
  951. public function getTitle()
  952. {
  953. return $this->m_data['Name'];
  954. } // fn getTitle
  955. /**
  956. * Alias for getTitle().
  957. *
  958. * @return string
  959. */
  960. public function getName()
  961. {
  962. return $this->m_data['Name'];
  963. } // fn getName
  964. /**
  965. * Set the title of the article.
  966. *
  967. * @param string $p_title
  968. *
  969. * @return void
  970. */
  971. public function setTitle($p_title)
  972. {
  973. return parent::setProperty('Name', $p_title);
  974. } // fn setTitle
  975. /**
  976. * Get the article type.
  977. * @return string
  978. */
  979. public function getType()
  980. {
  981. return $this->m_data['Type'];
  982. } // fn getType
  983. /**
  984. * Get the logged in language's translation of the article type.
  985. * @return string
  986. */
  987. public function getTranslateType($p_languageId = null)
  988. {
  989. $type = $this->getType();
  990. $typeObj = new ArticleType($type);
  991. return $typeObj->getDisplayName($p_languageId);
  992. }
  993. /**
  994. * Return the user ID of the user who created this article.
  995. * @return int
  996. */
  997. public function getCreatorId()
  998. {
  999. return (int)$this->m_data['IdUser'];
  1000. } // fn getCreatorId
  1001. /**
  1002. * Set the user ID of the user who created this article.
  1003. *
  1004. * @param int $p_value
  1005. * @return boolean
  1006. */
  1007. public function setCreatorId($p_value)
  1008. {
  1009. return parent::setProperty('IdUser', (int)$p_value);
  1010. } // fn setCreatorId
  1011. /**
  1012. * Return the ID of the author who wrote this article.
  1013. * @return int
  1014. */
  1015. public function getAuthorId()
  1016. {
  1017. return (int)$this->m_data['fk_default_author_id'];
  1018. } // fn getAuthorId
  1019. /**
  1020. * Set the ID of the author who wrote this article.
  1021. *
  1022. * @param int $p_value
  1023. * @return boolean
  1024. */
  1025. public function setAuthorId($p_value)
  1026. {
  1027. return parent::setProperty('fk_default_author_id', (int)$p_value);
  1028. } // fn setAuthorId
  1029. /**
  1030. * Return an integer representing the order of the article
  1031. * within the section. Note that these numbers are not sequential
  1032. * and can only be compared with the other articles in the section.
  1033. *
  1034. * @return int
  1035. */
  1036. public function getOrder()
  1037. {
  1038. return $this->m_data['ArticleOrder'];
  1039. } // fn getOrder
  1040. /**
  1041. * Return true if the article will appear on the front page.
  1042. *
  1043. * @return boolean
  1044. */
  1045. public function onFrontPage()
  1046. {
  1047. return ($this->m_data['OnFrontPage'] == 'Y');
  1048. } // fn onFrontPage
  1049. /**
  1050. * Set whether the article should appear on the front page.
  1051. *
  1052. * @param boolean $p_value
  1053. * @return boolean
  1054. */
  1055. public function setOnFrontPage($p_value)
  1056. {
  1057. return parent::setProperty('OnFrontPage', $p_value?'Y':'N');
  1058. } // fn setOnFrontPage
  1059. /**
  1060. * Return TRUE if this article will appear on the section page.
  1061. *
  1062. * @return boolean
  1063. */
  1064. public function onSectionPage()
  1065. {
  1066. return ($this->m_data['OnSection'] == 'Y');
  1067. } // fn onSectionPage
  1068. /**
  1069. * Set whether the article will appear on the section page.
  1070. * @param boolean $p_value
  1071. * @return boolean
  1072. */
  1073. public function setOnSectionPage($p_value)
  1074. {
  1075. return parent::setProperty('OnSection', $p_value?'Y':'N');
  1076. } // fn setOnSectionPage
  1077. /**
  1078. * Return the current workflow state of the article:
  1079. * 'Y' = "Published"
  1080. * 'S' = "Submitted"
  1081. * 'N' = "New"
  1082. *
  1083. * @return string
  1084. * Can be 'Y', 'S', or 'N'.
  1085. */
  1086. public function getWorkflowStatus()
  1087. {
  1088. return $this->m_data['Published'];
  1089. } // fn getWorkflowStatus
  1090. /**
  1091. * Return a human-readable string for the status of the workflow.
  1092. * This can be called statically or as a member function.
  1093. * If called statically, you must pass in a parameter.
  1094. *
  1095. * @param string $p_value
  1096. * @return string
  1097. */
  1098. public function getWorkflowDisplayString($p_value = null)
  1099. {
  1100. if (is_null($p_value)) {
  1101. $p_value = $this->m_data['Published'];
  1102. }
  1103. if ( ($p_value != 'Y') && ($p_value != 'S') && ($p_value != 'N') && $p_value != 'M') {
  1104. return '';
  1105. }
  1106. switch ($p_value) {
  1107. case 'Y':
  1108. return getGS("Published");
  1109. case 'M':
  1110. return getGS('Publish with issue');
  1111. case 'S':
  1112. return getGS("Submitted");
  1113. case 'N':
  1114. return getGS("New");
  1115. }
  1116. } // fn getWorkflowDisplayString
  1117. /**
  1118. * Set the workflow state of the article.
  1119. * 'Y' = 'Published'
  1120. * 'S' = 'Submitted'
  1121. * 'N' = 'New'
  1122. *
  1123. * @param string $p_value
  1124. * @return boolean
  1125. */
  1126. public function setWorkflowStatus($p_value)
  1127. {
  1128. require_once($GLOBALS['g_campsiteDir'].'/classes/ArticleIndex.php');
  1129. $p_value = strtoupper($p_value);
  1130. if ( ($p_value != 'Y') && ($p_value != 'S') && ($p_value != 'N') && ($p_value != 'M')) {
  1131. return false;
  1132. }
  1133. // If the article is being published
  1134. if ( ($this->getWorkflowStatus() != 'Y') && ($p_value == 'Y') ) {
  1135. $this->setProperty('PublishDate', 'NOW()', true, true);
  1136. }
  1137. // Unlock the article if it changes status.
  1138. if ( $this->getWorkflowStatus() != $p_value ) {
  1139. $this->setIsLocked(false);
  1140. }
  1141. if ($p_value == 'Y' || $p_value == 'M') {
  1142. $issueObj = new Issue($this->getPublicationId(), $this->getLanguageId(),
  1143. $this->getIssueNumber());
  1144. if (!$issueObj->exists()) {
  1145. return false;
  1146. }
  1147. $p_value = $issueObj->isPublished() ? 'Y' : 'M';
  1148. }
  1149. $oldStatus = $this->getWorkflowStatus();
  1150. if (!parent::setProperty('Published', $p_value)) {
  1151. return false;
  1152. }
  1153. CampCache::singleton()->clear('user');
  1154. if (function_exists("camp_load_translation_strings")) {
  1155. camp_load_translation_strings("api");
  1156. }
  1157. $logtext = getGS('Article #$1 "$2" status changed from $3 to $4.',
  1158. $this->m_data['Number'], $this->m_data['Name'],
  1159. $this->getWorkflowDisplayString($oldStatus), $this->getWorkflowDisplayString($p_value))
  1160. ." (".getGS("Publication")." ".$this->m_data['IdPublication'].", "
  1161. ." ".getGS("Issue")." ".$this->m_data['NrIssue'].", "
  1162. ." ".getGS("Section")." ".$this->m_data['NrSection'].")";
  1163. Log::Message($logtext, null, 35);
  1164. return true;
  1165. } // fn setWorkflowStatus
  1166. /**
  1167. * Get the date the article was published.
  1168. * @return string
  1169. */
  1170. public function getPublishDate()
  1171. {
  1172. return $this->m_data['PublishDate'];
  1173. } // fn getPublishDate
  1174. /**
  1175. * Set the date the article was published, parameter must be in the
  1176. * form YYYY-MM-DD.
  1177. * @param string $p_value
  1178. * @return boolean
  1179. */
  1180. public function setPublishDate($p_value)
  1181. {
  1182. return $this->setProperty('PublishDate', $p_value);
  1183. } // fn setPublishDate
  1184. /**
  1185. * Return the date the article was created in the
  1186. * form YYYY-MM-DD HH:MM:SS.
  1187. *
  1188. * @return string
  1189. */
  1190. public function getCreationDate()
  1191. {
  1192. return $this->m_data['UploadDate'];
  1193. } // fn getCreationDate
  1194. /**
  1195. * Set the date the article was created, parameter must be in the
  1196. * form YYYY-MM-DD.
  1197. * @param string $p_value
  1198. * @return boolean
  1199. */
  1200. public function setCreationDate($p_value)
  1201. {
  1202. return $this->setProperty('UploadDate', $p_value);
  1203. } // fn setCreationDate
  1204. /**
  1205. * Return the date the article was last modified in the
  1206. * form YYYY-MM-DD HH:MM:SS.
  1207. *
  1208. * @return string
  1209. */
  1210. public function getLastModified()
  1211. {
  1212. // Deal with the differences between MySQL 4
  1213. // and MySQL 5.
  1214. if (strpos($this->m_data['time_updated'], "-") === false) {
  1215. $t = $this->m_data['time_updated'];
  1216. $str = substr($t, 0, 4).'-'.substr($t, 4, 2)
  1217. .'-'.substr($t, 6, 2).' '.substr($t, 8, 2)
  1218. .':'.substr($t, 10, 2).':'.substr($t, 12);
  1219. return $str;
  1220. } else {
  1221. return $this->m_data['time_updated'];
  1222. }
  1223. } // fn getLastModified
  1224. /**
  1225. * @return string
  1226. */
  1227. public function getKeywords()
  1228. {
  1229. require_once($GLOBALS['g_campsiteDir'].'/classes/SystemPref.php');
  1230. $keywords = $this->m_data['Keywords'];
  1231. $keywordSeparator = SystemPref::Get("KeywordSeparator");
  1232. return str_replace(",", $keywordSeparator, $keywords);
  1233. } // fn getKeywords
  1234. public function getReads() {
  1235. if (!$this->exists()) {
  1236. return null;
  1237. }
  1238. if (empty($this->m_data['object_id'])) {
  1239. return 0;
  1240. }
  1241. $requestObject = new RequestObject($this->m_data['object_id']);
  1242. return $requestObject->getRequestCount();
  1243. }
  1244. /**
  1245. * @param string $p_value
  1246. * @return boolean
  1247. */
  1248. public function setKeywords($p_value)
  1249. {
  1250. require_once($GLOBALS['g_campsiteDir'].'/classes/SystemPref.php');
  1251. $keywordsSeparator = SystemPref::Get('KeywordSeparator');
  1252. $p_value = str_replace($keywordsSeparator, ",", $p_value);
  1253. return parent::setProperty('Keywords', $p_value);
  1254. } // fn setKeywords
  1255. /**
  1256. * Return TRUE if this article was published.
  1257. *
  1258. * @return boolean
  1259. */
  1260. public function isPublished()
  1261. {
  1262. return ($this->m_data['Published'] == 'Y');
  1263. } // fn isPublic
  1264. /**
  1265. * Return TRUE if this article is viewable by non-subscribers.
  1266. *
  1267. * @return boolean
  1268. */
  1269. public function isPublic()
  1270. {
  1271. return ($this->m_data['Public'] == 'Y');
  1272. } // fn isPublic
  1273. /**
  1274. * Set whether this article is viewable by non-subscribers.
  1275. *
  1276. * @param boolean $p_value
  1277. * @return boolean
  1278. */
  1279. public function setIsPublic($p_value)
  1280. {
  1281. return parent::setProperty('Public', $p_value?'Y':'N');
  1282. } // fn setIsPublic
  1283. /**
  1284. * @return boolean
  1285. */
  1286. public function isIndexed()
  1287. {
  1288. return ($this->m_data['IsIndexed'] == 'Y');
  1289. } // fn isIndexed
  1290. /**
  1291. * @param boolean value
  1292. */
  1293. public function setIsIndexed($p_value)
  1294. {
  1295. return parent::setProperty('IsIndexed', $p_value?'Y':'N');
  1296. } // fn setIsIndexed
  1297. /**
  1298. * Return the user ID of the user who has locked the article.
  1299. * @return int
  1300. */
  1301. public function getLockedByUser()
  1302. {
  1303. return $this->m_data['LockUser'];
  1304. } // fn getLockedByUser
  1305. /**
  1306. * Get the URL name for this article.
  1307. *
  1308. * @return string
  1309. */
  1310. public function getUrlName()
  1311. {
  1312. return $this->m_data['ShortName'];
  1313. } // fn getUrlName
  1314. /**
  1315. * @param string value
  1316. */
  1317. public function setUrlName($p_value)
  1318. {
  1319. return parent::setProperty('ShortName', $p_value);
  1320. } // fn setUrlName
  1321. /**
  1322. * Return the ArticleData object for this article.
  1323. *
  1324. * @return ArticleData
  1325. */
  1326. public function getArticleData()
  1327. {
  1328. return new ArticleData($this->m_data['Type'],
  1329. $this->m_data['Number'],
  1330. $this->m_data['IdLanguage']);
  1331. } // fn getArticleData
  1332. /**
  1333. * Return TRUE if comments have been activated.
  1334. *
  1335. * @return boolean
  1336. */
  1337. public function commentsEnabled()
  1338. {
  1339. return $this->m_data['comments_enabled'];
  1340. } // fn commentsEnabled
  1341. /**
  1342. * Set whether comments are enabled for this article.
  1343. *
  1344. * @param boolean $p_value
  1345. * @return boolean
  1346. */
  1347. public function setCommentsEnabled($p_value)
  1348. {
  1349. $p_value = $p_value ? '1' : '0';
  1350. return $this->setProperty('comments_enabled', $p_value);
  1351. } // fn setCommentsEnabled
  1352. /**
  1353. * Return TRUE if comments are locked for this article.
  1354. * This means that comments cannot be added.
  1355. *
  1356. * @return boolean
  1357. */
  1358. public function commentsLocked()
  1359. {
  1360. return $this->m_data['comments_locked'];
  1361. } // fn commentsLocked
  1362. /**
  1363. * Set whether comments are locked for this article.
  1364. * If TRUE, this means that comments cannot be added to
  1365. * the article.
  1366. *
  1367. * @param boolean $p_value
  1368. * @return boolean
  1369. */
  1370. public function setCommentsLocked($p_value)
  1371. {
  1372. $p_value = $p_value ? '1' : '0';
  1373. return $this->setProperty('comments_locked', $p_value);
  1374. } // fn setCommentsLocked
  1375. /*****************************************************************/
  1376. /** Static Functions */
  1377. /*****************************************************************/
  1378. /**
  1379. * Set the article workflow on issue status change. Articles to be
  1380. * published with the issue will be published on article publish.
  1381. * Published articles are set to "publish with issue" on issue
  1382. * unpublish.
  1383. *
  1384. * @param int $p_publicationId
  1385. * @param int $p_languageId
  1386. * @param int $p_issueNo
  1387. * @param int $p_publish
  1388. */
  1389. public static function OnIssuePublish($p_publicationId, $p_languageId,
  1390. $p_issueNo, $p_publish = true)
  1391. {
  1392. global $g_ado_db;
  1393. settype($p_publicationId, 'integer');
  1394. settype($p_languageId, 'integer');
  1395. settype($p_issueNo, 'integer');
  1396. $issueObj = new Issue($p_publicationId, $p_languageId, $p_issueNo);
  1397. if (!$issueObj->exists()) {
  1398. return false;
  1399. }
  1400. if (($issueObj->isPublished() && $p_publish)
  1401. || (!$issueObj->isPublished() && !$p_publish)) {
  1402. return false;
  1403. }
  1404. $fromState = $p_publish ? 'M' : 'Y';
  1405. $toState = $p_publish ? 'Y' : 'M';
  1406. $sql = "UPDATE Articles SET Published = '$toState' WHERE "
  1407. . "IdPublication = $p_publicationId AND IdLanguage = $p_languageId"
  1408. . " AND NrIssue = $p_issueNo AND Published = '$fromState'";
  1409. $res = $g_ado_db->Execute($sql);
  1410. CampCache::singleton()->clear('user');
  1411. return $res;
  1412. }
  1413. /**
  1414. * Return an Article object having the given number
  1415. * in the given publication, issue, section, language.
  1416. *
  1417. * @param int $p_articleNr
  1418. * The article number
  1419. * @param int $p_publicationId
  1420. * The publication identifier
  1421. * @param int $p_issueNr
  1422. * The issue number
  1423. * @param int $p_sectionNr
  1424. * The section number
  1425. * @param int $p_languageId
  1426. * The language identifier
  1427. *
  1428. * @return object|null
  1429. * An article object on success, null on failure
  1430. */
  1431. public static function GetByNumber($p_articleNr, $p_publicationId, $p_issueNr,
  1432. $p_sectionNr, $p_languageId)
  1433. {
  1434. global $g_ado_db;
  1435. $queryStr = 'SELECT * FROM Articles '
  1436. .'WHERE IdPublication='.$p_publicationId
  1437. .' AND NrIssue='.$p_issueNr
  1438. .' AND NrSection='.$p_sectionNr
  1439. .' AND IdLanguage='.$p_languageId
  1440. .' AND Number='.$p_articleNr;
  1441. $result = DbObjectArray::Create('Article', $queryStr);
  1442. return (is_array($result) && sizeof($result)) ? $result[0] : null;
  1443. } // fn GetByNumber
  1444. /**
  1445. * Return an array of article having the given name
  1446. * in the given publication / issue / section / language.
  1447. *
  1448. * @param string $p_name
  1449. * @param int $p_publicationId
  1450. * @param int $p_issueId
  1451. * @param int $p_sectionId
  1452. * @param int $p_languageId
  1453. *
  1454. * @return array
  1455. */
  1456. public static function GetByName($p_name, $p_publicationId = null, $p_issueId = null,
  1457. $p_sectionId = null, $p_languageId = null, $p_skipCache = false)
  1458. {
  1459. global $g_ado_db;
  1460. $queryStr = 'SELECT * FROM Articles';
  1461. $whereClause = array();
  1462. if (!is_null($p_publicationId)) {
  1463. $whereClause[] = "IdPublication=$p_publicationId";
  1464. }
  1465. if (!is_null($p_issueId)) {
  1466. $whereClause[] = "NrIssue=$p_issueId";
  1467. }
  1468. if (!is_null($p_sectionId)) {
  1469. $whereClause[] = "NrSection=$p_sectionId";
  1470. }
  1471. if (!is_null($p_languageId)) {
  1472. $whereClause[] = "IdLanguage=$p_languageId";
  1473. }
  1474. $whereClause[] = "Name='" . $g_ado_db->escape($p_name) . "'";
  1475. if (count($whereClause) > 0) {
  1476. $queryStr .= ' WHERE ' . implode(' AND ', $whereClause);
  1477. }
  1478. if (!$p

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