Nessuna descrizione

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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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. * Names of the database fields for the download permissions table.
  18. */
  19. const DOWNLOAD_PERMISSION_DB_FIELDS = array(
  20. 'download_id',
  21. 'product_id',
  22. 'user_id',
  23. 'user_email',
  24. 'order_id',
  25. 'order_key',
  26. 'downloads_remaining',
  27. 'access_granted',
  28. 'download_count',
  29. 'access_expires',
  30. );
  31. /**
  32. * Create download permission for a user, from an array of data.
  33. *
  34. * @param array $data Data to create the permission for.
  35. * @returns int The database id of the created permission, or false if the permission creation failed.
  36. */
  37. public function create_from_data( $data ) {
  38. $data = array_intersect_key( $data, array_flip( self::DOWNLOAD_PERMISSION_DB_FIELDS ) );
  39. $id = $this->insert_new_download_permission( $data );
  40. do_action( 'woocommerce_grant_product_download_access', $data );
  41. return $id;
  42. }
  43. /**
  44. * Create download permission for a user.
  45. *
  46. * @param WC_Customer_Download $download WC_Customer_Download object.
  47. */
  48. public function create( &$download ) {
  49. global $wpdb;
  50. // Always set a access granted date.
  51. if ( is_null( $download->get_access_granted( 'edit' ) ) ) {
  52. $download->set_access_granted( time() );
  53. }
  54. $data = array();
  55. foreach ( self::DOWNLOAD_PERMISSION_DB_FIELDS as $db_field_name ) {
  56. $value = call_user_func( array( $download, 'get_' . $db_field_name ), 'edit' );
  57. $data[ $db_field_name ] = $value;
  58. }
  59. $inserted_id = $this->insert_new_download_permission( $data );
  60. if ( $inserted_id ) {
  61. $download->set_id( $inserted_id );
  62. $download->apply_changes();
  63. }
  64. do_action( 'woocommerce_grant_product_download_access', $data );
  65. }
  66. /**
  67. * Create download permission for a user, from an array of data.
  68. * Assumes that all the keys in the passed data are valid.
  69. *
  70. * @param array $data Data to create the permission for.
  71. * @return int The database id of the created permission, or false if the permission creation failed.
  72. */
  73. private function insert_new_download_permission( $data ) {
  74. global $wpdb;
  75. // Always set a access granted date.
  76. if ( ! isset( $data['access_granted'] ) ) {
  77. $data['access_granted'] = time();
  78. }
  79. $data['access_granted'] = $this->adjust_date_for_db( $data['access_granted'] );
  80. if ( isset( $data['access_expires'] ) ) {
  81. $data['access_expires'] = $this->adjust_date_for_db( $data['access_expires'] );
  82. }
  83. $format = array(
  84. '%s',
  85. '%s',
  86. '%s',
  87. '%s',
  88. '%s',
  89. '%s',
  90. '%s',
  91. '%s',
  92. '%d',
  93. '%s',
  94. );
  95. $result = $wpdb->insert(
  96. $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
  97. apply_filters( 'woocommerce_downloadable_file_permission_data', $data ),
  98. apply_filters( 'woocommerce_downloadable_file_permission_format', $format, $data )
  99. );
  100. return $result ? $wpdb->insert_id : false;
  101. }
  102. /**
  103. * Adjust a date value to be inserted in the database.
  104. *
  105. * @param mixed $date The date value. Can be a WC_DateTime, a timestamp, or anything else that "date" recognizes.
  106. * @return string The date converted to 'Y-m-d' format.
  107. * @throws Exception The passed value can't be converted to a date.
  108. */
  109. private function adjust_date_for_db( $date ) {
  110. if ( 'WC_DateTime' === get_class( $date ) ) {
  111. $date = $date->getTimestamp();
  112. }
  113. $adjusted_date = date( 'Y-m-d', $date ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
  114. if ( $adjusted_date ) {
  115. return $adjusted_date;
  116. }
  117. $msg = sprintf( __( "I don't know how to get a date from a %s", 'woocommerce' ), is_object( $date ) ? get_class( $date ) : gettype( $date ) );
  118. throw new Exception( $msg );
  119. }
  120. /**
  121. * Method to read a download permission from the database.
  122. *
  123. * @param WC_Customer_Download $download WC_Customer_Download object.
  124. *
  125. * @throws Exception Throw exception if invalid download is passed.
  126. */
  127. public function read( &$download ) {
  128. global $wpdb;
  129. if ( ! $download->get_id() ) {
  130. throw new Exception( __( 'Invalid download.', 'woocommerce' ) );
  131. }
  132. $download->set_defaults();
  133. $raw_download = $wpdb->get_row(
  134. $wpdb->prepare(
  135. "SELECT * FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE permission_id = %d",
  136. $download->get_id()
  137. )
  138. );
  139. if ( ! $raw_download ) {
  140. throw new Exception( __( 'Invalid download.', 'woocommerce' ) );
  141. }
  142. $download->set_props(
  143. array(
  144. 'download_id' => $raw_download->download_id,
  145. 'product_id' => $raw_download->product_id,
  146. 'user_id' => $raw_download->user_id,
  147. 'user_email' => $raw_download->user_email,
  148. 'order_id' => $raw_download->order_id,
  149. 'order_key' => $raw_download->order_key,
  150. 'downloads_remaining' => $raw_download->downloads_remaining,
  151. 'access_granted' => strtotime( $raw_download->access_granted ),
  152. 'download_count' => $raw_download->download_count,
  153. 'access_expires' => is_null( $raw_download->access_expires ) ? null : strtotime( $raw_download->access_expires ),
  154. )
  155. );
  156. $download->set_object_read( true );
  157. }
  158. /**
  159. * Method to update a download in the database.
  160. *
  161. * @param WC_Customer_Download $download WC_Customer_Download object.
  162. */
  163. public function update( &$download ) {
  164. global $wpdb;
  165. $data = array(
  166. 'download_id' => $download->get_download_id( 'edit' ),
  167. 'product_id' => $download->get_product_id( 'edit' ),
  168. 'user_id' => $download->get_user_id( 'edit' ),
  169. 'user_email' => $download->get_user_email( 'edit' ),
  170. 'order_id' => $download->get_order_id( 'edit' ),
  171. 'order_key' => $download->get_order_key( 'edit' ),
  172. 'downloads_remaining' => $download->get_downloads_remaining( 'edit' ),
  173. // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
  174. 'access_granted' => date( 'Y-m-d', $download->get_access_granted( 'edit' )->getTimestamp() ),
  175. 'download_count' => $download->get_download_count( 'edit' ),
  176. // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
  177. 'access_expires' => ! is_null( $download->get_access_expires( 'edit' ) ) ? date( 'Y-m-d', $download->get_access_expires( 'edit' )->getTimestamp() ) : null,
  178. );
  179. $format = array(
  180. '%s',
  181. '%s',
  182. '%s',
  183. '%s',
  184. '%s',
  185. '%s',
  186. '%s',
  187. '%s',
  188. '%d',
  189. '%s',
  190. );
  191. $wpdb->update(
  192. $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
  193. $data,
  194. array(
  195. 'permission_id' => $download->get_id(),
  196. ),
  197. $format
  198. );
  199. $download->apply_changes();
  200. }
  201. /**
  202. * Method to delete a download permission from the database.
  203. *
  204. * @param WC_Customer_Download $download WC_Customer_Download object.
  205. * @param array $args Array of args to pass to the delete method.
  206. */
  207. public function delete( &$download, $args = array() ) {
  208. global $wpdb;
  209. $wpdb->query(
  210. $wpdb->prepare(
  211. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  212. WHERE permission_id = %d",
  213. $download->get_id()
  214. )
  215. );
  216. $download->set_id( 0 );
  217. }
  218. /**
  219. * Method to delete a download permission from the database by ID.
  220. *
  221. * @param int $id permission_id of the download to be deleted.
  222. */
  223. public function delete_by_id( $id ) {
  224. global $wpdb;
  225. $wpdb->query(
  226. $wpdb->prepare(
  227. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  228. WHERE permission_id = %d",
  229. $id
  230. )
  231. );
  232. }
  233. /**
  234. * Method to delete a download permission from the database by order ID.
  235. *
  236. * @param int $id Order ID of the downloads that will be deleted.
  237. */
  238. public function delete_by_order_id( $id ) {
  239. global $wpdb;
  240. $wpdb->query(
  241. $wpdb->prepare(
  242. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  243. WHERE order_id = %d",
  244. $id
  245. )
  246. );
  247. }
  248. /**
  249. * Method to delete a download permission from the database by download ID.
  250. *
  251. * @param int $id download_id of the downloads that will be deleted.
  252. */
  253. public function delete_by_download_id( $id ) {
  254. global $wpdb;
  255. $wpdb->query(
  256. $wpdb->prepare(
  257. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  258. WHERE download_id = %s",
  259. $id
  260. )
  261. );
  262. }
  263. /**
  264. * Method to delete a download permission from the database by user ID.
  265. *
  266. * @since 3.4.0
  267. * @param int $id user ID of the downloads that will be deleted.
  268. * @return bool True if deleted rows.
  269. */
  270. public function delete_by_user_id( $id ) {
  271. global $wpdb;
  272. return (bool) $wpdb->query(
  273. $wpdb->prepare(
  274. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  275. WHERE user_id = %d",
  276. $id
  277. )
  278. );
  279. }
  280. /**
  281. * Method to delete a download permission from the database by user email.
  282. *
  283. * @since 3.4.0
  284. * @param string $email email of the downloads that will be deleted.
  285. * @return bool True if deleted rows.
  286. */
  287. public function delete_by_user_email( $email ) {
  288. global $wpdb;
  289. return (bool) $wpdb->query(
  290. $wpdb->prepare(
  291. "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
  292. WHERE user_email = %s",
  293. $email
  294. )
  295. );
  296. }
  297. /**
  298. * Get a download object.
  299. *
  300. * @param array $data From the DB.
  301. * @return WC_Customer_Download
  302. */
  303. private function get_download( $data ) {
  304. return new WC_Customer_Download( $data );
  305. }
  306. /**
  307. * Get array of download ids by specified args.
  308. *
  309. * @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').
  310. * @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'].
  311. */
  312. public function get_downloads( $args = array() ) {
  313. global $wpdb;
  314. $args = wp_parse_args(
  315. $args,
  316. array(
  317. 'user_email' => '',
  318. 'user_id' => '',
  319. 'order_id' => '',
  320. 'order_key' => '',
  321. 'product_id' => '',
  322. 'download_id' => '',
  323. 'orderby' => 'permission_id',
  324. 'order' => 'ASC',
  325. 'limit' => -1,
  326. 'page' => 1,
  327. 'return' => 'objects',
  328. )
  329. );
  330. $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' );
  331. $get_results_output = ARRAY_A;
  332. if ( 'ids' === $args['return'] ) {
  333. $fields = 'permission_id';
  334. } elseif ( 'objects' === $args['return'] ) {
  335. $fields = '*';
  336. $get_results_output = OBJECT;
  337. } else {
  338. $fields = explode( ',', (string) $args['return'] );
  339. $fields = implode( ', ', array_intersect( $fields, $valid_fields ) );
  340. }
  341. $query = array();
  342. $query[] = "SELECT {$fields} FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE 1=1";
  343. if ( $args['user_email'] ) {
  344. $query[] = $wpdb->prepare( 'AND user_email = %s', sanitize_email( $args['user_email'] ) );
  345. }
  346. if ( $args['user_id'] ) {
  347. $query[] = $wpdb->prepare( 'AND user_id = %d', absint( $args['user_id'] ) );
  348. }
  349. if ( $args['order_id'] ) {
  350. $query[] = $wpdb->prepare( 'AND order_id = %d', $args['order_id'] );
  351. }
  352. if ( $args['order_key'] ) {
  353. $query[] = $wpdb->prepare( 'AND order_key = %s', $args['order_key'] );
  354. }
  355. if ( $args['product_id'] ) {
  356. $query[] = $wpdb->prepare( 'AND product_id = %d', $args['product_id'] );
  357. }
  358. if ( $args['download_id'] ) {
  359. $query[] = $wpdb->prepare( 'AND download_id = %s', $args['download_id'] );
  360. }
  361. $orderby = in_array( $args['orderby'], $valid_fields, true ) ? $args['orderby'] : 'permission_id';
  362. $order = 'DESC' === strtoupper( $args['order'] ) ? 'DESC' : 'ASC';
  363. $orderby_sql = sanitize_sql_orderby( "{$orderby} {$order}" );
  364. $query[] = "ORDER BY {$orderby_sql}";
  365. if ( 0 < $args['limit'] ) {
  366. $query[] = $wpdb->prepare( 'LIMIT %d, %d', absint( $args['limit'] ) * absint( $args['page'] - 1 ), absint( $args['limit'] ) );
  367. }
  368. // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
  369. $results = $wpdb->get_results( implode( ' ', $query ), $get_results_output );
  370. switch ( $args['return'] ) {
  371. case 'ids':
  372. return wp_list_pluck( $results, 'permission_id' );
  373. case 'objects':
  374. return array_map( array( $this, 'get_download' ), $results );
  375. default:
  376. return $results;
  377. }
  378. }
  379. /**
  380. * Update download ids if the hash changes.
  381. *
  382. * @deprecated 3.3.0 Download id is now a static UUID and should not be changed based on file hash.
  383. *
  384. * @param int $product_id Product ID.
  385. * @param string $old_id Old download_id.
  386. * @param string $new_id New download_id.
  387. */
  388. public function update_download_id( $product_id, $old_id, $new_id ) {
  389. global $wpdb;
  390. wc_deprecated_function( __METHOD__, '3.3' );
  391. $wpdb->update(
  392. $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
  393. array(
  394. 'download_id' => $new_id,
  395. ),
  396. array(
  397. 'download_id' => $old_id,
  398. 'product_id' => $product_id,
  399. )
  400. );
  401. }
  402. /**
  403. * Get a customers downloads.
  404. *
  405. * @param int $customer_id Customer ID.
  406. * @return array
  407. */
  408. public function get_downloads_for_customer( $customer_id ) {
  409. global $wpdb;
  410. return $wpdb->get_results(
  411. $wpdb->prepare(
  412. "SELECT * FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions as permissions
  413. WHERE user_id = %d
  414. AND permissions.order_id > 0
  415. AND
  416. (
  417. permissions.downloads_remaining > 0
  418. OR permissions.downloads_remaining = ''
  419. )
  420. AND
  421. (
  422. permissions.access_expires IS NULL
  423. OR permissions.access_expires >= %s
  424. OR permissions.access_expires = '0000-00-00 00:00:00'
  425. )
  426. ORDER BY permissions.order_id, permissions.product_id, permissions.permission_id;",
  427. $customer_id,
  428. date( 'Y-m-d', current_time( 'timestamp' ) ) // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
  429. )
  430. );
  431. }
  432. /**
  433. * Update user prop for downloads based on order id.
  434. *
  435. * @param int $order_id Order ID.
  436. * @param int $customer_id Customer ID.
  437. * @param string $email Customer email address.
  438. */
  439. public function update_user_by_order_id( $order_id, $customer_id, $email ) {
  440. global $wpdb;
  441. $wpdb->update(
  442. $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
  443. array(
  444. 'user_id' => $customer_id,
  445. 'user_email' => $email,
  446. ),
  447. array(
  448. 'order_id' => $order_id,
  449. ),
  450. array(
  451. '%d',
  452. '%s',
  453. ),
  454. array(
  455. '%d',
  456. )
  457. );
  458. }
  459. }