class-qdr-tss-db-manager.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <?php
  2. /**
  3. * Database operations for the plugin.
  4. *
  5. * This class handles all database operations, including creating tables,
  6. * performing queries, and managing data.
  7. *
  8. * @package QDR_Temporary_Shared_Storage
  9. * @since 1.0.0
  10. */
  11. class QDR_TSS_DB_Manager {
  12. /**
  13. * The single instance of the class.
  14. *
  15. * @var QDR_TSS_DB_Manager
  16. * @since 1.0.0
  17. */
  18. protected static $_instance = null;
  19. /**
  20. * The database table name.
  21. *
  22. * @var string
  23. * @since 1.0.0
  24. */
  25. protected $table_name;
  26. /**
  27. * Main QDR_TSS_DB_Manager Instance.
  28. *
  29. * Ensures only one instance of QDR_TSS_DB_Manager is loaded or can be loaded.
  30. *
  31. * @since 1.0.0
  32. * @static
  33. * @return QDR_TSS_DB_Manager - Main instance.
  34. */
  35. public static function instance() {
  36. if (is_null(self::$_instance)) {
  37. self::$_instance = new self();
  38. }
  39. return self::$_instance;
  40. }
  41. /**
  42. * QDR_TSS_DB_Manager Constructor.
  43. */
  44. public function __construct() {
  45. global $wpdb;
  46. $this->table_name = $wpdb->prefix . QDR_TSS_PLUGIN_TABLE;
  47. }
  48. /**
  49. * Create the database table.
  50. *
  51. * @since 1.0.0
  52. * @return bool True on success, false on failure.
  53. */
  54. public function create_table() {
  55. global $wpdb;
  56. $charset_collate = $wpdb->get_charset_collate();
  57. $sql = "CREATE TABLE $this->table_name (
  58. id bigint(20) NOT NULL AUTO_INCREMENT,
  59. media_id bigint(20) NOT NULL,
  60. original_file_name varchar(255) NOT NULL,
  61. description text NULL,
  62. message text NULL,
  63. active_from datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
  64. active_to datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
  65. password varchar(255) NOT NULL,
  66. reference varchar(255) NULL,
  67. upload_date datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
  68. download_count int DEFAULT 0 NOT NULL,
  69. last_download datetime DEFAULT '0000-00-00 00:00:00' NULL,
  70. file_path varchar(255) NOT NULL,
  71. file_size bigint(20) NOT NULL,
  72. PRIMARY KEY (id),
  73. KEY media_id (media_id),
  74. KEY reference (reference),
  75. KEY active_to (active_to)
  76. ) $charset_collate;";
  77. require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
  78. return dbDelta($sql);
  79. }
  80. /**
  81. * Get an item by ID.
  82. *
  83. * @since 1.0.0
  84. * @param int $id The item ID.
  85. * @return object|null Database row as object or null if not found.
  86. */
  87. public function get_item($id) {
  88. global $wpdb;
  89. return $wpdb->get_row($wpdb->prepare("SELECT * FROM $this->table_name WHERE id = %d", $id));
  90. }
  91. /**
  92. * Get an item by media ID.
  93. *
  94. * @since 1.0.0
  95. * @param int $media_id The media ID.
  96. * @return object|null Database row as object or null if not found.
  97. */
  98. public function get_item_by_media_id($media_id) {
  99. global $wpdb;
  100. return $wpdb->get_row($wpdb->prepare("SELECT * FROM $this->table_name WHERE media_id = %d", $media_id));
  101. }
  102. /**
  103. * Get items with pagination and filtering.
  104. *
  105. * @since 1.0.0
  106. * @param array $args {
  107. * Optional. Arguments to retrieve items.
  108. *
  109. * @type int $per_page Number of items per page. Default 10.
  110. * @type int $page Page number. Default 1.
  111. * @type string $orderby Column to order by. Default 'upload_date'.
  112. * @type string $order Order direction. Default 'DESC'.
  113. * @type string $original_file_name Filter by file name.
  114. * @type string $reference Filter by reference.
  115. * }
  116. * @return array {
  117. * @type array $items The items.
  118. * @type int $total Total number of items.
  119. * @type int $total_pages Total number of pages.
  120. * }
  121. */
  122. public function get_items($args = array()) {
  123. global $wpdb;
  124. // Default arguments
  125. $defaults = array(
  126. 'per_page' => 10,
  127. 'page' => 1,
  128. 'orderby' => 'upload_date',
  129. 'order' => 'DESC',
  130. 'original_file_name' => '',
  131. 'reference' => ''
  132. );
  133. $args = wp_parse_args($args, $defaults);
  134. // Ensure valid values
  135. $args['per_page'] = absint($args['per_page']);
  136. $args['page'] = absint($args['page']);
  137. $args['order'] = strtoupper($args['order']) === 'ASC' ? 'ASC' : 'DESC';
  138. // Allowed columns for orderby
  139. $allowed_orderby_columns = array(
  140. 'media_id', 'original_file_name', 'description', 'active_from', 'active_to',
  141. 'reference', 'upload_date', 'download_count', 'last_download'
  142. );
  143. if (!in_array($args['orderby'], $allowed_orderby_columns)) {
  144. $args['orderby'] = 'upload_date';
  145. }
  146. // Build query
  147. $query = "SELECT * FROM $this->table_name";
  148. $count_query = "SELECT COUNT(*) FROM $this->table_name";
  149. $where_conditions = array();
  150. $query_values = array();
  151. // Filter by original_file_name
  152. if (!empty($args['original_file_name'])) {
  153. $where_conditions[] = "original_file_name LIKE %s";
  154. $query_values[] = '%' . $wpdb->esc_like($args['original_file_name']) . '%';
  155. }
  156. // Filter by reference
  157. if (!empty($args['reference'])) {
  158. $where_conditions[] = "reference LIKE %s";
  159. $query_values[] = '%' . $wpdb->esc_like($args['reference']) . '%';
  160. }
  161. // Add WHERE conditions if any
  162. if (!empty($where_conditions)) {
  163. $where_clause = " WHERE " . implode(" AND ", $where_conditions);
  164. $query .= $where_clause;
  165. $count_query .= $where_clause;
  166. }
  167. // Add ordering
  168. $query .= " ORDER BY {$args['orderby']} {$args['order']}";
  169. // Add pagination
  170. $offset = ($args['page'] - 1) * $args['per_page'];
  171. $query .= " LIMIT %d OFFSET %d";
  172. $query_values[] = $args['per_page'];
  173. $query_values[] = $offset;
  174. // Prepare and execute queries
  175. $items = $wpdb->get_results($wpdb->prepare($query, $query_values));
  176. $total_query_values = array_slice($query_values, 0, -2);
  177. $total = $wpdb->get_var($wpdb->prepare($count_query, $total_query_values));
  178. return array(
  179. 'items' => $items,
  180. 'total' => (int) $total,
  181. 'total_pages' => ceil($total / $args['per_page'])
  182. );
  183. }
  184. /**
  185. * Insert a new item.
  186. *
  187. * @since 1.0.0
  188. * @param array $data The item data.
  189. * @return int|false The item ID on success, false on failure.
  190. */
  191. public function insert_item($data) {
  192. global $wpdb;
  193. $result = $wpdb->insert(
  194. $this->table_name,
  195. $data,
  196. $this->get_column_formats($data)
  197. );
  198. return $result ? $wpdb->insert_id : false;
  199. }
  200. /**
  201. * Update an existing item.
  202. *
  203. * @since 1.0.0
  204. * @param int $id The item ID.
  205. * @param array $data The item data.
  206. * @return bool True on success, false on failure.
  207. */
  208. public function update_item($id, $data) {
  209. global $wpdb;
  210. return $wpdb->update(
  211. $this->table_name,
  212. $data,
  213. array('id' => $id),
  214. $this->get_column_formats($data),
  215. array('%d')
  216. );
  217. }
  218. /**
  219. * Update an item by media ID.
  220. *
  221. * @since 1.0.0
  222. * @param int $media_id The media ID.
  223. * @param array $data The item data.
  224. * @return bool True on success, false on failure.
  225. */
  226. public function update_item_by_media_id($media_id, $data) {
  227. global $wpdb;
  228. return $wpdb->update(
  229. $this->table_name,
  230. $data,
  231. array('media_id' => $media_id),
  232. $this->get_column_formats($data),
  233. array('%d')
  234. );
  235. }
  236. /**
  237. * Delete an item.
  238. *
  239. * @since 1.0.0
  240. * @param int $id The item ID.
  241. * @return bool True on success, false on failure.
  242. */
  243. public function delete_item($id) {
  244. global $wpdb;
  245. return $wpdb->delete(
  246. $this->table_name,
  247. array('id' => $id),
  248. array('%d')
  249. );
  250. }
  251. /**
  252. * Delete an item by media ID.
  253. *
  254. * @since 1.0.0
  255. * @param int $media_id The media ID.
  256. * @return bool True on success, false on failure.
  257. */
  258. public function delete_item_by_media_id($media_id) {
  259. global $wpdb;
  260. return $wpdb->delete(
  261. $this->table_name,
  262. array('media_id' => $media_id),
  263. array('%d')
  264. );
  265. }
  266. /**
  267. * Get expired items.
  268. *
  269. * @since 1.0.0
  270. * @return array Array of expired items.
  271. */
  272. public function get_expired_items() {
  273. global $wpdb;
  274. $current_time = current_time('mysql');
  275. return $wpdb->get_results($wpdb->prepare(
  276. "SELECT * FROM $this->table_name WHERE active_to < %s",
  277. $current_time
  278. ));
  279. }
  280. /**
  281. * Delete expired items.
  282. *
  283. * @since 1.0.0
  284. * @return int Number of deleted items.
  285. */
  286. public function delete_expired_items() {
  287. global $wpdb;
  288. $current_time = current_time('mysql');
  289. return $wpdb->query($wpdb->prepare(
  290. "DELETE FROM $this->table_name WHERE active_to < %s",
  291. $current_time
  292. ));
  293. }
  294. /**
  295. * Increment download count and update last download time.
  296. *
  297. * @since 1.0.0
  298. * @param int $id The item ID.
  299. * @return bool True on success, false on failure.
  300. */
  301. public function increment_download_count($id) {
  302. global $wpdb;
  303. return $wpdb->query($wpdb->prepare(
  304. "UPDATE $this->table_name SET download_count = download_count + 1, last_download = %s WHERE id = %d",
  305. current_time('mysql'),
  306. $id
  307. ));
  308. }
  309. /**
  310. * Calculate total storage usage.
  311. *
  312. * @since 1.0.0
  313. * @return int Total storage usage in bytes.
  314. */
  315. public function get_total_storage() {
  316. global $wpdb;
  317. $total = $wpdb->get_var("SELECT SUM(file_size) FROM $this->table_name");
  318. return $total ? (int) $total : 0;
  319. }
  320. /**
  321. * Check if adding a new file would exceed storage limit.
  322. *
  323. * @since 1.0.0
  324. * @param int $file_size The file size in bytes.
  325. * @param int $max_size The maximum allowed storage size in bytes.
  326. * @return bool True if adding the file would exceed limit, false otherwise.
  327. */
  328. public function would_exceed_storage_limit($file_size, $max_size) {
  329. $current_usage = $this->get_total_storage();
  330. return ($current_usage + $file_size) > $max_size;
  331. }
  332. /**
  333. * Get column formats for data.
  334. *
  335. * @since 1.0.0
  336. * @access private
  337. * @param array $data The data to get formats for.
  338. * @return array The column formats.
  339. */
  340. private function get_column_formats($data) {
  341. $formats = array();
  342. $columns = array(
  343. 'id' => '%d',
  344. 'media_id' => '%d',
  345. 'original_file_name' => '%s',
  346. 'description' => '%s',
  347. 'message' => '%s',
  348. 'active_from' => '%s',
  349. 'active_to' => '%s',
  350. 'password' => '%s',
  351. 'reference' => '%s',
  352. 'upload_date' => '%s',
  353. 'download_count' => '%d',
  354. 'last_download' => '%s',
  355. 'file_path' => '%s',
  356. 'file_size' => '%d'
  357. );
  358. foreach ($data as $column => $value) {
  359. if (isset($columns[$column])) {
  360. $formats[] = $columns[$column];
  361. } else {
  362. $formats[] = '%s';
  363. }
  364. }
  365. return $formats;
  366. }
  367. }