Source: includes/classes/Command/Utility.php

  1. <?php
  2. /**
  3. * ElasticPress CLI Utility
  4. *
  5. * @since 4.5.0
  6. * @package elasticpress
  7. */
  8. namespace ElasticPress\Command;
  9. use WP_CLI;
  10. if ( ! defined( 'ABSPATH' ) ) {
  11. exit; // Exit if accessed directly.
  12. }
  13. /**
  14. * Utility class for WP CLI commands.
  15. */
  16. class Utility {
  17. /**
  18. * Internal timer.
  19. *
  20. * @var float
  21. */
  22. protected static $time_start = null;
  23. /**
  24. * Properly clean up when receiving SIGINT on indexing
  25. *
  26. * @param int $signal_no Signal number
  27. */
  28. public static function delete_transient_on_int( $signal_no ) {
  29. if ( SIGINT === $signal_no ) {
  30. self::delete_transient();
  31. WP_CLI::log( esc_html__( 'Indexing cleaned up.', 'elasticpress' ) );
  32. WP_CLI::halt( 0 );
  33. }
  34. }
  35. /**
  36. * Delete transient that indicates indexing is occurring
  37. */
  38. public static function delete_transient() {
  39. \ElasticPress\IndexHelper::factory()->clear_index_meta();
  40. if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
  41. delete_site_transient( 'ep_cli_sync_progress' );
  42. delete_site_transient( 'ep_wpcli_sync_interrupted' );
  43. } else {
  44. delete_transient( 'ep_cli_sync_progress' );
  45. delete_transient( 'ep_wpcli_sync_interrupted' );
  46. }
  47. }
  48. /**
  49. * Stops the timer.
  50. *
  51. * @param int $precision The number of digits from the right of the decimal to display. Default 3.
  52. * @return float Time spent so far
  53. */
  54. public static function timer_stop( $precision = 3 ) {
  55. $diff = microtime( true ) - self::$time_start;
  56. return (float) number_format( (float) $diff, $precision, '.', '' );
  57. }
  58. /**
  59. * Starts the timer.
  60. *
  61. * @return true
  62. */
  63. public static function timer_start() {
  64. self::$time_start = microtime( true );
  65. return true;
  66. }
  67. /**
  68. * Check if sync should be interrupted
  69. */
  70. public static function should_interrupt_sync() {
  71. $should_interrupt_sync = get_transient( 'ep_wpcli_sync_interrupted' );
  72. if ( $should_interrupt_sync ) {
  73. WP_CLI::line( esc_html__( 'Sync was interrupted', 'elasticpress' ) );
  74. self::delete_transient_on_int( 2 );
  75. WP_CLI::halt( 0 );
  76. }
  77. }
  78. /**
  79. * Given a timestamp in microseconds, returns it in the given format.
  80. *
  81. * @param float $microtime Unix timestamp in ms
  82. * @param string $format Desired format
  83. * @return string
  84. */
  85. public static function timer_format( $microtime, $format = 'H:i:s.u' ) {
  86. $microtime_date = \DateTime::createFromFormat( 'U.u', number_format( (float) $microtime, 3, '.', '' ) );
  87. return $microtime_date->format( $format );
  88. }
  89. /**
  90. * If put_mapping fails while indexing, stop the index process.
  91. *
  92. * @param array $index_meta Index meta info
  93. * @param Indexable $indexable Indexable object
  94. * @param bool $result Whether the request was successful or not
  95. */
  96. public static function stop_on_failed_mapping( $index_meta, $indexable, $result ) {
  97. if ( ! $result ) {
  98. self::delete_transient();
  99. WP_CLI::error( esc_html__( 'Mapping Failed.', 'elasticpress' ) );
  100. }
  101. }
  102. /**
  103. * Ties the `ep_cli_put_mapping` action to `ep_sync_put_mapping`.
  104. *
  105. * @param array $index_meta Index meta information
  106. * @param Indexable $indexable Indexable object
  107. * @return void
  108. */
  109. public static function call_ep_cli_put_mapping( $index_meta, $indexable ) {
  110. /**
  111. * Fires after CLI put mapping
  112. *
  113. * @hook ep_cli_put_mapping
  114. * @param {Indexable} $indexable Indexable involved in mapping
  115. * @param {array} $args CLI command position args
  116. * @param {array} $assoc_args CLI command associative args
  117. */
  118. do_action( 'ep_cli_put_mapping', $indexable, WP_CLI::get_runner()->arguments, WP_CLI::get_runner()->assoc_args );
  119. }
  120. /**
  121. * Custom get_transient to WP-CLI env.
  122. *
  123. * We are using the direct SQL query instead of
  124. * the regular function call to retrieve the updated
  125. * value to stop the sync. Otherwise, we always get
  126. * false after the command is running even when the value
  127. * is updated.
  128. *
  129. * @param mixed $pre_transient The default value.
  130. * @param string $transient Transient name.
  131. * @return true|null
  132. */
  133. public static function custom_get_transient( $pre_transient, $transient ) {
  134. global $wpdb;
  135. if ( wp_using_ext_object_cache() ) {
  136. /**
  137. * When external object cache is used we need to make sure to force a remote fetch,
  138. * so that the value from the local memory is discarded.
  139. */
  140. $should_interrupt_sync = wp_cache_get( $transient, 'transient', true );
  141. } else {
  142. // phpcs:disable WordPress.DB.DirectDatabaseQuery
  143. $should_interrupt_sync = $wpdb->get_var(
  144. $wpdb->prepare(
  145. "
  146. SELECT option_value
  147. FROM $wpdb->options
  148. WHERE option_name = %s
  149. LIMIT 1
  150. ",
  151. "_transient_{$transient}"
  152. )
  153. );
  154. // phpcs:enable WordPress.DB.DirectDatabaseQuery
  155. }
  156. return $should_interrupt_sync ? (bool) $should_interrupt_sync : null;
  157. }
  158. }