class-wc-customer-download-data-store.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. <?php
  2. /**
  3. * WC_Customer_Download_Data_Store class file.
  4. *
  5. * @package WooCommerce\Classes
  6. */
  7. if ( ! defined( 'ABSPATH' ) ) {
  8. exit;
  9. }
  10. /**
  11. * WC Customer Download Data Store.
  12. *
  13. * @version 3.0.0
  14. */
  15. class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store_Interface {
  16. /**
  17. * Create download permission for a user.
  18. *
  19. * @param WC_Customer_Download $download WC_Customer_Download object.
  20. */
  21. public function create( &$download ) {
  22. global $wpdb;
  23. // Always set a access granted date.
  24. if ( is_null( $download->get_access_granted( 'edit' ) ) ) {
  25. $download->set_access_granted( current_time( 'timestamp', true ) );
  26. }
  27. $data = array(
  28. 'download_id' => $download->get_download_id( 'edit' ),
  29. 'product_id' => $download->get_product_id( 'edit' ),
  30. 'user_id' => $download->get_user_id( 'edit' ),
  31. 'user_email' => $download->get_user_email( 'edit' ),
  32. 'order_id' => $download->get_order_id( 'edit' ),
  33. 'order_key' => $download->get_order_key( 'edit' ),
  34. 'downloads_remaining' => $download->get_downloads_remaining( 'edit' ),
  35. 'access_granted' => date( 'Y-m-d', $download->get_access_granted( 'edit' )->getTimestamp() ),
  36. 'download_count' => $download->get_download_count( 'edit' ),
  37. 'access_expires' => ! is_null( $download->get_access_expires( 'edit' ) ) ? date( 'Y-m-d', $download->get_access_expires( 'edit' )->getTimestamp() ) : null,
  38. );
  39. $format = array(
  40. '%s',
  41. '%s',
  42. '%s',
  43. '%s',
  44. '%s',
  45. '%s',
  46. '%s',
  47. '%s',
  48. '%d',
  49. '%s',
  50. );
  51. $result = $wpdb->insert(
  52. $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
  53. apply_filters( 'woocommerce_downloadable_file_permission_data', $data ),
  54. apply_filters( 'woocommerce_downloadable_file_permission_format', $format, $data )
  55. );
  56. do_action( 'woocommerce_grant_product_download_access', $data );
  57. if ( $result ) {
  58. $download->set_id( $wpdb->insert_id );
  59. $download->apply_changes();
  60. }
  61. }
  62. /**
  63. * Method to read a download permission from the database.
  64. *
  65. * @param WC_Customer_Download $download WC_Customer_Download object.
  66. *
  67. * @throws Exception Throw exception if invalid download is passed.
  68. */
  69. public function read( &$download ) {
  70. global $wpdb;
  71. if ( ! $download->get_id() ) {
  72. throw new Exception( __( 'Invalid download.', 'woocommerce' ) );
  73. }
  74. $download->set_defaults();
  75. $raw_download = $wpdb->get_row(
  76. $wpdb->prepare(
  77. "SELECT * FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE permission_id = %d",
  78. $download->get_id()
  79. )
  80. );
  81. if ( ! $raw_download ) {
  82. throw new Exception( __( 'Invalid download.', 'woocommerce' ) );
  83. }
  84. $download->set_props(
  85. array(
  86. 'download_id' => $raw_download->download_id,
  87. 'product_id' => $raw_download->product_id,
  88. 'user_id' => $raw_download->user_id,
  89. 'user_email' => $raw_download->user_email,
  90. 'order_id' => $raw_download->order_id,
  91. 'order_key' => $raw_download->order_key,
  92. 'downloads_remaining' => $raw_download->downloads_remaining,
  93. 'access_granted' => strtotime( $raw_download->access_granted ),
  94. 'download_count' => $raw_download->download_count,
  95. 'access_expires' => is_null( $raw_download->access_expires ) ? null : strtotime( $raw_download->access_expires ),
  96. )
  97. );
  98. $download->set_object_read( true );
  99. }
  100. /**
  101. * Method to update a download in the database.
  102. *
  103. * @param WC_Customer_Download $download WC_Customer_Download object.
  104. */
  105. public function update( &$download ) {
  106. global $wpdb;
  107. $data = array(
  108. 'download_id' => $download->get_download_id( 'edit' ),
  109. 'product_id' => $download->get_product_id( 'edit' ),
  110. 'user_id' => $download->get_user_id( 'edit' ),
  111. 'user_email' => $download->get_user_email( 'edit' ),
  112. 'order_id' => $download->get_order_id( 'edit' ),
  113. 'order_key' => $download->get_order_key( 'edit' ),
  114. 'downloads_remaining' => $download->get_downloads_remaining( 'edit' ),
  115. 'access_granted' => date( 'Y-m-d', $download->get_access_granted( 'edit' )->getTimestamp() ),
  116. 'download_count' => $download->get_download_count( 'edit' ),
  117. 'access_expires' => ! is_null( $download->get_access_expires( 'edit' ) ) ? date( 'Y-m-d', $download->get_access_expires( 'edit' )->getTimestamp() ) : null,
  118. );
  119. $format = array(
  120. '%s',
  121. '%s',
  122. '%s',
  123. '%s',
  124. '%s',
  125. '%s',
  126. '%s',
  127. '%s',
  128. '%d',
  129. '%s',
  130. );
  131. $wpdb->update(
  132. $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
  133. $data,
  134. array(
  135. 'permission_id' => $download->get_id(),
  136. ),
  137. $format
  138. );
  139. $download->apply_changes();
  140. }
  141. /**
  142. * Method to delete a download permission from the database.
  143. *
  144. * @param WC_Customer_Download $download WC_Customer_Download object.
  145. * @param array $args Array of args to pass to the delete method.
  146. */
  147. public function delete( &$download, $args = array() ) {
  148. global $wpdb;
  149. $wpdb->query(
  150. $wpdb->prepare(
  151. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  152. WHERE permission_id = %d",
  153. $download->get_id()
  154. )
  155. );
  156. $download->set_id( 0 );
  157. }
  158. /**
  159. * Method to delete a download permission from the database by ID.
  160. *
  161. * @param int $id permission_id of the download to be deleted.
  162. */
  163. public function delete_by_id( $id ) {
  164. global $wpdb;
  165. $wpdb->query(
  166. $wpdb->prepare(
  167. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  168. WHERE permission_id = %d",
  169. $id
  170. )
  171. );
  172. }
  173. /**
  174. * Method to delete a download permission from the database by order ID.
  175. *
  176. * @param int $id Order ID of the downloads that will be deleted.
  177. */
  178. public function delete_by_order_id( $id ) {
  179. global $wpdb;
  180. $wpdb->query(
  181. $wpdb->prepare(
  182. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  183. WHERE order_id = %d",
  184. $id
  185. )
  186. );
  187. }
  188. /**
  189. * Method to delete a download permission from the database by download ID.
  190. *
  191. * @param int $id download_id of the downloads that will be deleted.
  192. */
  193. public function delete_by_download_id( $id ) {
  194. global $wpdb;
  195. $wpdb->query(
  196. $wpdb->prepare(
  197. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  198. WHERE download_id = %s",
  199. $id
  200. )
  201. );
  202. }
  203. /**
  204. * Method to delete a download permission from the database by user ID.
  205. *
  206. * @since 3.4.0
  207. * @param int $id user ID of the downloads that will be deleted.
  208. * @return bool True if deleted rows.
  209. */
  210. public function delete_by_user_id( $id ) {
  211. global $wpdb;
  212. return (bool) $wpdb->query(
  213. $wpdb->prepare(
  214. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  215. WHERE user_id = %d",
  216. $id
  217. )
  218. );
  219. }
  220. /**
  221. * Method to delete a download permission from the database by user email.
  222. *
  223. * @since 3.4.0
  224. * @param string $email email of the downloads that will be deleted.
  225. * @return bool True if deleted rows.
  226. */
  227. public function delete_by_user_email( $email ) {
  228. global $wpdb;
  229. return (bool) $wpdb->query(
  230. $wpdb->prepare(
  231. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  232. WHERE user_email = %s",
  233. $email
  234. )
  235. );
  236. }
  237. /**
  238. * Get a download object.
  239. *
  240. * @param array $data From the DB.
  241. * @return WC_Customer_Download
  242. */
  243. private function get_download( $data ) {
  244. return new WC_Customer_Download( $data );
  245. }
  246. /**
  247. * Get array of download ids by specified args.
  248. *
  249. * @param array $args Arguments to filter downloads. $args['return'] accepts the following values: 'objects' (default), 'ids' or a comma separeted list of fields (for example: 'order_id,user_id,user_email').
  250. * @return array Can be an array of permission_ids, an array of WC_Customer_Download objects or an array of arrays containing specified fields depending on the value of $args['return'].
  251. */
  252. public function get_downloads( $args = array() ) {
  253. global $wpdb;
  254. $args = wp_parse_args(
  255. $args, array(
  256. 'user_email' => '',
  257. 'user_id' => '',
  258. 'order_id' => '',
  259. 'order_key' => '',
  260. 'product_id' => '',
  261. 'download_id' => '',
  262. 'orderby' => 'permission_id',
  263. 'order' => 'ASC',
  264. 'limit' => -1,
  265. 'page' => 1,
  266. 'return' => 'objects',
  267. )
  268. );
  269. $valid_fields = array( 'permission_id', 'download_id', 'product_id', 'order_id', 'order_key', 'user_email', 'user_id', 'downloads_remaining', 'access_granted', 'access_expires', 'download_count' );
  270. $get_results_output = ARRAY_A;
  271. if ( 'ids' === $args['return'] ) {
  272. $fields = 'permission_id';
  273. } elseif ( 'objects' === $args['return'] ) {
  274. $fields = '*';
  275. $get_results_output = OBJECT;
  276. } else {
  277. $fields = explode( ',', (string) $args['return'] );
  278. $fields = implode( ', ', array_intersect( $fields, $valid_fields ) );
  279. }
  280. $query = array();
  281. $query[] = "SELECT {$fields} FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE 1=1";
  282. if ( $args['user_email'] ) {
  283. $query[] = $wpdb->prepare( 'AND user_email = %s', sanitize_email( $args['user_email'] ) );
  284. }
  285. if ( $args['user_id'] ) {
  286. $query[] = $wpdb->prepare( 'AND user_id = %d', absint( $args['user_id'] ) );
  287. }
  288. if ( $args['order_id'] ) {
  289. $query[] = $wpdb->prepare( 'AND order_id = %d', $args['order_id'] );
  290. }
  291. if ( $args['order_key'] ) {
  292. $query[] = $wpdb->prepare( 'AND order_key = %s', $args['order_key'] );
  293. }
  294. if ( $args['product_id'] ) {
  295. $query[] = $wpdb->prepare( 'AND product_id = %d', $args['product_id'] );
  296. }
  297. if ( $args['download_id'] ) {
  298. $query[] = $wpdb->prepare( 'AND download_id = %s', $args['download_id'] );
  299. }
  300. $orderby = in_array( $args['orderby'], $valid_fields, true ) ? $args['orderby'] : 'permission_id';
  301. $order = 'DESC' === strtoupper( $args['order'] ) ? 'DESC' : 'ASC';
  302. $orderby_sql = sanitize_sql_orderby( "{$orderby} {$order}" );
  303. $query[] = "ORDER BY {$orderby_sql}";
  304. if ( 0 < $args['limit'] ) {
  305. $query[] = $wpdb->prepare( 'LIMIT %d, %d', absint( $args['limit'] ) * absint( $args['page'] - 1 ), absint( $args['limit'] ) );
  306. }
  307. // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared
  308. $results = $wpdb->get_results( implode( ' ', $query ), $get_results_output );
  309. switch ( $args['return'] ) {
  310. case 'ids':
  311. return wp_list_pluck( $results, 'permission_id' );
  312. case 'objects':
  313. return array_map( array( $this, 'get_download' ), $results );
  314. default:
  315. return $results;
  316. }
  317. }
  318. /**
  319. * Update download ids if the hash changes.
  320. *
  321. * @deprecated 3.3.0 Download id is now a static UUID and should not be changed based on file hash.
  322. *
  323. * @param int $product_id Product ID.
  324. * @param string $old_id Old download_id.
  325. * @param string $new_id New download_id.
  326. */
  327. public function update_download_id( $product_id, $old_id, $new_id ) {
  328. global $wpdb;
  329. wc_deprecated_function( __METHOD__, '3.3' );
  330. $wpdb->update(
  331. $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
  332. array(
  333. 'download_id' => $new_id,
  334. ),
  335. array(
  336. 'download_id' => $old_id,
  337. 'product_id' => $product_id,
  338. )
  339. );
  340. }
  341. /**
  342. * Get a customers downloads.
  343. *
  344. * @param int $customer_id Customer ID.
  345. * @return array
  346. */
  347. public function get_downloads_for_customer( $customer_id ) {
  348. global $wpdb;
  349. return $wpdb->get_results(
  350. $wpdb->prepare(
  351. "SELECT * FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions as permissions
  352. WHERE user_id = %d
  353. AND permissions.order_id > 0
  354. AND
  355. (
  356. permissions.downloads_remaining > 0
  357. OR permissions.downloads_remaining = ''
  358. )
  359. AND
  360. (
  361. permissions.access_expires IS NULL
  362. OR permissions.access_expires >= %s
  363. OR permissions.access_expires = '0000-00-00 00:00:00'
  364. )
  365. ORDER BY permissions.order_id, permissions.product_id, permissions.permission_id;",
  366. $customer_id,
  367. date( 'Y-m-d', current_time( 'timestamp' ) )
  368. )
  369. );
  370. }
  371. /**
  372. * Update user prop for downloads based on order id.
  373. *
  374. * @param int $order_id Order ID.
  375. * @param int $customer_id Customer ID.
  376. * @param string $email Customer email address.
  377. */
  378. public function update_user_by_order_id( $order_id, $customer_id, $email ) {
  379. global $wpdb;
  380. $wpdb->update(
  381. $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
  382. array(
  383. 'user_id' => $customer_id,
  384. 'user_email' => $email,
  385. ),
  386. array(
  387. 'order_id' => $order_id,
  388. ),
  389. array(
  390. '%d',
  391. '%s',
  392. ),
  393. array(
  394. '%d',
  395. )
  396. );
  397. }
  398. }