From bb7a1fccd1c3ffdd6a6d7cddf4b92a439e8fb54d Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Tue, 10 Dec 2024 18:49:36 -0600 Subject: [PATCH 01/47] Create dedicated Status trait --- .../Order_Modifiers/Traits/Status.php | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/Tickets/Commerce/Order_Modifiers/Traits/Status.php diff --git a/src/Tickets/Commerce/Order_Modifiers/Traits/Status.php b/src/Tickets/Commerce/Order_Modifiers/Traits/Status.php new file mode 100644 index 0000000000..55d5d39db2 --- /dev/null +++ b/src/Tickets/Commerce/Order_Modifiers/Traits/Status.php @@ -0,0 +1,100 @@ +get_valid_statuses(); + + /** + * Filters the human-readable status label for an order modifier. + * + * This allows developers to modify the status labels (e.g., changing 'Draft' to 'Pending'). + * + * @since TBD + * + * @param string[] $statuses The array of default status labels. + * @param string $raw_status The raw status from the database (e.g., 'active', 'draft'). + * @param string $modifier_type The type of the modifier (e.g., 'coupon', 'fee'). + */ + $statuses = apply_filters( 'tec_tickets_commerce_order_modifier_status_display', $statuses, $status, $this->modifier_type ); + + return $statuses[ $status ] ?? $status; + } + + /** + * Get the valid statuses for an order modifier. + * + * @since TBD + * + * @return array + */ + protected function get_valid_statuses(): array { + $statuses = [ + 'active' => _x( 'Active', 'Order modifier status label', 'event-tickets' ), + 'inactive' => _x( 'Inactive', 'Order modifier status label', 'event-tickets' ), + 'draft' => _x( 'Draft', 'Order modifier status label', 'event-tickets' ), + ]; + + /** + * Filters the valid statuses for an order modifier. + * + * This allows developers to modify the valid statuses for an order modifier. + * + * @since TBD + * + * @param string[] $statuses The array of default status labels. + * @param string $modifier_type The type of the modifier (e.g., 'coupon', 'fee'). + */ + return apply_filters( 'tec_tickets_commerce_order_modifier_valid_statuses', $statuses, $this->modifier_type ); + } + + /** + * Check if a status is valid for an order modifier. + * + * @since TBD + * + * @param string $status The status to check. + * + * @return bool Whether the status is valid. + */ + protected function is_valid_status( string $status ): bool { + return array_key_exists( $status, $this->get_valid_statuses() ); + } +} From bd42f7d985c781489e4e057b377a0d7582d3874f Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Tue, 10 Dec 2024 19:00:40 -0600 Subject: [PATCH 02/47] Sort imports alphabetically --- .../Order_Modifiers/Repositories/Order_Modifiers.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index 8a5742dfca..52a77a4a35 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -17,12 +17,12 @@ use TEC\Common\StellarWP\Models\Repositories\Contracts\Insertable; use TEC\Common\StellarWP\Models\Repositories\Contracts\Updatable; use TEC\Common\StellarWP\Models\Repositories\Repository; -use TEC\Tickets\Exceptions\Not_Found_Exception; -use TEC\Tickets\Commerce\Order_Modifiers\Custom_Tables\Order_Modifiers as Table; use TEC\Tickets\Commerce\Order_Modifiers\Custom_Tables\Order_Modifier_Relationships as Relationship_Table; -use TEC\Tickets\Commerce\Order_Modifiers\Models\Order_Modifier; +use TEC\Tickets\Commerce\Order_Modifiers\Custom_Tables\Order_Modifiers as Table; use TEC\Tickets\Commerce\Order_Modifiers\Custom_Tables\Order_Modifiers_Meta; +use TEC\Tickets\Commerce\Order_Modifiers\Models\Order_Modifier; use TEC\Tickets\Commerce\Order_Modifiers\Traits\Valid_Types; +use TEC\Tickets\Exceptions\Not_Found_Exception; /** * Class Order_Modifiers. From 122f385a2153658b1599689dce5b0fa5455b3956 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Tue, 10 Dec 2024 19:04:41 -0600 Subject: [PATCH 03/47] Use Status trait, and remove methods from Valid_Types trait --- .../Modifiers/Modifier_Abstract.php | 40 ++----------------- .../Repositories/Order_Modifiers.php | 2 + .../Order_Modifiers/Traits/Valid_Types.php | 40 ------------------- 3 files changed, 5 insertions(+), 77 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php index 04587164f1..f0feeafd72 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php @@ -23,6 +23,7 @@ use Exception; use InvalidArgumentException; use TEC\Common\StellarWP\Models\Contracts\Model; +use TEC\Tickets\Commerce\Order_Modifiers\Traits\Status; use TEC\Tickets\Commerce\Order_Modifiers\Traits\Valid_Types; use TEC\Tickets\Commerce\Utils\Value; use TEC\Tickets\Exceptions\Not_Found_Exception; @@ -47,6 +48,8 @@ * @since 5.18.0 */ abstract class Modifier_Abstract implements Modifier_Strategy_Interface { + + use Status; use Valid_Types; /** @@ -382,43 +385,6 @@ protected function is_slug_unique( string $slug ): bool { } } - /** - * Convert the status to a human-readable format. - * - * This method converts the internal status values ('active', 'inactive', 'draft') - * into human-readable strings ('Active', 'Inactive', 'Draft'). - * It also provides a filter to allow for customizing the status labels if necessary. - * - * @since 5.18.0 - * - * @param string $status The raw status from the database. - * - * @return string The human-readable status. - */ - public function get_status_display( string $status ): string { - // Default conversion. - $statuses = [ - 'active' => _x( 'Active', 'Order modifier status', 'event-tickets' ), - 'inactive' => _x( 'Inactive', 'Order modifier status', 'event-tickets' ), - 'draft' => _x( 'Draft', 'Order modifier status', 'event-tickets' ), - ]; - - /** - * Filters the human-readable status label for an order modifier. - * - * This allows developers to modify the status labels (e.g., changing 'Draft' to 'Pending'). - * - * @since 5.18.0 - * - * @param string[] $statuses The array of default status labels. - * @param string $raw_status The raw status from the database (e.g., 'active', 'draft'). - * @param string $modifier_type The type of the modifier (e.g., 'coupon', 'fee'). - */ - $statuses = apply_filters( 'tec_tickets_commerce_order_modifier_status_display', $statuses, $status, $this->modifier_type ); - - return $statuses[ $status ] ?? $status; - } - /** * Retrieves the page slug for the current modifier context. * diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index 52a77a4a35..9a7c805b86 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -21,6 +21,7 @@ use TEC\Tickets\Commerce\Order_Modifiers\Custom_Tables\Order_Modifiers as Table; use TEC\Tickets\Commerce\Order_Modifiers\Custom_Tables\Order_Modifiers_Meta; use TEC\Tickets\Commerce\Order_Modifiers\Models\Order_Modifier; +use TEC\Tickets\Commerce\Order_Modifiers\Traits\Status; use TEC\Tickets\Commerce\Order_Modifiers\Traits\Valid_Types; use TEC\Tickets\Exceptions\Not_Found_Exception; @@ -33,6 +34,7 @@ */ class Order_Modifiers extends Repository implements Insertable, Updatable, Deletable { + use Status; use Valid_Types; /** diff --git a/src/Tickets/Commerce/Order_Modifiers/Traits/Valid_Types.php b/src/Tickets/Commerce/Order_Modifiers/Traits/Valid_Types.php index 1b06fdb31b..485a80d6af 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Traits/Valid_Types.php +++ b/src/Tickets/Commerce/Order_Modifiers/Traits/Valid_Types.php @@ -183,44 +183,4 @@ protected static function get_valid_subtypes(): array { 'flat' => 1, ]; } - - /** - * Determine if a status is valid. - * - * @since 5.18.0 - * - * @param string $status The status. - * - * @return bool - */ - protected static function is_valid_status( string $status ): bool { - return array_key_exists( $status, self::get_valid_status() ); - } - - /** - * Get the valid order modifier status. - * - * @since 5.18.0 - * - * @return array The valid order modifier status. - */ - protected static function get_valid_status(): array { - $status = [ - 'active' => 1, - 'inactive' => 1, - 'draft' => 1, - ]; - - /** - * - * Get the valid order modifier statuses. - * - * Retrieves the list of valid statuses for an order modifier. - * - * @since 5.18.0 - * - * @return array The valid order modifier statuses. Keys are the status names, and values are integer flags. - */ - return (array) apply_filters( 'tec_tickets_commerce_order_modifier_status_flags', $status ); - } } From c0cc7ddd4d0cf0a6d685c574b58eb8b317b8334a Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Tue, 24 Dec 2024 13:35:33 -0600 Subject: [PATCH 04/47] Add wrapper functions to get table names This makes interpolation easier --- .../Repositories/Order_Modifiers.php | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index 9a7c805b86..824b1b0004 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -72,7 +72,7 @@ public function delete( Model $model ): bool { $this->validate_model_type( $model ); return (bool) DB::delete( - Table::table_name(), + $this->get_table_name(), [ 'id' => $model->id ], [ '%d' ] ); @@ -92,7 +92,7 @@ public function insert( Model $model ): Model { $this->validate_model_type( $model ); DB::insert( - Table::table_name(), + $this->get_table_name(), [ 'modifier_type' => $model->modifier_type, 'sub_type' => $model->sub_type, @@ -136,7 +136,7 @@ public function update( Model $model ): Model { $this->validate_model_type( $model ); DB::update( - Table::table_name(), + $this->get_table_name(), [ 'modifier_type' => $model->modifier_type, 'sub_type' => $model->sub_type, @@ -364,8 +364,8 @@ public function find_by_modifier_type_and_meta( } // Get the table names dynamically. - $order_modifiers_table = Table::table_name(); - $order_modifiers_meta_table = Order_Modifiers_Meta::table_name(); + $order_modifiers_table = $this->get_table_name(); + $order_modifiers_meta_table = $this->get_meta_table_name(); // Initialize the SQL query with the base WHERE clause for modifier_type. $sql = []; @@ -427,7 +427,37 @@ public function prepareQuery(): ModelQueryBuilder { $builder = new ModelQueryBuilder( $class ); - return $builder->from( Table::table_name( false ) ); + return $builder->from( $this->get_table_name( false ) ); + } + + /** + * Wrapper for getting the table name. + * + * This allows for easy interpolation in strings. + * + * @since TBD + * + * @param bool $with_prefix Whether to include the table prefix. Default is true. + * + * @return string The table name. + */ + protected function get_table_name( bool $with_prefix = true ): string { + return Table::table_name( $with_prefix ); + } + + /** + * Wrapper for getting the meta table name. + * + * This allows for easy interpolation in strings. + * + * @since TBD + * + * @param bool $with_prefix Whether to include the table prefix. Default is true. + * + * @return string The meta table name. + */ + protected function get_meta_table_name( bool $with_prefix = true ): string { + return Order_Modifiers_Meta::table_name( $with_prefix ); } /** From 55f23b3a11cbb87d524a53fe6dba26b460541b1b Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Tue, 24 Dec 2024 14:57:54 -0600 Subject: [PATCH 05/47] Create separate method for adding ->from() to the query builder --- .../Repositories/Order_Modifiers.php | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index 824b1b0004..2f3a0a2ac0 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -176,7 +176,7 @@ public function update( Model $model ): Model { * @throws RuntimeException If we didn't get an Order_Modifier object. */ public function find_by_id( int $id ): Order_Modifier { - $result = $this->prepareQuery() + $result = $this->get_query_builder_with_from() ->where( 'id', $id ) ->get(); @@ -208,7 +208,7 @@ public function search_modifiers( array $args = [] ): array { $args = array_merge( $defaults, $args ); // Start building the query. - $query = $this->prepareQuery(); + $query = $this->get_query_builder_with_from(); // Add search functionality (search in display_name or slug). if ( ! empty( $args['search_term'] ) ) { @@ -243,7 +243,7 @@ public function search_modifiers( array $args = [] ): array { * @return Order_Modifier[] Array of active Order Modifier model instances, or null if not found. */ public function find_active(): array { - $result = $this->prepareQuery() + $result = $this->get_query_builder_with_from() ->where( 'modifier_type', $this->modifier_type ) ->where( 'status', 'active' ) ->getAll(); @@ -262,7 +262,7 @@ public function find_active(): array { * @throws Not_Found_Exception If the Order Modifier is not found. */ public function find_by_slug( string $slug ): Order_Modifier { - $result = $this->prepareQuery() + $result = $this->get_query_builder_with_from() ->where( 'modifier_type', $this->modifier_type ) ->where( 'slug', $slug ) ->where( 'status', 'active' ) @@ -279,7 +279,7 @@ public function find_by_slug( string $slug ): Order_Modifier { * @return Order_Modifier[] Array of Order Modifier model instances. */ public function get_all(): array { - $results = $this->prepareQuery() + $results = $this->get_query_builder_with_from() ->where( 'modifier_type', $this->modifier_type ) ->getAll(); @@ -418,14 +418,28 @@ public function find_by_modifier_type_and_meta( * * @since 5.18.0 * - * @return ModelQueryBuilder + * @return ModelQueryBuilder The query builder object. */ public function prepareQuery(): ModelQueryBuilder { // Determine the model class based on the modifier type. $this->validate_type( $this->modifier_type ); $class = $this->get_valid_types()[ $this->modifier_type ]; - $builder = new ModelQueryBuilder( $class ); + return new ModelQueryBuilder( $class ); + } + + /** + * Wrapper for getting the query builder with table name as the FROM clause. + * + * This will call ->from() on the query builder with the table name before + * the object is returned. + * + * @since TBD + * + * @return ModelQueryBuilder The query builder object. + */ + protected function get_query_builder_with_from(): ModelQueryBuilder { + $builder = $this->prepareQuery(); return $builder->from( $this->get_table_name( false ) ); } From f4883ae5230462a8e265b459189a369d9a8e801d Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Tue, 24 Dec 2024 15:00:45 -0600 Subject: [PATCH 06/47] Use method parameters for JOIN aliases --- .../Repositories/Order_Modifiers.php | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index 2f3a0a2ac0..01a2be44c3 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -304,15 +304,24 @@ public function get_all(): array { public function find_relationship_by_post_ids( array $post_ids, string $modifier_type, string $status = 'active' ): array { $this->validate_type( $modifier_type ); - $order_modifiers_table = Relationship_Table::base_table_name(); - $builder = new ModelQueryBuilder( $this->get_valid_types()[ $modifier_type ] ); - - $results = $builder->from( Table::table_name( false ) . ' as m' ) - ->select( 'm.*' ) - ->innerJoin( "{$order_modifiers_table} as r", 'm.id', 'r.modifier_id' ) - ->whereIn( 'r.post_id', $post_ids ) - ->where( 'm.modifier_type', $modifier_type ) - ->where( 'm.status', $status ) + $builder = $this->prepareQuery(); + + // Table aliases for the query. + $modifiers = 'm'; + $relationships = 'r'; + + $results = $builder + ->from( $this->get_table_name( false ), $modifiers ) + ->select( "{$modifiers}.*" ) + ->innerJoin( + Relationship_Table::base_table_name(), + "{$modifiers}.id", + "{$relationships}.modifier_id", + $relationships + ) + ->whereIn( "{$relationships}.post_id", $post_ids ) + ->where( "{$modifiers}.modifier_type", $modifier_type ) + ->where( "{$modifiers}.status", $status ) ->getAll(); return $results ?? []; From b5e162fdcf53b563418419227e9e3d6fd9c28d0b Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Tue, 24 Dec 2024 18:07:07 -0600 Subject: [PATCH 07/47] Shorten names of class properties --- .../Order_Modifiers/Modifiers/Coupon.php | 4 +- .../Order_Modifiers/Modifiers/Fee.php | 4 +- .../Modifiers/Modifier_Abstract.php | 49 ++++++++++--------- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Coupon.php b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Coupon.php index 70250f2a38..398ed46d88 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Coupon.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Coupon.php @@ -173,14 +173,14 @@ public function render_edit( array $context ): void { * @return array The context data ready for rendering the form. */ public function map_context_to_template( array $context ): array { - $order_modifier_coupon_limit_meta_value = $this->order_modifiers_meta_repository->find_by_order_modifier_id_and_meta_key( $context['modifier_id'], 'coupons_available' )->meta_value ?? ''; + $limit_value = $this->meta_repository->find_by_order_modifier_id_and_meta_key( $context['modifier_id'], 'coupons_available' )->meta_value ?? ''; return [ 'order_modifier_display_name' => $context['display_name'] ?? '', 'order_modifier_slug' => $context['slug'] ?? $this->generate_unique_slug(), 'order_modifier_sub_type' => $context['sub_type'] ?? '', 'order_modifier_fee_amount_cents' => $this->convert_from_raw_amount( $context['raw_amount'] ?? 0 ), 'order_modifier_status' => $context['status'] ?? '', - 'order_modifier_coupon_limit' => $order_modifier_coupon_limit_meta_value ?? '', + 'order_modifier_coupon_limit' => $limit_value ?? '', ]; } diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Fee.php b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Fee.php index b358b9fea9..e3b374938a 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Fee.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Fee.php @@ -269,7 +269,7 @@ public function render_edit( array $context ): void { * @return array The context data ready for rendering the form. */ public function map_context_to_template( array $context ): array { - $order_modifier_fee_applied_to = $this->order_modifiers_meta_repository->find_by_order_modifier_id_and_meta_key( $context['modifier_id'], 'fee_applied_to' )->meta_value ?? ''; + $order_modifier_fee_applied_to = $this->meta_repository->find_by_order_modifier_id_and_meta_key( $context['modifier_id'], 'fee_applied_to' )->meta_value ?? ''; return [ 'order_modifier_display_name' => $context['display_name'] ?? '', 'order_modifier_slug' => $context['slug'] ?? $this->generate_unique_slug(), @@ -295,6 +295,6 @@ public function map_context_to_template( array $context ): array { * @return array The list of posts related to the modifier. */ public function get_active_on( $modifier_id ) { - return $this->order_modifiers_relationship_repository->find_by_modifier_id( $modifier_id ); + return $this->relationship_repository->find_by_modifier_id( $modifier_id ); } } diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php index f0feeafd72..517cea3cc1 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php @@ -23,22 +23,23 @@ use Exception; use InvalidArgumentException; use TEC\Common\StellarWP\Models\Contracts\Model; -use TEC\Tickets\Commerce\Order_Modifiers\Traits\Status; -use TEC\Tickets\Commerce\Order_Modifiers\Traits\Valid_Types; -use TEC\Tickets\Commerce\Utils\Value; -use TEC\Tickets\Exceptions\Not_Found_Exception; +use TEC\Tickets\Commerce\Order_Modifiers\Factory; use TEC\Tickets\Commerce\Order_Modifiers\Models\Order_Modifier; use TEC\Tickets\Commerce\Order_Modifiers\Models\Order_Modifier_Meta; use TEC\Tickets\Commerce\Order_Modifiers\Models\Order_Modifier_Relationships; use TEC\Tickets\Commerce\Order_Modifiers\Modifier_Admin_Handler; -use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifiers as Order_Modifiers_Repository; -use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifiers_Meta as Order_Modifiers_Meta_Repository; -use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifier_Relationship as Order_Modifier_Relationship_Repository; +use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifier_Relationship as Relationship_Repo; +use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifiers as Modifiers_Repo; +use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifiers_Meta as Meta_Repo; +use TEC\Tickets\Commerce\Order_Modifiers\Traits\Status; +use TEC\Tickets\Commerce\Order_Modifiers\Traits\Valid_Types; use TEC\Tickets\Commerce\Order_Modifiers\Values\Currency_Value; use TEC\Tickets\Commerce\Order_Modifiers\Values\Float_Value; use TEC\Tickets\Commerce\Order_Modifiers\Values\Percent_Value; use TEC\Tickets\Commerce\Order_Modifiers\Values\Positive_Integer_Value; use TEC\Tickets\Commerce\Order_Modifiers\Values\Precision_Value; +use TEC\Tickets\Commerce\Utils\Value; +use TEC\Tickets\Exceptions\Not_Found_Exception; /** * Class Modifier_Abstract @@ -64,25 +65,25 @@ abstract class Modifier_Abstract implements Modifier_Strategy_Interface { * The repository for interacting with the order modifiers table. * * @since 5.18.0 - * @var Order_Modifiers_Repository + * @var Modifiers_Repo */ - protected Order_Modifiers_Repository $repository; + protected Modifiers_Repo $repository; /** * The repository for interacting with the order modifiers meta table. * * @since 5.18.0 - * @var Order_Modifiers_Meta_Repository Repository + * @var Meta_Repo Repository */ - protected Order_Modifiers_Meta_Repository $order_modifiers_meta_repository; + protected Meta_Repo $meta_repository; /** * The repository for interacting with the order modifier relationship table. * * @since 5.18.0 - * @var Order_Modifier_Relationship_Repository Repository + * @var Relationship_Repo Repository */ - protected Order_Modifier_Relationship_Repository $order_modifiers_relationship_repository; + protected Relationship_Repo $relationship_repository; /** * Fields required by this modifier. @@ -99,9 +100,9 @@ abstract class Modifier_Abstract implements Modifier_Strategy_Interface { * @since 5.18.0 */ public function __construct() { - $this->repository = new Order_Modifiers_Repository( $this->modifier_type ); - $this->order_modifiers_meta_repository = new Order_Modifiers_Meta_Repository(); - $this->order_modifiers_relationship_repository = new Order_Modifier_Relationship_Repository(); + $this->repository = Factory::get_repository_for_type( $this->modifier_type ); + $this->meta_repository = new Meta_Repo(); + $this->relationship_repository = new Relationship_Repo(); } /** @@ -436,7 +437,7 @@ protected function handle_meta_data( int $modifier_id, array $args = [] ): Model } // Upsert the metadata using the repository. - return $this->order_modifiers_meta_repository->upsert_meta( new Order_Modifier_Meta( $meta_data ) ); + return $this->meta_repository->upsert_meta( new Order_Modifier_Meta( $meta_data ) ); } @@ -459,7 +460,7 @@ protected function add_relationship( int $modifier_id, int $post_id ): void { 'post_id' => $post_id, 'post_type' => get_post_type( $post_id ), ]; - $this->order_modifiers_relationship_repository->insert( new Order_Modifier_Relationships( $data ) ); + $this->relationship_repository->insert( new Order_Modifier_Relationships( $data ) ); } /** @@ -475,7 +476,7 @@ protected function add_relationship( int $modifier_id, int $post_id ): void { * @return void */ public function delete_relationship_by_modifier( int $modifier_id ): void { - $this->order_modifiers_relationship_repository->clear_relationships_by_modifier_id( $modifier_id ); + $this->relationship_repository->clear_relationships_by_modifier_id( $modifier_id ); } /** @@ -495,7 +496,7 @@ public function delete_relationship_by_post( int $post_id ): void { 'post_id' => $post_id, 'post_type' => get_post_type( $post_id ), ]; - $this->order_modifiers_relationship_repository->clear_relationships_by_post_id( new Order_Modifier_Relationships( $data ) ); + $this->relationship_repository->clear_relationships_by_post_id( new Order_Modifier_Relationships( $data ) ); } /** @@ -552,12 +553,12 @@ abstract protected function get_plural_name(): string; */ public function maybe_clear_relationships( int $modifier_id, string $new_apply_type ): void { // Retrieve the current apply_type from the metadata. - $current_apply_type = $this->order_modifiers_meta_repository->find_by_order_modifier_id_and_meta_key( $modifier_id, 'fee_applied_to' )->meta_value ?? null; + $current_apply_type = $this->meta_repository->find_by_order_modifier_id_and_meta_key( $modifier_id, 'fee_applied_to' )->meta_value ?? null; // If the apply_type has changed, clear all relationships. if ( $current_apply_type !== $new_apply_type ) { // Clear the relationships for this modifier. - $this->order_modifiers_relationship_repository->clear_relationships_by_modifier_id( $modifier_id ); + $this->relationship_repository->clear_relationships_by_modifier_id( $modifier_id ); } } @@ -586,7 +587,7 @@ public function delete_modifier( int $modifier_id ): bool { $this->delete_relationship_by_modifier( $modifier_id ); // Delete associated meta data. - $this->order_modifiers_meta_repository->delete( new Order_Modifier_Meta( [ 'id' => $modifier_id ] ) ); + $this->meta_repository->delete( new Order_Modifier_Meta( [ 'id' => $modifier_id ] ) ); // Delete the modifier itself (mandatory). $delete_modifier = $this->repository->delete( @@ -620,7 +621,7 @@ public function delete_modifier( int $modifier_id ): bool { * @return mixed|null The meta data found, or null if no matching record is found. */ public function get_order_modifier_meta_by_key( int $order_modifier_id, string $meta_key ) { - return $this->order_modifiers_meta_repository->find_by_order_modifier_id_and_meta_key( $order_modifier_id, $meta_key ); + return $this->meta_repository->find_by_order_modifier_id_and_meta_key( $order_modifier_id, $meta_key ); } /** From 72f25c8d0a82a39e4d214e19e2baa0566a6d17df Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Tue, 24 Dec 2024 18:15:59 -0600 Subject: [PATCH 08/47] Update get_modifier_id() to match actual behavior of the code --- .../Order_Modifiers/Modifiers/Modifier_Abstract.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php index 517cea3cc1..74eb68f600 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php @@ -22,6 +22,7 @@ use Exception; use InvalidArgumentException; +use RuntimeException; use TEC\Common\StellarWP\Models\Contracts\Model; use TEC\Tickets\Commerce\Order_Modifiers\Factory; use TEC\Tickets\Commerce\Order_Modifiers\Models\Order_Modifier; @@ -154,14 +155,13 @@ public function update_modifier( array $data ): Model { * * @since 5.18.0 * - * @param int $modifier_id The modifier ID. + * @param int $modifier_id The modifier ID. * - * - * @return array|null The modifier data or null if not found. + * @return array The modifier data as an array. + * @throws RuntimeException If the modifier is not found. */ public function get_modifier_by_id( int $modifier_id ): ?array { - $modifier_data = $this->repository->find_by_id( $modifier_id ); - return $modifier_data ? $modifier_data->to_array() : null; + return $this->repository->find_by_id( $modifier_id )->to_array(); } /** From 7795d62c689e119f91031a30d4b48938dd11bde7 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Tue, 24 Dec 2024 18:33:26 -0600 Subject: [PATCH 09/47] Simplify required field logic --- .../Modifiers/Modifier_Abstract.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php index 74eb68f600..20c9e6706a 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php @@ -197,17 +197,17 @@ public function validate_data( array $data ): bool { $missing_fields = array_diff_key( $this->required_fields, $data ); if ( ! empty( $missing_fields ) ) { $errors[] = sprintf( - /* translators: %s: List of missing fields. */ + /* translators: %s: List of missing fields. */ __( 'The following required fields are missing: %s', 'event-tickets' ), implode( ', ', array_keys( $missing_fields ) ) ); } // Validate required fields are not empty. - foreach ( $this->required_fields as $field => $required ) { - if ( $required && ( ! isset( $data[ $field ] ) || ( is_string( $data[ $field ] ) && trim( $data[ $field ] ) === '' ) ) ) { + foreach ( $this->required_fields as $field => $r ) { + if ( ! is_string( $data[ $field ] ) || trim( $data[ $field ] ) === '' ) { $errors[] = sprintf( - /* translators: %s: Field name. */ + /* translators: %s: Field name. */ __( 'The field "%s" is required and cannot be empty.', 'event-tickets' ), $field ); @@ -217,7 +217,7 @@ public function validate_data( array $data ): bool { // Validate the sub_type field, if present. if ( ! empty( $data['sub_type'] ) && ! $this->is_valid_subtype( $data['sub_type'] ) ) { $errors[] = sprintf( - /* translators: %s: Invalid sub-type value. */ + /* translators: %s: Invalid sub-type value. */ __( 'The provided sub-type "%s" is invalid. Please use a valid sub-type.', 'event-tickets' ), $data['sub_type'] ); @@ -226,7 +226,7 @@ public function validate_data( array $data ): bool { // Validate the status field, if present. if ( ! empty( $data['status'] ) && ! $this->is_valid_status( $data['status'] ) ) { $errors[] = sprintf( - /* translators: %s: Invalid status value. */ + /* translators: %s: Invalid status value. */ __( 'The provided status "%s" is invalid. Please use a valid status.', 'event-tickets' ), $data['status'] ); @@ -236,7 +236,7 @@ public function validate_data( array $data ): bool { if ( ! empty( $errors ) ) { throw new InvalidArgumentException( sprintf( - /* translators: %s: Validation error messages. */ + /* translators: %s: Validation error messages. */ __( 'Validation failed: %s', 'event-tickets' ), implode( '; ', $errors ) ) From 41f296d7ab5a95c68e08a68f2ae8f75c6c1a5962 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Tue, 24 Dec 2024 18:33:52 -0600 Subject: [PATCH 10/47] Add get_modifier_by_applied_to() method --- .../Repositories/Order_Modifiers.php | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index 01a2be44c3..a2d97966a9 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -11,6 +11,7 @@ use RuntimeException; use TEC\Common\StellarWP\DB\DB; +use TEC\Common\StellarWP\DB\QueryBuilder\QueryBuilder; use TEC\Common\StellarWP\Models\Contracts\Model; use TEC\Common\StellarWP\Models\ModelQueryBuilder; use TEC\Common\StellarWP\Models\Repositories\Contracts\Deletable; @@ -422,6 +423,92 @@ public function find_by_modifier_type_and_meta( return $results; } + /** + * Finds Order Modifiers by applied_to value. + * + * @since TBD + * + * @param string[] $applied_to The value(s) to filter the query by. + * @param array $params { Optional. Parameters to filter the query. + * @type string[] $status The status of the modifiers to filter by. Default 'active'. + * @type int $limit The number of results to return. Default 10. + * @type string $order The order of the results. Default 'DESC'. + * } + * + * @return array + */ + public function get_modifier_by_applied_to( array $applied_to, array $params = [] ): array { + // Set up default query parameters. + $params = wp_parse_args( $params, $this->get_default_query_params() ); + + // Validate the parameters before using them in the query. + $valid_params = $this->get_valid_params( $params ); + + // Filter out empty and duplicate values. + $applied_to = array_unique( array_filter( array_map( 'trim', $applied_to ) ) ); + + // Generate a cache key based on the arguments. + $cache_key = 'modifier_type_applied_to_' . md5( + wp_json_encode( + [ + $this->modifier_type, + $applied_to, + $valid_params, + ] + ) + ); + + $tribe_cache = tribe( 'cache' ); + + // Try to get the results from the cache. + $cached_results = $tribe_cache[ $cache_key ] ?? false; + if ( $cached_results && is_array( $cached_results ) ) { + return $cached_results; + } + + // Table aliases for the query. + $modifiers = 'o'; + $meta = 'm'; + + // Initialize the query builder and construct the query. + $builder = new QueryBuilder(); + $builder + ->from( $this->get_table_name( false ), $modifiers) + ->select( "{$modifiers}.*", "{$meta}.meta_value" ) + ->innerJoin( + $this->get_meta_table_name( false ), + "{$modifiers}.id", + "{$meta}.order_modifier_id", + $meta + ) + ->where( "{$modifiers}.modifier_type", $this->modifier_type ) + ->where( "{$meta}.meta_key", $this->get_applied_to_key() ) + ->whereIn( "{$meta}.meta_value", $applied_to ) + ; + + // Add the status params to the pieces. + if ( array_key_exists( 'status', $valid_params ) ) { + $builder->whereIn( "{$modifiers}.status", $valid_params['status'] ); + } + + // Add the order param to the pieces. + if ( array_key_exists( 'order', $valid_params ) ) { + $builder->orderBy( "{$modifiers}.id", $valid_params['order'] ); + } + + // Add the limit param to the pieces. + if ( array_key_exists( 'limit', $valid_params ) ) { + $builder->limit( $valid_params['limit'] ); + } + + $results = $builder->getAll() ?? []; + + // Cache the results for future use. + $tribe_cache[ $cache_key ] = $results; + + return $results; + } + /** * Prepare a query builder for the repository. * @@ -483,6 +570,85 @@ protected function get_meta_table_name( bool $with_prefix = true ): string { return Order_Modifiers_Meta::table_name( $with_prefix ); } + /** + * Get the default query parameters. + * + * @since TBD + * + * @return array The default query parameters. + */ + protected function get_default_query_params(): array { + return [ + 'status' => [ 'active' ], + 'limit' => 10, + 'order' => 'ASC', + ]; + } + + /** + * Get the valid parameters for the query. + * + * This will remove any parameters that we don't handle from the query and do basic + * validation of the value of each query parameter. + * + * @since TBD + * + * @param array $params The parameters to validate. + * + * @return array The valid parameters. + */ + protected function get_valid_params( array $params ): array { + $valid_params = []; + foreach ( $params as $key => $value ) { + switch ( $key ) { + case 'status': + $valid_params[ $key ] = array_filter( + (array) $value, + fn( $status ) => $this->is_valid_status( $status ) + ); + break; + + case 'order': + $value = strtoupper( $value ); + $valid_params[ $key ] = 'ASC' === $value ? 'ASC' : 'DESC'; + break; + + case 'limit': + $valid_params[ $key ] = absint( $value ); + break; + + // Default is to skip adding the parameter. + default: + break; + } + } + + return $valid_params; + } + + /** + * Get the key used to store the applied to value in the meta table. + * + * @since TBD + * + * @return string The key used to store the applied to value in the meta table. + */ + protected function get_applied_to_key(): string { + $default_key = "{$this->modifier_type}_applied_to"; + + /** + * Filters the key used to store the applied to value in the meta table. + * + * @since TBD + * + * @param string $result The key used to store the applied to value in the meta table. + * @param string $modifier_type The type of the modifier (e.g., 'coupon', 'fee'). + */ + $result = (string) apply_filters( 'tec_tickets_commerce_order_modifier_applied_to_key', $default_key, $this->modifier_type ); + + return ( ! empty( $result ) ) ? $result : $default_key; + } + /** * Normalize the return result to ensure we have an Order_Modifier object. * From ea8e61d57b859d17311c4693ff7215fce2cdbbcb Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 12:14:19 -0600 Subject: [PATCH 11/47] Use Factory class for tests --- tests/_support/Traits/Order_Modifiers.php | 6 +++--- .../Modifier_Admin_Handler_Test.php | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/_support/Traits/Order_Modifiers.php b/tests/_support/Traits/Order_Modifiers.php index 5a9edff01c..ccc3a36060 100644 --- a/tests/_support/Traits/Order_Modifiers.php +++ b/tests/_support/Traits/Order_Modifiers.php @@ -4,9 +4,9 @@ use TEC\Common\StellarWP\Models\Contracts\Model; use TEC\Tickets\Commerce\Order_Modifiers\Controller; +use TEC\Tickets\Commerce\Order_Modifiers\Factory; use TEC\Tickets\Commerce\Order_Modifiers\Models\Order_Modifier; use TEC\Tickets\Commerce\Order_Modifiers\Modifiers\Modifier_Manager; -use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifiers as Order_Modifiers_Repository; trait Order_Modifiers { @@ -57,14 +57,14 @@ protected function upsert_order_modifier_for_test( array $data ): Model { * @return Order_Modifier The retrieved order modifier. */ protected function get_order_modifier_for_test( int $modifier_id, $type = 'coupon' ) { - $order_modifier_repository = new Order_Modifiers_Repository( $type ); + $order_modifier_repository = Factory::get_repository_for_type( $type ); // Retrieve the modifier by ID. return $order_modifier_repository->find_by_id( $modifier_id ); } protected function clear_all_modifiers( $type = 'coupon' ) { - $order_modifier_repository = new Order_Modifiers_Repository( $type ); + $order_modifier_repository = Factory::get_repository_for_type( $type ); $all_modifiers = $order_modifier_repository->get_all(); diff --git a/tests/order_modifiers_integration/Modifier_Admin_Handler_Test.php b/tests/order_modifiers_integration/Modifier_Admin_Handler_Test.php index 5e7ecc247f..2f580a9f14 100644 --- a/tests/order_modifiers_integration/Modifier_Admin_Handler_Test.php +++ b/tests/order_modifiers_integration/Modifier_Admin_Handler_Test.php @@ -13,7 +13,6 @@ use Generator; use Tribe\Tickets\Test\Traits\Order_Modifiers; use TEC\Tickets\Exceptions\Not_Found_Exception; -use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifiers as Order_Modifier_Repository; class Modifier_Admin_Handler_Test extends Controller_Test_Case { use With_Uopz; @@ -342,7 +341,7 @@ function () use ( $data ) { $this->assertGreaterThan( 0, $modifier_id, 'The "modifier_id" parameter should be greater than 0.' ); // Validate data stored in the repository. - $modifier_repository = new Order_Modifier_Repository( $data['post_data']['modifier'] ); + $modifier_repository = Factory::get_repository_for_type( $data['post_data']['modifier'] ); $stored_modifier = $modifier_repository->find_by_id( $modifier_id ); $this->assertNotNull( $stored_modifier, 'The stored modifier should exist in the repository.' ); @@ -781,7 +780,7 @@ function () { $this->assertEquals( 'success', $query_params['deleted'] ?? null, 'Modifier should be successfully deleted.' ); // Step 3: Confirm the modifier was deleted. - $modifier_repository = new Order_Modifier_Repository( 'fee' ); + $modifier_repository = Factory::get_repository_for_type( 'fee' ); try { $deleted_modifier = $modifier_repository->find_by_id( $modifier_id ); @@ -847,7 +846,7 @@ function () { $this->assertGreaterThan( 0, intval( $modifier_id ), 'Modifier ID should be greater than 0.' ); // Step 2: Confirm the modifier exists in the repository. - $modifier_repository = new Order_Modifier_Repository( 'fee' ); + $modifier_repository = Factory::get_repository_for_type( 'fee' ); $created_modifier = $modifier_repository->find_by_id( $modifier_id ); $this->assertNotNull( $created_modifier, 'Created modifier should exist in the repository.' ); From 7f8f2910e22532096f7d169c7bdb16a850bd8ac0 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 12:35:28 -0600 Subject: [PATCH 12/47] Tweak formatting --- .../Repositories/Order_Modifiers_Meta.php | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers_Meta.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers_Meta.php index bc4b822d17..ce6d2b10d7 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers_Meta.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers_Meta.php @@ -137,13 +137,10 @@ public function upsert_meta( Order_Modifier_Meta $meta_data ): Model { $meta_data->meta_key ); - if ( $existing_meta ) { - // If the record exists, update it with the new data. - return $this->update( $meta_data ); - } - - // If no existing record is found, insert a new one. - return $this->insert( $meta_data ); + // If the record exists, update it with the new data, otherwise insert a new one. + return $existing_meta + ? $this->update( $meta_data ) + : $this->insert( $meta_data ); } /** @@ -157,8 +154,8 @@ public function upsert_meta( Order_Modifier_Meta $meta_data ): Model { */ public function find_by_order_modifier_id( int $order_modifier_id ): Model { return $this->prepareQuery() - ->where( 'order_modifier_id', $order_modifier_id ) - ->get(); + ->where( 'order_modifier_id', $order_modifier_id ) + ->get(); } /** @@ -173,9 +170,9 @@ public function find_by_order_modifier_id( int $order_modifier_id ): Model { */ public function find_by_order_modifier_id_and_meta_key( int $order_modifier_id, string $meta_key ): ?Order_Modifier_Meta { return $this->prepareQuery() - ->where( 'order_modifier_id', $order_modifier_id ) - ->where( 'meta_key', $meta_key ) - ->limit( 1 ) - ->get(); + ->where( 'order_modifier_id', $order_modifier_id ) + ->where( 'meta_key', $meta_key ) + ->limit( 1 ) + ->get(); } } From fa611f2e5fc09528b37df8bf8fcfa5d44159b5c8 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 13:05:23 -0600 Subject: [PATCH 13/47] Use QueryBuilder instead of raw SQL --- .../Order_Modifier_Relationship.php | 17 +++--- .../Repositories/Order_Modifiers.php | 59 ++++++++++--------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifier_Relationship.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifier_Relationship.php index d564e14399..fa3745a5c9 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifier_Relationship.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifier_Relationship.php @@ -214,13 +214,16 @@ public function find_by_post_id( int $post_id ): ?array { * @return ModelQueryBuilder The query builder with the necessary joins. */ protected function build_base_query(): ModelQueryBuilder { - $posts_table = 'posts'; - $order_modifiers_table = Order_Modifiers::base_table_name(); - return $this->prepareQuery() - ->select( 'r.id,m.id as modifier_id', 'p.ID as post_id', 'p.post_type', 'p.post_title' ) - ->innerJoin( "$order_modifiers_table as m", 'r.modifier_id', 'm.id' ) - ->innerJoin( "$posts_table as p", 'r.post_id', 'p.ID' ); + ->select( + 'r.id', + [ 'm.id', 'modifier_id' ], + [ 'p.ID', 'post_id' ], + 'p.post_type', + 'p.post_title' + ) + ->innerJoin( Order_Modifiers::base_table_name(), 'r.modifier_id', 'm.id', 'm' ) + ->innerJoin( 'posts', 'r.post_id', 'p.ID', 'p' ); } /** @@ -233,6 +236,6 @@ protected function build_base_query(): ModelQueryBuilder { public function prepareQuery(): ModelQueryBuilder { $builder = new ModelQueryBuilder( Relationship_Model::class ); - return $builder->from( Table::table_name( false ) . ' as r' ); + return $builder->from( Table::table_name( false ), 'r' ); } } diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index a2d97966a9..75d7651383 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -373,49 +373,50 @@ public function find_by_modifier_type_and_meta( return $cached_results; } - // Get the table names dynamically. - $order_modifiers_table = $this->get_table_name(); - $order_modifiers_meta_table = $this->get_meta_table_name(); + // Aliases for the tables. + $modifiers = 'o'; + $meta = 'm'; // Initialize the SQL query with the base WHERE clause for modifier_type. - $sql = []; - $sql[] = <<modifier_type ]; + $builder = new QueryBuilder(); + $builder + ->select( "{$modifiers}.*", "{$meta}.meta_value" ) + ->from( $this->get_table_name( false ), $modifiers ) + ->leftJoin( + $this->get_meta_table_name( false ), + "{$modifiers}.id", + "{$meta}.order_modifier_id", + $meta + ) + ->where( "{$modifiers}.modifier_type", $this->modifier_type ) + ->where( "{$modifiers}.status", 'active' ) + ; // Handle the meta_key condition: Use IFNULL if a default_meta_key is provided, otherwise check for meta_key directly. if ( $default_meta_key ) { - $sql[] = 'AND (IFNULL(m.meta_key, %s) = %s)'; - $params[] = $default_meta_key; + $builder->whereRaw( + "IFNULL({$meta}.meta_key, %s) = %s", + $default_meta_key, + $meta_key + ); } else { - $sql[] = 'AND m.meta_key = %s'; + $builder->where( "{$meta}.meta_key", $meta_key ); } - // Add the meta key to the params. - $params[] = $meta_key; - // Handle the meta_value condition: Use IFNULL if a default_meta_value is provided, otherwise check directly. - $meta_params_string = implode( ',', array_fill( 0, count( $meta_values ), '%s' ) ); if ( $default_meta_value ) { - $sql[] = "AND (IFNULL(m.meta_value, %s) IN ({$meta_params_string}))"; - $params[] = $default_meta_value; + $meta_params_string = implode( ',', array_fill( 0, count( $meta_values ), '%s' ) ); + $builder->whereRaw( + "IFNULL({$meta}.meta_value, %s) IN ({$meta_params_string})", + $default_meta_value, + ...$meta_values + ); } else { - $sql[] = "AND m.meta_value IN ({$meta_params_string})"; + $builder->whereIn( "{$meta}.meta_value", $meta_values ); } - $params = array_merge( $params, $meta_values ); - // Prepare and execute the query. - $results = DB::get_results( - DB::prepare( implode( ' ', $sql ), ...$params ) - ); + $results = $builder->getAll() ?? []; // Cache the results for future use. $tribe_cache[ $cache_key ] = $results; From f3e46881f0aa0076503ad208877da2fab78df938 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 15:35:39 -0600 Subject: [PATCH 14/47] Use factory for modifier model --- .../Commerce/Order_Modifiers/Models/Order_Modifier.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Models/Order_Modifier.php b/src/Tickets/Commerce/Order_Modifiers/Models/Order_Modifier.php index d2b2e3a1a1..2b6e8f5d2d 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Models/Order_Modifier.php +++ b/src/Tickets/Commerce/Order_Modifiers/Models/Order_Modifier.php @@ -16,7 +16,7 @@ use TEC\Common\StellarWP\Models\Model; use TEC\Common\StellarWP\Models\ModelQueryBuilder; use TEC\Tickets\Commerce\Order_Modifiers\Data_Transfer_Objects\Order_Modifier_DTO; -use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifiers as Repository; +use TEC\Tickets\Commerce\Order_Modifiers\Factory; use TEC\Tickets\Commerce\Order_Modifiers\Values\Float_Value; use TEC\Tickets\Commerce\Order_Modifiers\Values\Percent_Value; use TEC\Tickets\Commerce\Order_Modifiers\Values\Positive_Integer_Value; @@ -84,7 +84,7 @@ public static function find( $id ): ?self { return null; } - return ( new Repository( static::$order_modifier_type ) )->find_by_id( $id ); + return Factory::get_repository_for_type( static::$order_modifier_type )->find_by_id( $id ); } /** @@ -116,7 +116,7 @@ public static function create( array $attributes ): self { * @return static */ public function save(): self { - $repository = new Repository( $this->modifier_type ); + $repository = Factory::get_repository_for_type( $this->modifier_type ); if ( $this->id ) { $repository->update( $this ); @@ -136,7 +136,7 @@ public function save(): self { * @return bool Whether the model was deleted. */ public function delete(): bool { - return ( new Repository( $this->modifier_type ) )->delete( $this ); + return Factory::get_repository_for_type( $this->modifier_type )->delete( $this ); } /** @@ -147,7 +147,7 @@ public function delete(): bool { * @return ModelQueryBuilder The query builder instance. */ public static function query(): ModelQueryBuilder { - return tribe( Repository::class )->query(); + return Factory::get_repository_for_type( static::$order_modifier_type )->prepareQuery(); } /** From 442c6b6327b661300b89c67df4216cba3b27688d Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 15:36:19 -0600 Subject: [PATCH 15/47] Use direct methods for column headers --- .../Table_Views/Order_Modifier_Table.php | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php b/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php index b85d67a8f6..5e8120dbf0 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php +++ b/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php @@ -104,16 +104,16 @@ public function __construct( * @since 5.18.0 */ public function prepare_items() { - $columns = $this->get_columns(); - $hidden = []; - $sortable = $this->get_sortable_columns(); - $this->_column_headers = [ $columns, $hidden, $sortable ]; + $this->_column_headers = [ + $this->get_columns(), + $this->get_hidden_columns(), + $this->get_sortable_columns(), + ]; // Handle search. $search = tribe_get_request_var( 's', '' ); // Capture sorting parameters. - $orderby = sanitize_text_field( tribe_get_request_var( 'orderby', 'display_name' ) ); $order = sanitize_text_field( tribe_get_request_var( 'order', 'asc' ) ); @@ -329,6 +329,16 @@ public function render_title(): void { * * @return void */ - public function render_table_explain_text() { + public function render_table_explain_text() {} + + /** + * Retrieves hidden columns for the table. + * + * @since TBD + * + * @return array + */ + protected function get_hidden_columns(): array { + return []; } } From cf0cf92eb6b1876fe58d3fa3d5529768e07fe881 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 15:37:03 -0600 Subject: [PATCH 16/47] Use new method for getting fees --- .../Order_Modifiers/Repositories/Fees.php | 7 +--- .../Order_Modifiers/Traits/Fee_Types.php | 32 +++++++------------ 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Fees.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Fees.php index e35d937e45..42a157ae8e 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Fees.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Fees.php @@ -35,11 +35,6 @@ public function __construct() { * @return stdClass[] The array of fee objects from the database. */ public function get_all_automatic_fees() { - return $this->find_by_modifier_type_and_meta( - 'fee_applied_to', - [ 'all' ], - 'fee_applied_to', - 'all' - ); + return $this->get_modifier_by_applied_to( [ 'all' ] ); } } diff --git a/src/Tickets/Commerce/Order_Modifiers/Traits/Fee_Types.php b/src/Tickets/Commerce/Order_Modifiers/Traits/Fee_Types.php index 1e63b1344e..e0467a07b1 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Traits/Fee_Types.php +++ b/src/Tickets/Commerce/Order_Modifiers/Traits/Fee_Types.php @@ -10,8 +10,8 @@ namespace TEC\Tickets\Commerce\Order_Modifiers\Traits; use Exception; +use TEC\Tickets\Commerce\Order_Modifiers\Factory; use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifier_Relationship as Relationships; -use TEC\Tickets\Commerce\Order_Modifiers\Repositories\Order_Modifiers; /** * Trait Fee_Types @@ -20,15 +20,6 @@ */ trait Fee_Types { - /** - * The repository for interacting with the order modifiers table. - * - * @since 5.18.0 - * - * @var Order_Modifiers - */ - protected Order_Modifiers $modifiers_repository; - /** * The repository for interacting with the order modifiers relationships. * @@ -75,18 +66,19 @@ protected function get_selectable_fees( array $all_fees ) { * * @return array The fees. */ - protected function get_all_fees(): array { - $available_fees = $this->modifiers_repository->find_by_modifier_type_and_meta( - 'fee_applied_to', - [ 'per', 'all' ], - 'fee_applied_to', - 'all' + protected function get_all_fees( array $params = [] ): array { + $params = wp_parse_args( + $params, + [ + 'limit' => 100, + ] ); - // If no fees were found, return an empty array. - if ( null === $available_fees ) { - return []; - } + $available_fees = Factory::get_repository_for_type( 'fee' ) + ->get_modifier_by_applied_to( + [ 'per', 'all' ], + $params + ); // Convert the return value to an array keyed by the fee ID. return array_combine( From a1b282eea3f809165f79d8e45041f87ebcbd28f3 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 15:37:17 -0600 Subject: [PATCH 17/47] Remove unused properties --- src/Tickets/Commerce/Order_Modifiers/API/Fees.php | 5 ++--- .../Order_Modifiers/Admin/Order_Modifier_Fee_Metabox.php | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/API/Fees.php b/src/Tickets/Commerce/Order_Modifiers/API/Fees.php index df810fda45..582e807625 100644 --- a/src/Tickets/Commerce/Order_Modifiers/API/Fees.php +++ b/src/Tickets/Commerce/Order_Modifiers/API/Fees.php @@ -62,9 +62,8 @@ public function __construct( Manager $manager ) { parent::__construct( $container ); - $this->modifiers_repository = $fee_repository; - $this->relationships = $relationships; - $this->manager = $manager; + $this->relationships = $relationships; + $this->manager = $manager; } /** diff --git a/src/Tickets/Commerce/Order_Modifiers/Admin/Order_Modifier_Fee_Metabox.php b/src/Tickets/Commerce/Order_Modifiers/Admin/Order_Modifier_Fee_Metabox.php index 7967e3e135..ef11743cc6 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Admin/Order_Modifier_Fee_Metabox.php +++ b/src/Tickets/Commerce/Order_Modifiers/Admin/Order_Modifier_Fee_Metabox.php @@ -102,7 +102,6 @@ public function __construct( $this->manager = $manager; // Set up the order modifiers repository for accessing fee data. - $this->modifiers_repository = $fees_repository; $this->order_modifiers_relationship_repository = $order_modifier_relationship; } From e7cc6ba2d791a92392d659fde661c6879aa49d09 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 18:42:55 -0600 Subject: [PATCH 18/47] Correct the handling of raw amount --- .../Modifiers/Modifier_Abstract.php | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php index 20c9e6706a..50078f55ea 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php @@ -205,12 +205,26 @@ public function validate_data( array $data ): bool { // Validate required fields are not empty. foreach ( $this->required_fields as $field => $r ) { - if ( ! is_string( $data[ $field ] ) || trim( $data[ $field ] ) === '' ) { - $errors[] = sprintf( - /* translators: %s: Field name. */ - __( 'The field "%s" is required and cannot be empty.', 'event-tickets' ), - $field - ); + switch ( $field ) { + case 'raw_amount': + if ( ! is_float( $data[ $field ] ) ) { + $errors[] = sprintf( + /* translators: %s: Field name. */ + __( 'The field "%s" must be a valid number.', 'event-tickets' ), + $field + ); + } + break; + + default: + if ( ! is_string( $data[ $field ] ) || trim( $data[ $field ] ) === '' ) { + $errors[] = sprintf( + /* translators: %s: Field name. */ + __( 'The field "%s" is required and cannot be empty.', 'event-tickets' ), + $field + ); + } + break; } } From 35f2b655d50d28730697ff52119e295d3b78e653 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 18:43:51 -0600 Subject: [PATCH 19/47] Handle orderby in the parameters --- .../Repositories/Order_Modifiers.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index 75d7651383..c1457a5e3e 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -206,7 +206,7 @@ public function search_modifiers( array $args = [] ): array { ]; // Merge passed arguments with defaults. - $args = array_merge( $defaults, $args ); + $args = wp_parse_args( $args, $defaults ); // Start building the query. $query = $this->get_query_builder_with_from(); @@ -614,6 +614,20 @@ protected function get_valid_params( array $params ): array { $valid_params[ $key ] = 'ASC' === $value ? 'ASC' : 'DESC'; break; + case 'orderby': + $valid_orderby = [ + 'display_name' => 1, + 'slug' => 1, + 'raw_amount' => 1, + 'used' => 1, + 'remaining' => 1, + 'status' => 1, + ]; + if ( array_key_exists( $value, $valid_orderby ) ) { + $valid_params[ $key ] = $value; + } + break; + case 'limit': $valid_params[ $key ] = absint( $value ); break; From 742b96f9bf0eaf707b5a2b30bc5758a0903c1c25 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 19:44:50 -0600 Subject: [PATCH 20/47] Handle more query parameters --- .../Repositories/Order_Modifiers.php | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index c1457a5e3e..7e3a14bf13 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -580,9 +580,12 @@ protected function get_meta_table_name( bool $with_prefix = true ): string { */ protected function get_default_query_params(): array { return [ - 'status' => [ 'active' ], - 'limit' => 10, - 'order' => 'ASC', + 'limit' => 10, + 'order' => 'ASC', + 'orderby' => 'id', + 'page' => 1, + 'search_term' => '', + 'status' => [ 'active' ], ]; } @@ -602,11 +605,10 @@ protected function get_valid_params( array $params ): array { $valid_params = []; foreach ( $params as $key => $value ) { switch ( $key ) { - case 'status': - $valid_params[ $key ] = array_filter( - (array) $value, - fn( $status ) => $this->is_valid_status( $status ) - ); + case 'limit': + case 'offset': + case 'page': + $valid_params[ $key ] = absint( $value ); break; case 'order': @@ -628,8 +630,15 @@ protected function get_valid_params( array $params ): array { } break; - case 'limit': - $valid_params[ $key ] = absint( $value ); + case 'search_term': + $valid_params[ $key ] = DB::esc_like( $value ); + break; + + case 'status': + $valid_params[ $key ] = array_filter( + (array) $value, + fn( $status ) => $this->is_valid_status( $status ) + ); break; // Default is to skip adding the parameter. @@ -638,6 +647,11 @@ protected function get_valid_params( array $params ): array { } } + // If the page parameter is passed, set the offset based on the page and limit. + if ( array_key_exists( 'page', $valid_params ) && array_key_exists( 'limit', $valid_params ) ) { + $valid_params['offset'] = ( $valid_params['page'] - 1 ) * $valid_params['limit']; + } + return $valid_params; } From be70694f3874435eba4ccbd39857b9a90b8059fd Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 19:45:16 -0600 Subject: [PATCH 21/47] Correctly handle orderby options --- .../Commerce/Order_Modifiers/Repositories/Order_Modifiers.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index 7e3a14bf13..a68d5f3ec2 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -494,7 +494,8 @@ public function get_modifier_by_applied_to( array $applied_to, array $params = [ // Add the order param to the pieces. if ( array_key_exists( 'order', $valid_params ) ) { - $builder->orderBy( "{$modifiers}.id", $valid_params['order'] ); + $orderby = array_key_exists( 'orderby', $valid_params ) ? $valid_params['orderby'] : 'id'; + $builder->orderBy( "{$modifiers}.{$orderby}", $valid_params['order'] ); } // Add the limit param to the pieces. From cd9c501cd0c0dad6657599ed8e9b5f46dfc3de98 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 19:58:19 -0600 Subject: [PATCH 22/47] Use consistent methods for handling query args --- .../Repositories/Order_Modifiers.php | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index a68d5f3ec2..4e6840aeb7 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -198,36 +198,32 @@ public function find_by_id( int $id ): Order_Modifier { * @return Order_Modifier[] An array of Order_Modifiers or an empty array if none found. */ public function search_modifiers( array $args = [] ): array { - // Define default arguments. - $defaults = [ - 'search_term' => '', - 'orderby' => 'display_name', - 'order' => 'asc', - ]; - // Merge passed arguments with defaults. - $args = wp_parse_args( $args, $defaults ); + $args = wp_parse_args( $args, $this->get_default_query_params() ); + $valid_args = $this->get_valid_params( $args ); // Start building the query. $query = $this->get_query_builder_with_from(); // Add search functionality (search in display_name or slug). - if ( ! empty( $args['search_term'] ) ) { - $query = $query->whereLike( 'display_name', DB::esc_like( $args['search_term'] ) ); + if ( ! empty( $valid_args['search_term'] ) ) { + $query->whereLike( 'display_name', $valid_args['search_term'] ); } - // Add ordering. - $valid_orderby = [ - 'display_name' => 1, - 'slug' => 1, - 'raw_amount' => 1, - 'used' => 1, - 'remaining' => 1, - 'status' => 1, - ]; + // Set the order and orderby parameters. + if ( ! empty( $valid_args['order'] ) ) { + $orderby = array_key_exists( 'orderby', $valid_args ) ? $valid_args['orderby'] : 'display_name'; + $query->orderBy( $orderby, $valid_args['order'] ); + } + + // Add the query limit. + if ( ! empty( $valid_args['limit'] ) ) { + $query->limit( $valid_args['limit'] ); + } - if ( ! empty( $args['orderby'] ) && array_key_exists( $args['orderby'], $valid_orderby ) ) { - $query = $query->orderBy( $args['orderby'], $args['order'] ); + // Add the query offset. + if ( ! empty( $valid_args['offset'] ) ) { + $query->offset( $valid_args['offset'] ); } // Set the modifier type. From eddaf253d489789e3557762ada303e7243548d95 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 19:59:30 -0600 Subject: [PATCH 23/47] Add method for getting the count of items found by search --- .../Modifiers/Modifier_Abstract.php | 13 +++++++++ .../Repositories/Order_Modifiers.php | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php index 50078f55ea..1a560271b4 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Modifier_Abstract.php @@ -177,6 +177,19 @@ public function find_by_search( array $search ): array { return $this->repository->search_modifiers( $search ); } + /** + * Finds a modifier by the given search criteria and returns the count. + * + * @since TBD + * + * @param array $search Parameters to search Order Modifiers by. + * + * @return int The count of the modifiers found. + */ + public function find_count_by_search( array $search ): int { + return $this->repository->get_search_count( $search ); + } + /** * Validates the required fields for the modifier. * diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index 4e6840aeb7..23d95f2316 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -232,6 +232,34 @@ public function search_modifiers( array $args = [] ): array { return $query->getAll() ?? []; } + /** + * Get the count of Order Modifiers based on the given criteria. + * + * @since TBD + * + * @param array $args Arguments for the query. + * + * @return int Number of Order Modifiers found. + */ + public function get_search_count( array $args = [] ): int { + // Merge passed arguments with defaults. + $args = wp_parse_args( $args, $this->get_default_query_params() ); + $valid_args = $this->get_valid_params( $args ); + + // Start building the query. + $query = $this->get_query_builder_with_from(); + + // Add search functionality (search in display_name or slug). + if ( ! empty( $valid_args['search_term'] ) ) { + $query->whereLike( 'display_name', $valid_args['search_term'] ); + } + + // Set the modifier type. + $query = $query->where( 'modifier_type', $this->modifier_type ); + + return $query->count() ?? 0; + } + /** * Finds all active Order Modifiers of the current type. * From f97b1cb9207eb7d2bef2eb2ce5ab83f9bd1272dc Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 19:59:43 -0600 Subject: [PATCH 24/47] Update item retrieval with new methods --- .../Table_Views/Order_Modifier_Table.php | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php b/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php index 5e8120dbf0..8de64d150a 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php +++ b/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php @@ -113,30 +113,25 @@ public function prepare_items() { // Handle search. $search = tribe_get_request_var( 's', '' ); - // Capture sorting parameters. - $orderby = sanitize_text_field( tribe_get_request_var( 'orderby', 'display_name' ) ); - $order = sanitize_text_field( tribe_get_request_var( 'order', 'asc' ) ); + // Pagination parameters. + $per_page = $this->get_items_per_page( "{$this->modifier->get_modifier_type()}_per_page", 10 ); + $current_page = $this->get_pagenum(); // Fetch the data from the modifier class, including sorting. - $data = $this->modifier->find_by_search( + $this->items = $this->modifier->find_by_search( [ - 'search_term' => $search, - 'orderby' => $orderby, - 'order' => $order, - 'modifier_type' => $this->modifier->get_modifier_type(), + 'search_term' => $search, + 'orderby' => sanitize_text_field( tribe_get_request_var( 'orderby', 'display_name' ) ), + 'order' => sanitize_text_field( tribe_get_request_var( 'order', 'asc' ) ), + 'limit' => $per_page, + 'page' => $current_page, ] ); - // Pagination. - $per_page = $this->get_items_per_page( $this->modifier->get_modifier_type() . '_per_page', 10 ); - $current_page = $this->get_pagenum(); - $total_items = count( $data ); - - $data = array_slice( $data, ( $current_page - 1 ) * $per_page, $per_page ); - - // Set the items for the table. - $this->items = $data; + // Get the total number of items. + $total_items = $this->modifier->find_count_by_search( [ 'search_term' => $search ] ); + // Set the pagination args. $this->set_pagination_args( [ 'total_items' => $total_items, From 5c5b871d47cf8ad3f9475d4523b8dc994ba1ad51 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 22:33:47 -0600 Subject: [PATCH 25/47] Add new fee repo test --- .../Repositories/Fees.php | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tests/order_modifiers_integration/Repositories/Fees.php diff --git a/tests/order_modifiers_integration/Repositories/Fees.php b/tests/order_modifiers_integration/Repositories/Fees.php new file mode 100644 index 0000000000..d6352d32e1 --- /dev/null +++ b/tests/order_modifiers_integration/Repositories/Fees.php @@ -0,0 +1,80 @@ + '1000', + 'sub_type' => 'flat', + ], + [ + 'amount' => '10', + 'sub_type' => 'percentage', + ], + [ + 'amount' => '5', + 'sub_type' => 'percentage', + ], + [ + 'amount' => '1', + 'sub_type' => 'flat', + ], + [ + 'amount' => '20', + 'sub_type' => 'flat', + ], + ]; + + foreach ( $samples as $index => $sample ) { + $data = [ + 'order_modifier_amount' => $sample['amount'], + 'order_modifier_sub_type' => $sample['sub_type'], + 'order_modifier_slug' => "test_fee_{$index}_1", + 'order_modifier_display_name' => "Test Fee {$index} – 1", + ]; + + $this->upsert_order_modifier_for_test( $data ); + + $data['order_modifier_slug'] = "test_fee_{$index}_2"; + $data['order_modifier_display_name'] = "Test Fee {$index} – 2"; + + $this->upsert_order_modifier_for_test( $data ); + } + } + + /** + * @test + * @return void + */ + public function should_find_all_fees() { + $this->create_modifiers(); + + $repo = Factory::get_repository_for_type( $this->modifier_type ); + + // Test that we get the correct count of all fees. + $count = $repo->get_search_count(); + $this->assertEquals( 20, $count ); + + // Test that we get the correct number of fees with a limit. + $results = $repo->search_modifiers( [ 'limit' => 5 ] ); + $this->assertCount( 5, $results ); + } +} From 09fdf9de71b884b23a518ad5798d8bef73370356 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 22:49:16 -0600 Subject: [PATCH 26/47] Add changelog file --- changelog/feature-ET-2268-update-modifier-queries | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog/feature-ET-2268-update-modifier-queries diff --git a/changelog/feature-ET-2268-update-modifier-queries b/changelog/feature-ET-2268-update-modifier-queries new file mode 100644 index 0000000000..9acb656672 --- /dev/null +++ b/changelog/feature-ET-2268-update-modifier-queries @@ -0,0 +1,4 @@ +Significance: minor +Type: performance + +Enhance the performance of order modifier database queries [ET-2268] From 3a0dd42d0d145b1fcc514da83d8e2b24e47d4a8a Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Thu, 9 Jan 2025 22:52:57 -0600 Subject: [PATCH 27/47] Fix PHPCS issues --- .../Repositories/Order_Modifiers.php | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php index 23d95f2316..f69ca1b3d4 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php +++ b/src/Tickets/Commerce/Order_Modifiers/Repositories/Order_Modifiers.php @@ -199,7 +199,7 @@ public function find_by_id( int $id ): Order_Modifier { */ public function search_modifiers( array $args = [] ): array { // Merge passed arguments with defaults. - $args = wp_parse_args( $args, $this->get_default_query_params() ); + $args = wp_parse_args( $args, $this->get_default_query_params() ); $valid_args = $this->get_valid_params( $args ); // Start building the query. @@ -243,7 +243,7 @@ public function search_modifiers( array $args = [] ): array { */ public function get_search_count( array $args = [] ): int { // Merge passed arguments with defaults. - $args = wp_parse_args( $args, $this->get_default_query_params() ); + $args = wp_parse_args( $args, $this->get_default_query_params() ); $valid_args = $this->get_valid_params( $args ); // Start building the query. @@ -413,8 +413,7 @@ public function find_by_modifier_type_and_meta( $meta ) ->where( "{$modifiers}.modifier_type", $this->modifier_type ) - ->where( "{$modifiers}.status", 'active' ) - ; + ->where( "{$modifiers}.status", 'active' ); // Handle the meta_key condition: Use IFNULL if a default_meta_key is provided, otherwise check for meta_key directly. if ( $default_meta_key ) { @@ -454,7 +453,7 @@ public function find_by_modifier_type_and_meta( * @since TBD * * @param string[] $applied_to The value(s) to filter the query by. - * @param array $params { Optional. Parameters to filter the query. + * @param array $params { Optional. Parameters to filter the query. * @type string[] $status The status of the modifiers to filter by. Default 'active'. * @type int $limit The number of results to return. Default 10. * @type string $order The order of the results. Default 'DESC'. @@ -474,14 +473,14 @@ public function get_modifier_by_applied_to( array $applied_to, array $params = [ // Generate a cache key based on the arguments. $cache_key = 'modifier_type_applied_to_' . md5( - wp_json_encode( - [ - $this->modifier_type, - $applied_to, - $valid_params, - ] - ) - ); + wp_json_encode( + [ + $this->modifier_type, + $applied_to, + $valid_params, + ] + ) + ); $tribe_cache = tribe( 'cache' ); @@ -498,7 +497,7 @@ public function get_modifier_by_applied_to( array $applied_to, array $params = [ // Initialize the query builder and construct the query. $builder = new QueryBuilder(); $builder - ->from( $this->get_table_name( false ), $modifiers) + ->from( $this->get_table_name( false ), $modifiers ) ->select( "{$modifiers}.*", "{$meta}.meta_value" ) ->innerJoin( $this->get_meta_table_name( false ), @@ -508,8 +507,7 @@ public function get_modifier_by_applied_to( array $applied_to, array $params = [ ) ->where( "{$modifiers}.modifier_type", $this->modifier_type ) ->where( "{$meta}.meta_key", $this->get_applied_to_key() ) - ->whereIn( "{$meta}.meta_value", $applied_to ) - ; + ->whereIn( "{$meta}.meta_value", $applied_to ); // Add the status params to the pieces. if ( array_key_exists( 'status', $valid_params ) ) { @@ -637,7 +635,7 @@ protected function get_valid_params( array $params ): array { break; case 'order': - $value = strtoupper( $value ); + $value = strtoupper( $value ); $valid_params[ $key ] = 'ASC' === $value ? 'ASC' : 'DESC'; break; From 02540ebab31f8e718c66a797e745686c87e3c585 Mon Sep 17 00:00:00 2001 From: Jeremy Pry Date: Fri, 10 Jan 2025 12:20:13 -0600 Subject: [PATCH 28/47] Replace tribe_get_request_var() with tec_get_request_var() --- .../Order_Modifiers/Modifier_Admin_Handler.php | 12 ++++++------ .../Commerce/Order_Modifiers/Modifiers/Coupon.php | 4 ++-- .../Commerce/Order_Modifiers/Modifiers/Fee.php | 12 ++++++------ .../Table_Views/Order_Modifier_Table.php | 12 ++++++------ 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifier_Admin_Handler.php b/src/Tickets/Commerce/Order_Modifiers/Modifier_Admin_Handler.php index 9adf6c9d28..13153bafa2 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifier_Admin_Handler.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifier_Admin_Handler.php @@ -257,7 +257,7 @@ public function render_tec_order_modifiers_page(): void { */ protected function get_modifier_data_by_id( int $modifier_id ): ?array { // Get the modifier type from the request or use the default. - $modifier_type = tribe_get_request_var( 'modifier', $this->get_default_type() ); + $modifier_type = tec_get_request_var( 'modifier', $this->get_default_type() ); // Get the appropriate strategy for the selected modifier type. $modifier_strategy = tribe( Controller::class )->get_modifier( $modifier_type ); @@ -353,7 +353,7 @@ public function handle_form_submission(): void { return; } - $raw_data = tribe_get_request_vars( true ); + $raw_data = tec_get_request_vars( true ); $raw_data['order_modifier_id'] = $context['modifier_id']; try { @@ -464,10 +464,10 @@ protected function render_error_message( string $message ): void { */ public function handle_delete_modifier(): void { // Check if the action is 'delete_modifier' and nonce is set. - $action = tribe_get_request_var( 'action', '' ); - $modifier_id = absint( tribe_get_request_var( 'modifier_id', '' ) ); - $nonce = tribe_get_request_var( '_wpnonce', '' ); - $modifier_type = sanitize_key( tribe_get_request_var( 'modifier', '' ) ); + $action = tec_get_request_var( 'action', '' ); + $modifier_id = absint( tec_get_request_var( 'modifier_id', '' ) ); + $nonce = tec_get_request_var( '_wpnonce', '' ); + $modifier_type = sanitize_key( tec_get_request_var( 'modifier', '' ) ); // Early bail if the action is not 'delete_modifier'. if ( 'delete_modifier' !== $action ) { diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Coupon.php b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Coupon.php index 398ed46d88..4940ff1720 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Coupon.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Coupon.php @@ -88,7 +88,7 @@ public function insert_modifier( array $data ): Model { [ 'meta_key' => 'coupons_available', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value - 'meta_value' => tribe_get_request_var( 'order_modifier_coupon_limit', '' ), + 'meta_value' => tec_get_request_var( 'order_modifier_coupon_limit', '' ), ] ); @@ -114,7 +114,7 @@ public function update_modifier( array $data ): Model { [ 'meta_key' => 'coupons_available', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value - 'meta_value' => tribe_get_request_var( 'order_modifier_coupon_limit', '' ), + 'meta_value' => tec_get_request_var( 'order_modifier_coupon_limit', '' ), ] ); diff --git a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Fee.php b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Fee.php index e3b374938a..a22a8edaeb 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Modifiers/Fee.php +++ b/src/Tickets/Commerce/Order_Modifiers/Modifiers/Fee.php @@ -83,7 +83,7 @@ public function insert_modifier( array $data ): Model { $modifier = parent::insert_modifier( $data ); // Handle metadata (e.g., order_modifier_apply_to). - $apply_fee_to = tribe_get_request_var( 'order_modifier_apply_to', '' ); + $apply_fee_to = tec_get_request_var( 'order_modifier_apply_to', '' ); // Handle metadata (e.g., order_modifier_apply_to). $this->handle_meta_data( @@ -100,10 +100,10 @@ public function insert_modifier( array $data ): Model { switch ( $apply_fee_to ) { case 'venue': - $apply_to_post_id = tribe_get_request_var( 'venue_list', null ); + $apply_to_post_id = tec_get_request_var( 'venue_list', null ); break; case 'organizer': - $apply_to_post_id = tribe_get_request_var( 'organizer_list', null ); + $apply_to_post_id = tec_get_request_var( 'organizer_list', null ); break; } @@ -132,7 +132,7 @@ public function update_modifier( array $data ): Model { } // Handle metadata (e.g., order_modifier_apply_to). - $apply_fee_to = tribe_get_request_var( 'order_modifier_apply_to', '' ); + $apply_fee_to = tec_get_request_var( 'order_modifier_apply_to', '' ); $this->maybe_clear_relationships( $modifier->id, $apply_fee_to ); @@ -150,10 +150,10 @@ public function update_modifier( array $data ): Model { switch ( $apply_fee_to ) { case 'venue': - $apply_to_post_ids = tribe_get_request_var( 'venue_list', [] ); + $apply_to_post_ids = tec_get_request_var( 'venue_list', [] ); break; case 'organizer': - $apply_to_post_ids = tribe_get_request_var( 'organizer_list', [] ); + $apply_to_post_ids = tec_get_request_var( 'organizer_list', [] ); break; } diff --git a/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php b/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php index 8de64d150a..ab7401ae88 100644 --- a/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php +++ b/src/Tickets/Commerce/Order_Modifiers/Table_Views/Order_Modifier_Table.php @@ -111,7 +111,7 @@ public function prepare_items() { ]; // Handle search. - $search = tribe_get_request_var( 's', '' ); + $search = tec_get_request_var( 's', '' ); // Pagination parameters. $per_page = $this->get_items_per_page( "{$this->modifier->get_modifier_type()}_per_page", 10 ); @@ -121,8 +121,8 @@ public function prepare_items() { $this->items = $this->modifier->find_by_search( [ 'search_term' => $search, - 'orderby' => sanitize_text_field( tribe_get_request_var( 'orderby', 'display_name' ) ), - 'order' => sanitize_text_field( tribe_get_request_var( 'order', 'asc' ) ), + 'orderby' => tec_get_request_var( 'orderby', 'display_name' ), + 'order' => tec_get_request_var( 'order', 'asc' ), 'limit' => $per_page, 'page' => $current_page, ] @@ -217,10 +217,10 @@ protected function render_actions( string $label, array $actions ): string { * @return void */ public function search_box( $text, $input_id, $placeholder = '' ) { - $search_value = sanitize_text_field( tribe_get_request_var( 's', '' ) ); + $search_value = tec_get_request_var( 's', '' ); // Set the input ID. - $input_id = $input_id . '-search-input'; + $input_id = "{$input_id}-search-input"; // If no placeholder is provided, default to the display_name column. if ( empty( $placeholder ) ) { @@ -252,7 +252,7 @@ public function render_tabs(): void { } // Determine the current modifier, falling back to the default. - $current_modifier = tribe_get_request_var( 'modifier', $this->get_default_type() ); + $current_modifier = tec_get_request_var( 'modifier', $this->get_default_type() ); echo '