1: <?php
2: namespace Opencart\Admin\Model\Cms;
3: /**
4: * Class Article
5: *
6: * @package Opencart\Admin\Model\Cms
7: */
8: class Article extends \Opencart\System\Engine\Model {
9: /**
10: * Add Article
11: *
12: * @param array<string, mixed> $data
13: *
14: * @return int
15: */
16: public function addArticle(array $data): int {
17: $this->db->query("INSERT INTO `" . DB_PREFIX . "article` SET `topic_id` = '" . (int)$data['topic_id'] . "', `author` = '" . $this->db->escape($data['author']) . "', `status` = '" . (bool)($data['status'] ?? 0) . "', `date_added` = NOW(), `date_modified` = NOW()");
18:
19: $article_id = $this->db->getLastId();
20:
21: // Description
22: foreach ($data['article_description'] as $language_id => $value) {
23: $this->model_cms_article->addDescription($article_id, $language_id, $value);
24: }
25:
26: // Store
27: if (isset($data['article_store'])) {
28: foreach ($data['article_store'] as $store_id) {
29: $this->model_cms_article->addStore($article_id, $store_id);
30: }
31: }
32:
33: // SEO URL
34: $this->load->model('design/seo_url');
35:
36: foreach ($data['article_seo_url'] as $store_id => $language) {
37: foreach ($language as $language_id => $keyword) {
38: $this->model_design_seo_url->addSeoUrl('article_id', $article_id, $keyword, $store_id, $language_id);
39: }
40: }
41:
42: // Layouts
43: if (isset($data['article_layout'])) {
44: foreach ($data['article_layout'] as $store_id => $layout_id) {
45: if ($layout_id) {
46: $this->model_cms_article->addLayout($article_id, $store_id, $layout_id);
47: }
48: }
49: }
50:
51: $this->cache->delete('article');
52:
53: return $article_id;
54: }
55:
56: /**
57: * Edit Article
58: *
59: * @param int $article_id
60: * @param array<string, mixed> $data
61: *
62: * @return void
63: */
64: public function editArticle(int $article_id, array $data): void {
65: $this->db->query("UPDATE `" . DB_PREFIX . "article` SET `topic_id` = '" . (int)$data['topic_id'] . "', `author` = '" . $this->db->escape($data['author']) . "', `status` = '" . (bool)($data['status'] ?? 0) . "', `date_modified` = NOW() WHERE `article_id` = '" . (int)$article_id . "'");
66:
67: // Description
68: $this->model_cms_article->deleteDescriptions($article_id);
69:
70: foreach ($data['article_description'] as $language_id => $value) {
71: $this->model_cms_article->addDescription($article_id, $language_id, $value);
72: }
73:
74: // Store
75: $this->model_cms_article->deleteStores($article_id);
76:
77: if (isset($data['article_store'])) {
78: foreach ($data['article_store'] as $store_id) {
79: $this->model_cms_article->addStore($article_id, $store_id);
80: }
81: }
82:
83: // SEO URL
84: $this->load->model('design/seo_url');
85:
86: $this->model_design_seo_url->deleteSeoUrlsByKeyValue('article_id', $article_id);
87:
88: foreach ($data['article_seo_url'] as $store_id => $language) {
89: foreach ($language as $language_id => $keyword) {
90: $this->model_design_seo_url->addSeoUrl('article_id', $article_id, $keyword, $store_id, $language_id);
91: }
92: }
93:
94: // Layouts
95: $this->model_cms_article->deleteLayouts($article_id);
96:
97: if (isset($data['article_layout'])) {
98: foreach ($data['article_layout'] as $store_id => $layout_id) {
99: if ($layout_id) {
100: $this->model_cms_article->addLayout($article_id, $store_id, $layout_id);
101: }
102: }
103: }
104:
105: $this->cache->delete('article');
106: }
107:
108: /**
109: * Edit Rating
110: *
111: * @param int $article_id
112: * @param int $rating
113: */
114: public function editRating(int $article_id, int $rating): void {
115: $this->db->query("UPDATE `" . DB_PREFIX . "article` SET `rating` = '" . (int)$rating . "' WHERE `article_id` = '" . (int)$article_id . "'");
116: }
117:
118: /**
119: * Delete Article
120: *
121: * @param int $article_id
122: *
123: * @return void
124: */
125: public function deleteArticle(int $article_id): void {
126: $this->db->query("DELETE FROM `" . DB_PREFIX . "article` WHERE `article_id` = '" . (int)$article_id . "'");
127:
128: $this->model_cms_article->deleteDescriptions($article_id);
129: $this->model_cms_article->deleteStores($article_id);
130: $this->model_cms_article->deleteLayouts($article_id);
131: $this->model_cms_article->deleteCommentsByArticleId($article_id);
132:
133: $this->load->model('design/seo_url');
134:
135: $this->model_design_seo_url->deleteSeoUrlsByKeyValue('article_id', $article_id);
136:
137: $this->cache->delete('article');
138: }
139:
140: /**
141: * Get Article
142: *
143: * @param int $article_id
144: *
145: * @return array<string, mixed>
146: */
147: public function getArticle(int $article_id): array {
148: $query = $this->db->query("SELECT DISTINCT * FROM `" . DB_PREFIX . "article` `a` LEFT JOIN `" . DB_PREFIX . "article_description` `ad` ON (`a`.`article_id` = `ad`.`article_id`) WHERE `a`.`article_id` = '" . (int)$article_id . "' AND `ad`.`language_id` = '" . (int)$this->config->get('config_language_id') . "'");
149:
150: return $query->row;
151: }
152:
153: /**
154: * Get Articles
155: *
156: * @param array<string, mixed> $data
157: *
158: * @return array<int, array<string, mixed>>
159: */
160: public function getArticles(array $data = []): array {
161: $sql = "SELECT * FROM `" . DB_PREFIX . "article` `a` LEFT JOIN `" . DB_PREFIX . "article_description` `ad` ON (`a`.`article_id` = `ad`.`article_id`) WHERE `ad`.`language_id` = '" . (int)$this->config->get('config_language_id') . "'";
162:
163: if (!empty($data['filter_name'])) {
164: $sql .= " AND LCASE(`ad`.`name`) LIKE '" . $this->db->escape(oc_strtolower($data['filter_name'])) . "'";
165: }
166:
167: $sort_data = [
168: 'ad.name',
169: 'a.author',
170: 'a.rating',
171: 'a.date_added'
172: ];
173:
174: if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
175: $sql .= " ORDER BY " . $data['sort'];
176: } else {
177: $sql .= " ORDER BY `a`.`date_added`";
178: }
179:
180: if (isset($data['order']) && ($data['order'] == 'DESC')) {
181: $sql .= " DESC";
182: } else {
183: $sql .= " ASC";
184: }
185:
186: if (isset($data['start']) || isset($data['limit'])) {
187: if ($data['start'] < 0) {
188: $data['start'] = 0;
189: }
190:
191: if ($data['limit'] < 1) {
192: $data['limit'] = 20;
193: }
194:
195: $sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit'];
196: }
197:
198: $key = md5($sql);
199:
200: $article_data = $this->cache->get('article.' . $key);
201:
202: if (!$article_data) {
203: $query = $this->db->query($sql);
204:
205: $article_data = $query->rows;
206:
207: $this->cache->set('article.' . $key, $article_data);
208: }
209:
210: return $article_data;
211: }
212:
213: /**
214: * Get Total Articles
215: *
216: * @param array<string, mixed> $data
217: *
218: * @return int
219: */
220: public function getTotalArticles(array $data = []): int {
221: $sql = "SELECT COUNT(*) AS `total` FROM `" . DB_PREFIX . "article`";
222:
223: if (!empty($data['filter_name'])) {
224: $sql .= " AND LCASE(`name`) LIKE '" . $this->db->escape(oc_strtolower($data['filter_name'])) . "'";
225: }
226:
227: $query = $this->db->query($sql);
228:
229: return (int)$query->row['total'];
230: }
231:
232: /**
233: * Add Description
234: *
235: * @param int $article_id
236: * @param int $language_id
237: * @param array<string, mixed> $data
238: *
239: * @return void
240: */
241: public function addDescription(int $article_id, int $language_id, array $data): void {
242: $this->db->query("INSERT INTO `" . DB_PREFIX . "article_description` SET `article_id` = '" . (int)$article_id . "', `language_id` = '" . (int)$language_id . "', `image` = '" . $this->db->escape($data['image']) . "', `name` = '" . $this->db->escape($data['name']) . "', `description` = '" . $this->db->escape($data['description']) . "', `tag` = '" . $this->db->escape($data['tag']) . "', `meta_title` = '" . $this->db->escape($data['meta_title']) . "', `meta_description` = '" . $this->db->escape($data['meta_description']) . "', `meta_keyword` = '" . $this->db->escape($data['meta_keyword']) . "'");
243: }
244:
245: /**
246: * Delete Descriptions
247: *
248: * @param int $article_id
249: *
250: * @return void
251: */
252: public function deleteDescriptions(int $article_id): void {
253: $this->db->query("DELETE FROM `" . DB_PREFIX . "article_description` WHERE `article_id` = '" . (int)$article_id . "'");
254: }
255:
256: /**
257: * Delete Descriptions By Language ID
258: *
259: * @param int $language_id
260: *
261: * @return void
262: */
263: public function deleteDescriptionsByLanguageId(int $language_id): void {
264: $this->db->query("DELETE FROM `" . DB_PREFIX . "article_description` WHERE `language_id` = '" . (int)$language_id . "'");
265: }
266:
267: /**
268: * Get Descriptions
269: *
270: * @param int $article_id
271: *
272: * @return array<int, array<string, mixed>>
273: */
274: public function getDescriptions(int $article_id): array {
275: $article_description_data = [];
276:
277: $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "article_description` WHERE `article_id` = '" . (int)$article_id . "'");
278:
279: foreach ($query->rows as $result) {
280: $article_description_data[$result['language_id']] = [
281: 'image' => $result['image'],
282: 'name' => $result['name'],
283: 'description' => $result['description'],
284: 'tag' => $result['tag'],
285: 'meta_title' => $result['meta_title'],
286: 'meta_description' => $result['meta_description'],
287: 'meta_keyword' => $result['meta_keyword']
288: ];
289: }
290:
291: return $article_description_data;
292: }
293:
294: /**
295: * Get Descriptions By Language ID
296: *
297: * @param int $language_id
298: *
299: * @return array<int, array<string, string>>
300: */
301: public function getDescriptionsByLanguageId(int $language_id): array {
302: $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "article_description` WHERE `language_id` = '" . (int)$language_id . "'");
303:
304: return $query->rows;
305: }
306:
307: /**
308: * Add Store
309: *
310: * @param int $article_id
311: * @param int $store_id
312: *
313: * @return void
314: */
315: public function addStore(int $article_id, int $store_id): void {
316: $this->db->query("INSERT INTO `" . DB_PREFIX . "article_to_store` SET `article_id` = '" . (int)$article_id . "', `store_id` = '" . (int)$store_id . "'");
317: }
318:
319: /**
320: * Delete Stores
321: *
322: * @param int $article_id
323: *
324: * @return void
325: */
326: public function deleteStores(int $article_id): void {
327: $this->db->query("DELETE FROM `" . DB_PREFIX . "article_to_store` WHERE `article_id` = '" . (int)$article_id . "'");
328: }
329:
330: /**
331: * Get Stores
332: *
333: * @param int $article_id
334: *
335: * @return array<int, int>
336: */
337: public function getStores(int $article_id): array {
338: $article_store_data = [];
339:
340: $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "article_to_store` WHERE `article_id` = '" . (int)$article_id . "'");
341:
342: foreach ($query->rows as $result) {
343: $article_store_data[] = $result['store_id'];
344: }
345:
346: return $article_store_data;
347: }
348:
349: /**
350: * Add Layout
351: *
352: * @param int $article_id
353: * @param int $store_id
354: * @param int $layout_id
355: *
356: * @return void
357: */
358: public function addLayout(int $article_id, int $store_id, int $layout_id): void {
359: $this->db->query("INSERT INTO `" . DB_PREFIX . "article_to_layout` SET `article_id` = '" . (int)$article_id . "', store_id = '" . (int)$store_id . "', `layout_id` = '" . (int)$layout_id . "'");
360: }
361:
362: /**
363: * Delete Layouts
364: *
365: * @param int $article_id
366: *
367: * @return void
368: */
369: public function deleteLayouts(int $article_id): void {
370: $this->db->query("DELETE FROM `" . DB_PREFIX . "article_to_layout` WHERE `article_id` = '" . (int)$article_id . "'");
371: }
372:
373: /**
374: * Delete Layouts By Layout ID
375: *
376: * @param int $layout_id
377: *
378: * @return void
379: */
380: public function deleteLayoutsByLayoutId(int $layout_id): void {
381: $this->db->query("DELETE FROM `" . DB_PREFIX . "article_to_layout` WHERE `layout_id` = '" . (int)$layout_id . "'");
382: }
383:
384: /**
385: * Get Layouts
386: *
387: * @param int $article_id
388: *
389: * @return array<int, int>
390: */
391: public function getLayouts(int $article_id): array {
392: $article_layout_data = [];
393:
394: $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "article_to_layout` WHERE `article_id` = '" . (int)$article_id . "'");
395:
396: foreach ($query->rows as $result) {
397: $article_layout_data[$result['store_id']] = $result['layout_id'];
398: }
399:
400: return $article_layout_data;
401: }
402:
403: /**
404: * Get Total Layouts By Layout ID
405: *
406: * @param int $layout_id
407: *
408: * @return int
409: */
410: public function getTotalLayoutsByLayoutId(int $layout_id): int {
411: $query = $this->db->query("SELECT COUNT(*) AS `total` FROM `" . DB_PREFIX . "article_to_layout` WHERE `layout_id` = '" . (int)$layout_id . "'");
412:
413: return (int)$query->row['total'];
414: }
415:
416: /**
417: * Edit Comment Status
418: *
419: * @param int $article_comment_id
420: * @param bool $status
421: *
422: * @return void
423: */
424: public function editCommentStatus(int $article_comment_id, bool $status): void {
425: $this->db->query("UPDATE `" . DB_PREFIX . "article_comment` SET `status` = '" . (bool)$status . "' WHERE `article_comment_id` = '" . (int)$article_comment_id . "'");
426:
427: $this->cache->delete('topic');
428: }
429:
430: /**
431: * Edit Comment Rating
432: *
433: * @param int $article_id
434: * @param int $article_comment_id
435: * @param int $rating
436: */
437: public function editCommentRating(int $article_id, int $article_comment_id, int $rating): void {
438: $this->db->query("UPDATE `" . DB_PREFIX . "article_comment` SET `rating` = '" . (int)$rating . "' WHERE `article_comment_id` = '" . (int)$article_comment_id . "' AND `article_id` = '" . (int)$article_id . "'");
439: }
440:
441: /**
442: * Delete Comment
443: *
444: * @param int $article_comment_id
445: *
446: * @return void
447: */
448: public function deleteComment(int $article_comment_id): void {
449: $this->db->query("DELETE FROM `" . DB_PREFIX . "article_comment` WHERE `article_comment_id` = '" . (int)$article_comment_id . "'");
450:
451: $this->cache->delete('topic');
452: }
453:
454: /**
455: * Delete Comments by article ID
456: *
457: * @param int $article_id
458: *
459: * @return void
460: */
461: public function deleteCommentsByArticleId(int $article_id): void {
462: $this->db->query("DELETE FROM `" . DB_PREFIX . "article_comment` WHERE `article_id` = '" . (int)$article_id . "'");
463:
464: $this->cache->delete('topic');
465: }
466:
467: /**
468: * Get Comment
469: *
470: * @param int $article_comment_id
471: *
472: * @return array<string, mixed>
473: */
474: public function getComment(int $article_comment_id): array {
475: $query = $this->db->query("SELECT DISTINCT * FROM `" . DB_PREFIX . "article_comment` WHERE `article_comment_id` = '" . (int)$article_comment_id . "'");
476:
477: return $query->row;
478: }
479:
480: /**
481: * Get Ratings
482: *
483: * @param int $article_id
484: * @param int $article_comment_id
485: *
486: * @return array<int, array<string, mixed>>
487: */
488: public function getRatings(int $article_id, int $article_comment_id = 0): array {
489: $sql = "SELECT rating, COUNT(*) AS total FROM `" . DB_PREFIX . "article_rating` WHERE `article_id` = '" . (int)$article_id . "'";
490:
491: if ($article_comment_id) {
492: $sql .= " AND `article_comment_id` = '" . (int)$article_comment_id . "'";
493: }
494:
495: $sql .= " GROUP BY rating";
496:
497: $query = $this->db->query($sql);
498:
499: return $query->rows;
500: }
501:
502: /**
503: * Get Comments
504: *
505: * @param array<string, mixed> $data
506: *
507: * @return array<int, array<string, mixed>>
508: */
509: public function getComments(array $data = []): array {
510: $sql = "SELECT *, `ac`.`rating`, `ac`.`status`, `ac`.`date_added` FROM `" . DB_PREFIX . "article_comment` `ac` LEFT JOIN `" . DB_PREFIX . "article` `a` ON (`ac`.`article_id` = `a`.`article_id`) LEFT JOIN `" . DB_PREFIX . "article_description` `ad` ON (`ac`.`article_id` = `ad`.`article_id`)";
511:
512: $implode = [];
513:
514: if (!empty($data['filter_keyword'])) {
515: $implode[] = "LCASE(`ac`.`comment`) LIKE '" . $this->db->escape('%' . oc_strtolower($data['filter_keyword']) . '%') . "'";
516: }
517:
518: if (!empty($data['filter_article'])) {
519: $implode[] = "LCASE(`ad`.`name`) LIKE '" . $this->db->escape(oc_strtolower($data['filter_article']) . '%') . "'";
520: }
521:
522: if (!empty($data['filter_customer_id'])) {
523: $implode[] = "`ac`.`customer_id` = '" . (int)$data['filter_customer_id'] . "'";
524: }
525:
526: if (!empty($data['filter_author'])) {
527: $implode[] = "LCASE(`ac`.`author`) LIKE '" . $this->db->escape(oc_strtolower($data['filter_author']) . '%') . "'";
528: }
529:
530: if (!empty($data['filter_status'])) {
531: $implode[] = "`ac`.`status` = '" . (bool)$data['filter_status'] . "'";
532: }
533:
534: if (!empty($data['filter_date_added'])) {
535: $implode[] = "DATE(`ac`.`date_added`) = DATE('" . $this->db->escape($data['filter_date_added']) . "')";
536: }
537:
538: if ($implode) {
539: $sql .= " WHERE " . implode(" AND ", $implode);
540: }
541:
542: $sql .= " ORDER BY `ac`.`date_added` DESC";
543:
544: if (isset($data['start']) || isset($data['limit'])) {
545: if ($data['start'] < 0) {
546: $data['start'] = 0;
547: }
548:
549: if ($data['limit'] < 1) {
550: $data['limit'] = 20;
551: }
552:
553: $sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit'];
554: }
555:
556: $query = $this->db->query($sql);
557:
558: return $query->rows;
559: }
560:
561: /**
562: * Get Total Comments
563: *
564: * @param array<string, mixed> $data
565: *
566: * @return int
567: */
568: public function getTotalComments(array $data = []): int {
569: $sql = "SELECT COUNT(*) AS `total` FROM `" . DB_PREFIX . "article_comment` `ac` LEFT JOIN `" . DB_PREFIX . "article` `a` ON (`ac`.`article_id` = `a`.`article_id`)";
570:
571: $implode = [];
572:
573: if (!empty($data['filter_keyword'])) {
574: $implode[] = "LCASE(`ac`.`comment`) LIKE '" . $this->db->escape('%' . oc_strtolower($data['filter_keyword']) . '%') . "'";
575: }
576:
577: if (!empty($data['filter_article'])) {
578: $implode[] = "LCASE(`ad`.`name`) LIKE '" . $this->db->escape(oc_strtolower($data['filter_article']) . '%') . "'";
579: }
580:
581: if (!empty($data['filter_customer_id'])) {
582: $implode[] = "`ac`.`customer_id` = '" . (int)$data['filter_customer_id'] . "'";
583: }
584:
585: if (!empty($data['filter_author'])) {
586: $implode[] = "LCASE(`ac`.`author`) LIKE '" . $this->db->escape(oc_strtolower($data['filter_author']) . '%') . "'";
587: }
588:
589: if (!empty($data['filter_status'])) {
590: $implode[] = "`ac`.`status` = '" . (bool)$data['filter_status'] . "'";
591: }
592:
593: if (!empty($data['filter_date_added'])) {
594: $implode[] = "DATE(`ac`.`date_added`) = DATE('" . $this->db->escape($data['filter_date_added']) . "')";
595: }
596:
597: if ($implode) {
598: $sql .= " WHERE " . implode(" AND ", $implode);
599: }
600:
601: $query = $this->db->query($sql);
602:
603: return (int)$query->row['total'];
604: }
605: }
606: