Files
laipower/wp-content/plugins/easy-digital-downloads/src/Orders/Number.php

279 lines
6.6 KiB
PHP

<?php
/**
* Class for getting/assigning order numbers.
*/
namespace EDD\Orders;
class Number {
/**
* Whether core sequential order numbers are enabled.
*
* @since 3.1.2
* @var bool
*/
private $sequential;
/**
* The order number prefix.
*
* @since 3.1.2
* @var string
*/
private $prefix = '';
/**
* The order number postfix.
*
* @since 3.1.2
* @var string
*/
private $postfix = '';
public function __construct() {
$this->sequential = edd_get_option( 'enable_sequential', false );
// If sequential order numbers are enabled, we need to make sure the prefix and suffix are loaded.
if ( $this->sequential ) {
$this->prefix = $this->get_prefix();
$this->postfix = $this->get_postfix();
}
}
/**
* Gets the formatted order number; if sequential order numbers are enabled,
* this function also updates the last payment number in the database.
*
* @since 3.1.2
* @return string|bool A formatted order number, or false if sequential order numbers are disabled.
*/
public function apply() {
if ( false === $this->sequential ) {
return '';
}
$next_order_number = $this->get_next_payment_number();
if ( ! $next_order_number ) {
return '';
}
return $this->format( $next_order_number );
}
/**
* Gets the unformatted next order number from the database.
*
* @since 3.1.2
* @return false|int False if sequential order numbers are disabled, otherwise the next order number to apply.
*/
public function get_next_payment_number() {
if ( false === $this->sequential ) {
return false;
}
return (int) apply_filters( 'edd_get_next_payment_number', $this->get_next() );
}
/**
* Formats the order number with the sequential pre/postfixes.
*
* @since 3.1.2
* @param int $number
* @return string|int
*/
public function format( $number ) {
if ( ! $this->sequential || ! is_numeric( $number ) ) {
return $number;
}
$prefix = $this->prefix;
$number = absint( $number );
$postfix = $this->postfix;
$formatted_number = $prefix . $number . $postfix;
return apply_filters( 'edd_format_payment_number', $formatted_number, $prefix, $number, $postfix );
}
/**
* Given an order number, unformat it by removing the pre/postfix.
*
* @since 3.1.2
* @param string $number
* @return int
*/
public function unformat( $number ) {
if ( ! $this->sequential ) {
return $number;
}
$prefix = $this->prefix;
$postfix = $this->postfix;
// Remove prefix
$number = preg_replace( '/' . $prefix . '/', '', $number, 1 );
// Remove the postfix
$length = strlen( $number );
$postfix_pos = strrpos( $number, strval( $postfix ) );
if ( false !== $postfix_pos ) {
$number = substr_replace( $number, '', $postfix_pos, $length );
}
return apply_filters( 'edd_remove_payment_prefix_postfix', intval( $number ), $prefix, $postfix );
}
/**
* Gets the next order number from the database. This also updates the "next"
* order number in the database with the number which is being returned.
*
* @since 3.1.2
* @return int
*/
private function get_next() {
global $wpdb;
$number = $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM {$wpdb->options} WHERE option_name=%s", 'edd_next_order_number' ) );
// The next order number exists, so increment it and update the database.
if ( ! is_null( $number ) ) {
$number = (int) $number;
// Update the option for the next order number now.
$this->update( $number + 1 );
return $number;
}
// If the option is not set for the next order number, we need to get the last order number from the database.
$order_number = (int) $this->get_last();
$next_number = $order_number + 1;
$this->insert( $next_number );
return $order_number;
}
/**
* Updates the last order number in the database.
*
* This doesn't use $wpdb->update() and instead opts for using $wpdb->query() because
* in our testing we're a consistent improvment in performance. While it's measured in microseconds
* it is in the effort to remove any race condition we are running into here.
*
* @since 3.1.2
* @param int $value
* @return bool
*/
private function update( $value ) {
global $wpdb;
// We should never hit this....but just in case, we need to unformat it.
if ( ! is_numeric( $value ) ) {
$value = $this->unformat( $value );
}
$value = $wpdb->prepare( '%d', $value );
return $wpdb->query(
"UPDATE {$wpdb->options} SET option_value = {$value} WHERE option_name = 'edd_next_order_number'"
);
}
/**
* Adds the last order number to the database.
*
* @since 3.1.2
* @param int $value
* @return bool
*/
private function insert( $value ) {
global $wpdb;
return $wpdb->insert(
$wpdb->options,
array(
'option_name' => 'edd_next_order_number',
'option_value' => $value,
),
array( '%s', '%d' )
);
}
/**
* Gets the last payment number from the database, or from the option.
*
* @return string
*/
private function get_last() {
// If this was the first order after switching to useing the 'next' order number option, we need to get the last order number from the database.
$last_payment_number = $this->get_last_payment_number();
if ( ! is_null( $last_payment_number ) ) {
return $last_payment_number + 1;
}
// If they enabled sequential order numbers after having orders, we need to get the last order number from the database.
$last_order = edd_get_orders(
array(
'number' => 1,
'orderby' => 'id',
'order' => 'DESC',
)
);
if ( ! empty( $last_order ) ) {
$last_order = reset( $last_order );
if ( $last_order instanceof EDD\Orders\Order && ! empty( $last_order->order_number ) ) {
return $this->unformat( $last_order->order_number );
}
}
// If all else fails, just get the starting number from the setting.
return $this->get_start();
}
/**
* Gets the EDD sequential starting number.
* Used when the last order number cannot otherwise be found.
*
* @return int
*/
private function get_start() {
return (int) edd_get_option( 'sequential_start', 1 );
}
/**
* Gets the sequential prefix.
*
* @since 3.1.2
* @return string
*/
private function get_prefix() {
return (string) edd_get_option( 'sequential_prefix' );
}
/**
* Gets the sequential postfix.
*
* @since 3.1.2
* @return string
*/
private function get_postfix() {
return (string) edd_get_option( 'sequential_postfix' );
}
/**
* Gets the last payment number from the database.
*
* @since 3.1.2
*
* @return int
*/
private function get_last_payment_number() {
global $wpdb;
return $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM {$wpdb->options} WHERE option_name=%s", 'edd_last_payment_number' ) );
}
}