publication.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <?php
  2. /**
  3. * Publication Model Class
  4. * Handles all publication-related database operations
  5. */
  6. class Publication {
  7. public $db;
  8. public function __construct() {
  9. $this->db = Database::getInstance();
  10. }
  11. public function getAll($status = 'published', $limit = null, $offset = 0) {
  12. $sql = "SELECT p.*, GROUP_CONCAT(c.name) as categories
  13. FROM publications p
  14. LEFT JOIN publication_categories pc ON p.id = pc.publication_id
  15. LEFT JOIN categories c ON pc.category_id = c.id";
  16. $params = [];
  17. if ($status !== 'all') {
  18. $sql .= " WHERE p.status = ?";
  19. $params[] = $status;
  20. }
  21. $sql .= " GROUP BY p.id ORDER BY p.created_at DESC";
  22. if ($limit) {
  23. $sql .= " LIMIT ? OFFSET ?";
  24. $params[] = (int)$limit;
  25. $params[] = (int)$offset;
  26. }
  27. return $this->db->fetchAll($sql, $params);
  28. }
  29. public function getById($id) {
  30. $sql = "SELECT p.*, GROUP_CONCAT(c.name) as categories
  31. FROM publications p
  32. LEFT JOIN publication_categories pc ON p.id = pc.publication_id
  33. LEFT JOIN categories c ON pc.category_id = c.id
  34. WHERE p.id = ?
  35. GROUP BY p.id";
  36. $publication = $this->db->fetch($sql, [$id]);
  37. if ($publication && $publication['categories']) {
  38. $publication['categories_array'] = explode(',', $publication['categories']);
  39. } else {
  40. $publication['categories_array'] = [];
  41. }
  42. return $publication;
  43. }
  44. public function getBySlug($slug) {
  45. // Try to get by slug first
  46. try {
  47. $sql = "SELECT p.*, GROUP_CONCAT(c.name) as categories
  48. FROM publications p
  49. LEFT JOIN publication_categories pc ON p.id = pc.publication_id
  50. LEFT JOIN categories c ON pc.category_id = c.id
  51. WHERE p.slug = ?
  52. GROUP BY p.id";
  53. $publication = $this->db->fetch($sql, [$slug]);
  54. } catch (Exception $e) {
  55. // If slug column doesn't exist, fall back to ID-based lookup
  56. if (strpos($e->getMessage(), "Unknown column 'slug'") !== false) {
  57. return $this->getById($slug);
  58. }
  59. throw $e;
  60. }
  61. if ($publication && $publication['categories']) {
  62. $publication['categories_array'] = explode(',', $publication['categories']);
  63. } else {
  64. $publication['categories_array'] = [];
  65. }
  66. return $publication;
  67. }
  68. public function create($data, $categories = []) {
  69. $this->db->beginTransaction();
  70. try {
  71. // Try to generate and add slug from title
  72. try {
  73. $slug = $this->generateSlug($data['title']);
  74. $data['slug'] = $slug;
  75. } catch (Exception $e) {
  76. // If slug column doesn't exist, skip slug generation
  77. if (strpos($e->getMessage(), "Unknown column 'slug'") === false) {
  78. throw $e;
  79. }
  80. // Continue without slug
  81. }
  82. // Set published_at if status is published
  83. if ($data['status'] === 'published' && !isset($data['published_at'])) {
  84. $data['published_at'] = date('Y-m-d H:i:s');
  85. }
  86. $publicationId = $this->db->insert('publications', $data);
  87. // Add categories
  88. if (!empty($categories)) {
  89. $this->updateCategories($publicationId, $categories);
  90. }
  91. $this->db->commit();
  92. return $publicationId;
  93. } catch (Exception $e) {
  94. $this->db->rollback();
  95. throw $e;
  96. }
  97. }
  98. public function update($id, $data, $categories = []) {
  99. $this->db->beginTransaction();
  100. try {
  101. // Try to update slug if title changed
  102. if (isset($data['title'])) {
  103. try {
  104. $data['slug'] = $this->generateSlug($data['title'], $id);
  105. } catch (Exception $e) {
  106. // If slug column doesn't exist, skip slug generation
  107. if (strpos($e->getMessage(), "Unknown column 'slug'") === false) {
  108. throw $e;
  109. }
  110. // Continue without slug
  111. }
  112. }
  113. // Set published_at if status changed to published
  114. if (isset($data['status']) && $data['status'] === 'published') {
  115. $current = $this->getById($id);
  116. if ($current['status'] !== 'published') {
  117. $data['published_at'] = date('Y-m-d H:i:s');
  118. }
  119. }
  120. $this->db->update('publications', $data, 'id = ?', [$id]);
  121. // Update categories if provided
  122. if (!empty($categories)) {
  123. $this->updateCategories($id, $categories);
  124. }
  125. $this->db->commit();
  126. return true;
  127. } catch (Exception $e) {
  128. $this->db->rollback();
  129. throw $e;
  130. }
  131. }
  132. public function delete($id) {
  133. $this->db->beginTransaction();
  134. try {
  135. // Delete category associations
  136. $this->db->delete('publication_categories', 'publication_id = ?', [$id]);
  137. // Delete publication
  138. $this->db->delete('publications', 'id = ?', [$id]);
  139. $this->db->commit();
  140. return true;
  141. } catch (Exception $e) {
  142. $this->db->rollback();
  143. throw $e;
  144. }
  145. }
  146. public function search($query, $status = 'published') {
  147. $sql = "SELECT p.*, GROUP_CONCAT(c.name) as categories
  148. FROM publications p
  149. LEFT JOIN publication_categories pc ON p.id = pc.publication_id
  150. LEFT JOIN categories c ON pc.category_id = c.id
  151. WHERE (p.title LIKE ? OR p.content LIKE ? OR p.summary LIKE ?)";
  152. $params = ["%$query%", "%$query%", "%$query%"];
  153. if ($status !== 'all') {
  154. $sql .= " AND p.status = ?";
  155. $params[] = $status;
  156. }
  157. $sql .= " GROUP BY p.id ORDER BY p.created_at DESC";
  158. return $this->db->fetchAll($sql, $params);
  159. }
  160. public function getByCategory($categoryName, $status = 'published') {
  161. $sql = "SELECT p.*, GROUP_CONCAT(c.name) as categories
  162. FROM publications p
  163. LEFT JOIN publication_categories pc ON p.id = pc.publication_id
  164. LEFT JOIN categories c ON pc.category_id = c.id
  165. WHERE c.name = ?";
  166. $params = [$categoryName];
  167. if ($status !== 'all') {
  168. $sql .= " AND p.status = ?";
  169. $params[] = $status;
  170. }
  171. $sql .= " GROUP BY p.id ORDER BY p.created_at DESC";
  172. return $this->db->fetchAll($sql, $params);
  173. }
  174. public function getCategories() {
  175. $sql = "SELECT c.*, COUNT(pc.publication_id) as publication_count
  176. FROM categories c
  177. LEFT JOIN publication_categories pc ON c.id = pc.category_id
  178. LEFT JOIN publications p ON pc.publication_id = p.id AND p.status = 'published'
  179. GROUP BY c.id
  180. ORDER BY c.name";
  181. return $this->db->fetchAll($sql);
  182. }
  183. private function updateCategories($publicationId, $categories) {
  184. // Delete existing category associations
  185. $this->db->delete('publication_categories', 'publication_id = ?', [$publicationId]);
  186. // Add new category associations
  187. foreach ($categories as $categoryId) {
  188. $this->db->insert('publication_categories', [
  189. 'publication_id' => $publicationId,
  190. 'category_id' => $categoryId
  191. ]);
  192. }
  193. }
  194. private function generateSlug($title, $excludeId = null) {
  195. $slug = strtolower($title);
  196. $slug = preg_replace('/[^a-z0-9]+/', '-', $slug);
  197. $slug = trim($slug, '-');
  198. // Check for uniqueness
  199. $sql = "SELECT COUNT(*) as count FROM publications WHERE slug = ?";
  200. $params = [$slug];
  201. if ($excludeId) {
  202. $sql .= " AND id != ?";
  203. $params[] = $excludeId;
  204. }
  205. $result = $this->db->fetch($sql, $params);
  206. if ($result['count'] > 0) {
  207. $slug .= '-' . time();
  208. }
  209. return $slug;
  210. }
  211. public function getStats() {
  212. $stats = [];
  213. $stats['total'] = $this->db->fetch("SELECT COUNT(*) as count FROM publications")['count'];
  214. $stats['published'] = $this->db->fetch("SELECT COUNT(*) as count FROM publications WHERE status = 'published'")['count'];
  215. $stats['draft'] = $this->db->fetch("SELECT COUNT(*) as count FROM publications WHERE status = 'draft'")['count'];
  216. $stats['archived'] = $this->db->fetch("SELECT COUNT(*) as count FROM publications WHERE status = 'archived'")['count'];
  217. return $stats;
  218. }
  219. }