Commit 72464baddd for woocommerce

commit 72464baddd8599ab8b92c91c5765b265ccf4424f
Author: Hannah Tinkler <hannah.tinkler@gmail.com>
Date:   Fri Feb 6 15:19:12 2026 +0000

    Refactor data store to avoid passing in incomplete objects (#63065)

    * Refactor PushTokensDataStore to use arrays and IDs instead of objects.

    - Change create() to accept array data and return PushToken
    - Change read() to accept int ID and return PushToken
    - Change update() to accept int ID and array data
    - Change delete() to accept int ID
    - Change get_by_token_or_device_id() to accept array data

diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 1c0d6cd6bf..4424d26346 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -70914,18 +70914,6 @@ parameters:
 			count: 1
 			path: src/Internal/ProductImage/MatchImageBySKU.php

-		-
-			message: '#^Parameter \#1 \$id of method Automattic\\WooCommerce\\Internal\\PushNotifications\\Entities\\PushToken\:\:set_id\(\) expects int, int\|WP_Post given\.$#'
-			identifier: argument.type
-			count: 2
-			path: src/Internal/PushNotifications/DataStores/PushTokensDataStore.php
-
-		-
-			message: '#^Parameter \#2 \$object_ids of function update_meta_cache expects array\<int\>\|string, array\<int\|WP_Post\> given\.$#'
-			identifier: argument.type
-			count: 1
-			path: src/Internal/PushNotifications/DataStores/PushTokensDataStore.php
-
 		-
 			message: '#^@param string \$css does not accept actual type of parameter\: string\|false\.$#'
 			identifier: parameter.phpDocType
diff --git a/plugins/woocommerce/src/Internal/PushNotifications/Controllers/PushTokenRestController.php b/plugins/woocommerce/src/Internal/PushNotifications/Controllers/PushTokenRestController.php
index 0cfafa88cd..fea2c3abaa 100644
--- a/plugins/woocommerce/src/Internal/PushNotifications/Controllers/PushTokenRestController.php
+++ b/plugins/woocommerce/src/Internal/PushNotifications/Controllers/PushTokenRestController.php
@@ -104,23 +104,23 @@ class PushTokenRestController extends RestApiControllerBase {
 	 */
 	public function create( WP_REST_Request $request ) {
 		try {
-			$push_token = new PushToken();
-			$push_token->set_user_id( get_current_user_id() );
-			$push_token->set_token( $request->get_param( 'token' ) );
-			$push_token->set_platform( $request->get_param( 'platform' ) );
-			$push_token->set_device_uuid( $request->get_param( 'device_uuid' ) );
-			$push_token->set_origin( $request->get_param( 'origin' ) );
+			$data = array(
+				'user_id'     => get_current_user_id(),
+				'token'       => $request->get_param( 'token' ),
+				'platform'    => $request->get_param( 'platform' ),
+				'device_uuid' => $request->get_param( 'device_uuid' ),
+				'origin'      => $request->get_param( 'origin' ),
+			);

 			$data_store = wc_get_container()->get( PushTokensDataStore::class );
+			$push_token = $data_store->get_by_token_or_device_id( $data );

-			$existing_token = clone $push_token;
-			$existing_token = $data_store->get_by_token_or_device_id( $existing_token );
-
-			if ( $existing_token ) {
-				$push_token->set_id( (int) $existing_token->get_id() );
+			if ( $push_token ) {
+				$push_token->set_token( $data['token'] );
+				$push_token->set_device_uuid( $data['device_uuid'] );
 				$data_store->update( $push_token );
 			} else {
-				$data_store->create( $push_token );
+				$push_token = $data_store->create( $data );
 			}
 		} catch ( Exception $e ) {
 			return $this->convert_exception_to_wp_error( $e );
@@ -140,21 +140,28 @@ class PushTokenRestController extends RestApiControllerBase {
 	 * @param WP_REST_Request $request The request object.
 	 * @phpstan-param WP_REST_Request<array<string, mixed>> $request
 	 * @throws PushTokenNotFoundException If token does not belong to authenticated user.
+	 * @throws WC_Data_Exception If token wasn't deleted.
 	 * @return WP_REST_Response|WP_Error
 	 */
 	public function delete( WP_REST_Request $request ) {
 		try {
-			$push_token = new PushToken();
-			$push_token->set_id( (int) $request->get_param( 'id' ) );
-
+			$id         = (int) $request->get_param( 'id' );
 			$data_store = wc_get_container()->get( PushTokensDataStore::class );
-			$data_store->read( $push_token );
+			$push_token = $data_store->read( $id );

 			if ( $push_token->get_user_id() !== get_current_user_id() ) {
 				throw new PushTokenNotFoundException();
 			}

-			$data_store->delete( $push_token );
+			$deleted = $data_store->delete( $id );
+
+			if ( ! $deleted ) {
+				throw new WC_Data_Exception(
+					'woocommerce_push_token_not_deleted',
+					'The push token could not be deleted.',
+					WP_Http::INTERNAL_SERVER_ERROR
+				);
+			}
 		} catch ( Exception $e ) {
 			return $this->convert_exception_to_wp_error( $e );
 		}
diff --git a/plugins/woocommerce/src/Internal/PushNotifications/DataStores/PushTokensDataStore.php b/plugins/woocommerce/src/Internal/PushNotifications/DataStores/PushTokensDataStore.php
index 2207c9bac2..5b6e242d9a 100644
--- a/plugins/woocommerce/src/Internal/PushNotifications/DataStores/PushTokensDataStore.php
+++ b/plugins/woocommerce/src/Internal/PushNotifications/DataStores/PushTokensDataStore.php
@@ -34,12 +34,14 @@ class PushTokensDataStore {
 	 * Creates a post representing the push token.
 	 *
 	 * @since 10.5.0
-	 * @param PushToken $push_token An instance of PushToken.
-	 * @throws PushTokenInvalidDataException If the token can't be created.
+	 * @param array $data Token data with keys: user_id, token, platform, device_uuid (optional), origin.
+	 * @throws PushTokenInvalidDataException If the token data is invalid.
 	 * @throws WC_Data_Exception If the token creation fails.
-	 * @return void
+	 * @return PushToken The created push token with ID set.
 	 */
-	public function create( PushToken &$push_token ): void {
+	public function create( array $data ): PushToken {
+		$push_token = new PushToken( $data );
+
 		if ( ! $push_token->can_be_created() ) {
 			throw new PushTokenInvalidDataException(
 				'Can\'t create push token because the push token data provided is invalid.'
@@ -67,31 +69,28 @@ class PushTokensDataStore {
 		}

 		$push_token->set_id( $id );
+
+		return $push_token;
 	}

 	/**
 	 * Gets post representing a push token.
 	 *
 	 * @since 10.5.0
-	 * @param PushToken $push_token An instance of PushToken.
-	 * @throws PushTokenInvalidDataException If the token can't be read.
+	 * @param int $id The push token ID.
+	 * @throws PushTokenInvalidDataException If the ID is invalid.
 	 * @throws PushTokenNotFoundException If the token can't be found.
-	 * @return void
+	 * @return PushToken The populated push token.
 	 */
-	public function read( PushToken &$push_token ): void {
-		if ( ! $push_token->can_be_read() ) {
-			throw new PushTokenInvalidDataException(
-				'Can\'t read push token because the push token data provided is invalid.'
-			);
-		}
-
-		$post = get_post( $push_token->get_id() );
+	public function read( int $id ): PushToken {
+		$push_token = new PushToken( array( 'id' => $id ) );
+		$post       = get_post( $push_token->get_id() );

 		if ( ! $post || PushToken::POST_TYPE !== $post->post_type ) {
 			throw new PushTokenNotFoundException();
 		}

-		$meta = $this->build_meta_array_from_database( $push_token );
+		$meta = $this->build_meta_array_from_database( (int) $push_token->get_id() );

 		if (
 			empty( $meta['token'] )
@@ -109,34 +108,29 @@ class PushTokensDataStore {

 		$push_token->set_user_id( (int) $post->post_author );
 		$push_token->set_token( $meta['token'] );
-		$push_token->set_platform( $meta['platform'] );
 		$push_token->set_device_uuid( $meta['device_uuid'] ?? null );
+		$push_token->set_platform( $meta['platform'] );
 		$push_token->set_origin( $meta['origin'] );
+
+		return $push_token;
 	}

 	/**
 	 * Updates a post representing the push token.
 	 *
 	 * @since 10.5.0
-	 * @param PushToken $push_token An instance of PushToken.
+	 * @param PushToken $push_token The push token to update.
 	 * @throws PushTokenInvalidDataException If the token can't be updated.
-	 * @throws PushTokenNotFoundException If the token can't be found.
 	 * @throws WC_Data_Exception If the token update fails.
-	 * @return void
+	 * @return bool True on success.
 	 */
-	public function update( PushToken &$push_token ): void {
+	public function update( PushToken $push_token ): bool {
 		if ( ! $push_token->can_be_updated() ) {
 			throw new PushTokenInvalidDataException(
 				'Can\'t update push token because the push token data provided is invalid.'
 			);
 		}

-		$post = get_post( $push_token->get_id() );
-
-		if ( ! $post || PushToken::POST_TYPE !== $post->post_type ) {
-			throw new PushTokenNotFoundException();
-		}
-
 		$result = wp_update_post(
 			array(
 				'ID'          => (int) $push_token->get_id(),
@@ -161,31 +155,26 @@ class PushTokensDataStore {
 		if ( null === $push_token->get_device_uuid() ) {
 			delete_post_meta( (int) $push_token->get_id(), 'device_uuid' );
 		}
+
+		return true;
 	}

 	/**
 	 * Deletes a push token.
 	 *
 	 * @since 10.5.0
-	 * @param PushToken $push_token An instance of PushToken.
-	 * @throws PushTokenInvalidDataException If the token can't be deleted.
+	 * @param int $id The push token ID.
 	 * @throws PushTokenNotFoundException If the token can't be found.
-	 * @return void
+	 * @return bool True on success.
 	 */
-	public function delete( PushToken &$push_token ): void {
-		if ( ! $push_token->can_be_deleted() ) {
-			throw new PushTokenInvalidDataException(
-				'Can\'t delete push token because the push token data provided is invalid.'
-			);
-		}
-
-		$post = get_post( $push_token->get_id() );
+	public function delete( int $id ): bool {
+		$post = get_post( $id );

 		if ( ! $post || PushToken::POST_TYPE !== $post->post_type ) {
 			throw new PushTokenNotFoundException();
 		}

-		wp_delete_post( (int) $push_token->get_id(), true );
+		return (bool) wp_delete_post( (int) $id, true );
 	}

 	/**
@@ -196,29 +185,35 @@ class PushTokensDataStore {
 	 * avoid creating a duplicate.
 	 *
 	 * @since 10.5.0
-	 * @param PushToken $push_token An instance of PushToken.
+	 * @param array $data Token data with keys: user_id, platform, origin, token (optional), device_uuid (optional).
 	 * @return null|PushToken
 	 * @throws PushTokenInvalidDataException If push token is missing data.
 	 */
-	public function get_by_token_or_device_id( PushToken &$push_token ): ?PushToken {
+	public function get_by_token_or_device_id( array $data ): ?PushToken {
+		$user_id     = $data['user_id'] ?? null;
+		$platform    = $data['platform'] ?? null;
+		$origin      = $data['origin'] ?? null;
+		$token       = $data['token'] ?? null;
+		$device_uuid = $data['device_uuid'] ?? null;
+
 		if (
-			! $push_token->get_user_id()
-			|| ! $push_token->get_platform()
-			|| ! $push_token->get_origin()
+			! $user_id
+			|| ! $platform
+			|| ! $origin
 			|| (
 				/**
 				 * Platforms iOS and Android require token OR device UUID.
 				 */
-				$push_token->get_platform() !== PushToken::PLATFORM_BROWSER
-				&& ! $push_token->get_token()
-				&& ! $push_token->get_device_uuid()
+				PushToken::PLATFORM_BROWSER !== $platform
+				&& ! $token
+				&& ! $device_uuid
 			)
 			|| (
 				/**
 				 * Browsers don't have device UUIDs, so require token.
 				 */
-				$push_token->get_platform() === PushToken::PLATFORM_BROWSER
-				&& ! $push_token->get_token()
+				PushToken::PLATFORM_BROWSER === $platform
+				&& ! $token
 			)
 		) {
 			throw new PushTokenInvalidDataException(
@@ -230,7 +225,7 @@ class PushTokensDataStore {
 			array(
 				'post_type'      => PushToken::POST_TYPE,
 				'post_status'    => 'private',
-				'author'         => $push_token->get_user_id(),
+				'author'         => $user_id,
 				'posts_per_page' => -1,
 				'orderby'        => 'ID',
 				'order'          => 'DESC',
@@ -238,6 +233,12 @@ class PushTokensDataStore {
 			)
 		);

+		/**
+		 * Typehint for PHPStan, specifies these are IDs and not instances of
+		 * WP_Post.
+		 *
+		 * @var int[] $post_ids
+		 */
 		$post_ids = $query->posts;

 		if ( empty( $post_ids ) ) {
@@ -247,11 +248,8 @@ class PushTokensDataStore {
 		update_meta_cache( 'post', $post_ids );

 		foreach ( $post_ids as $post_id ) {
-			$candidate = new PushToken();
-			$candidate->set_id( $post_id );
-
 			try {
-				$meta = $this->build_meta_array_from_database( $candidate );
+				$meta = $this->build_meta_array_from_database( $post_id );
 			} catch ( Exception $e ) {
 				wc_get_logger()->warning(
 					'Failed to load meta for push token.',
@@ -265,17 +263,23 @@ class PushTokensDataStore {
 			}

 			if (
-				$meta['platform'] === $push_token->get_platform()
-				&& $meta['origin'] === $push_token->get_origin()
+				$meta['platform'] === $platform
+				&& $meta['origin'] === $origin
 				&& (
-					( $push_token->get_token() && $push_token->get_token() === $meta['token'] )
-					|| ( $push_token->get_device_uuid() && $push_token->get_device_uuid() === $meta['device_uuid'] )
+					( $token && $token === $meta['token'] )
+					|| ( $device_uuid && $device_uuid === $meta['device_uuid'] )
 				)
 			) {
-				$push_token->set_id( $post_id );
-				$push_token->set_token( $meta['token'] );
-				$push_token->set_device_uuid( $meta['device_uuid'] );
-				return $push_token;
+				return new PushToken(
+					array(
+						'id'          => $post_id,
+						'user_id'     => $user_id,
+						'token'       => $meta['token'],
+						'device_uuid' => $meta['device_uuid'] ?? null,
+						'platform'    => $meta['platform'],
+						'origin'      => $meta['origin'],
+					)
+				);
 			}
 		}

@@ -287,18 +291,11 @@ class PushTokensDataStore {
 	 * keys defined in SUPPORTED_META; missing keys return null.
 	 *
 	 * @since 10.5.0
-	 * @param PushToken $push_token An instance of PushToken.
+	 * @param int $id The push token ID.
 	 * @return array
-	 * @throws PushTokenInvalidDataException If the token can't be read.
 	 */
-	private function build_meta_array_from_database( PushToken &$push_token ) {
-		if ( ! $push_token->can_be_read() ) {
-			throw new PushTokenInvalidDataException(
-				'Can\'t read meta for push token because the push token data provided is invalid.'
-			);
-		}
-
-		$meta        = (array) get_post_meta( (int) $push_token->get_id() );
+	private function build_meta_array_from_database( int $id ): array {
+		$meta        = (array) get_post_meta( $id );
 		$meta_by_key = (array) array_combine( static::SUPPORTED_META, static::SUPPORTED_META );

 		foreach ( static::SUPPORTED_META as $key ) {
@@ -322,7 +319,7 @@ class PushTokensDataStore {
 	 * @param PushToken $push_token An instance of PushToken.
 	 * @return array
 	 */
-	private function build_meta_array_from_token( PushToken &$push_token ) {
+	private function build_meta_array_from_token( PushToken $push_token ) {
 		return array_filter(
 			array(
 				'platform'    => $push_token->get_platform(),
diff --git a/plugins/woocommerce/src/Internal/PushNotifications/Entities/PushToken.php b/plugins/woocommerce/src/Internal/PushNotifications/Entities/PushToken.php
index 409bfb0932..593f8cbcc1 100644
--- a/plugins/woocommerce/src/Internal/PushNotifications/Entities/PushToken.php
+++ b/plugins/woocommerce/src/Internal/PushNotifications/Entities/PushToken.php
@@ -127,60 +127,37 @@ class PushToken {
 	private ?string $origin = null;

 	/**
-	 * Creates a new PushToken instance with the specified properties.
+	 * Creates a new PushToken instance with the given data.
 	 *
-	 * This is a utility method that provides a one-liner to create an instance
-	 * with all the data you want to specify upfront. Using this method doesn't
-	 * imply that the instance obtained is valid, complete, or usable in all
-	 * contexts - validity is still determined by the internal validation logic
-	 * of the class.
-	 *
-	 * @param int|null    $id          The ID of the token post.
-	 * @param int|null    $user_id     The ID of the user who owns the token.
-	 * @param string|null $token       The token representing a device we can send a push notification to.
-	 * @param string|null $device_uuid The UUID of the device that generated the token.
-	 * @param string|null $platform    The platform the token was generated by.
-	 * @param string|null $origin      The origin the token belongs to.
+	 * @param array $data Optional array with keys: id, user_id, token, device_uuid, platform, origin.
 	 * @throws PushTokenInvalidDataException If any of the provided values fail validation.
-	 * @return PushToken
 	 *
-	 * @since 10.4.0
+	 * @since 10.6.0
 	 */
-	public static function get_new_instance(
-		?int $id = null,
-		?int $user_id = null,
-		?string $token = null,
-		?string $device_uuid = null,
-		?string $platform = null,
-		?string $origin = null
-	): PushToken {
-		$instance = new self();
-
-		if ( null !== $id ) {
-			$instance->set_id( $id );
+	public function __construct( array $data = array() ) {
+		if ( array_key_exists( 'id', $data ) ) {
+			$this->set_id( (int) $data['id'] );
 		}

-		if ( null !== $user_id ) {
-			$instance->set_user_id( $user_id );
+		if ( array_key_exists( 'user_id', $data ) ) {
+			$this->set_user_id( (int) $data['user_id'] );
 		}

-		if ( null !== $token ) {
-			$instance->set_token( $token );
+		if ( array_key_exists( 'token', $data ) ) {
+			$this->set_token( (string) $data['token'] );
 		}

-		if ( null !== $device_uuid ) {
-			$instance->set_device_uuid( $device_uuid );
+		if ( array_key_exists( 'device_uuid', $data ) ) {
+			$this->set_device_uuid( (string) $data['device_uuid'] );
 		}

-		if ( null !== $platform ) {
-			$instance->set_platform( $platform );
+		if ( array_key_exists( 'platform', $data ) ) {
+			$this->set_platform( (string) $data['platform'] );
 		}

-		if ( null !== $origin ) {
-			$instance->set_origin( $origin );
+		if ( array_key_exists( 'origin', $data ) ) {
+			$this->set_origin( (string) $data['origin'] );
 		}
-
-		return $instance;
 	}

 	/**
diff --git a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Controllers/PushTokenRestControllerTest.php b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Controllers/PushTokenRestControllerTest.php
index ffc8360a5e..8aee42b8b1 100644
--- a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Controllers/PushTokenRestControllerTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Controllers/PushTokenRestControllerTest.php
@@ -680,16 +680,17 @@ class PushTokenRestControllerTest extends WC_REST_Unit_Test_Case {
 		/**
 		 * Create a token first.
 		 */
-		$push_token = new PushToken();
-		$push_token->set_user_id( $this->user_id );
-		$push_token->set_token( str_repeat( 'a', 64 ) );
-		$push_token->set_platform( PushToken::PLATFORM_APPLE );
-		$push_token->set_device_uuid( 'device-to-delete' );
-		$push_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
+		$data = array(
+			'user_id'     => $this->user_id,
+			'token'       => str_repeat( 'a', 64 ),
+			'platform'    => PushToken::PLATFORM_APPLE,
+			'device_uuid' => 'device-to-delete',
+			'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+		);

 		$data_store = wc_get_container()->get( PushTokensDataStore::class );
-		$data_store->create( $push_token );
-		$token_id = $push_token->get_id();
+		$push_token = $data_store->create( $data );
+		$token_id   = $push_token->get_id();

 		/**
 		 * Delete the token.
@@ -738,16 +739,17 @@ class PushTokenRestControllerTest extends WC_REST_Unit_Test_Case {
 		/**
 		 * Create a token for another shop manager.
 		 */
-		$push_token = new PushToken();
-		$push_token->set_user_id( $this->other_shop_manager_id );
-		$push_token->set_token( str_repeat( 'a', 64 ) );
-		$push_token->set_platform( PushToken::PLATFORM_APPLE );
-		$push_token->set_device_uuid( 'device-other-user' );
-		$push_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
+		$data = array(
+			'user_id'     => $this->other_shop_manager_id,
+			'token'       => str_repeat( 'a', 64 ),
+			'platform'    => PushToken::PLATFORM_APPLE,
+			'device_uuid' => 'device-other-user',
+			'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+		);

 		$data_store = wc_get_container()->get( PushTokensDataStore::class );
-		$data_store->create( $push_token );
-		$token_id = $push_token->get_id();
+		$push_token = $data_store->create( $data );
+		$token_id   = $push_token->get_id();

 		/**
 		 * Try to delete as a different user.
@@ -787,6 +789,43 @@ class PushTokenRestControllerTest extends WC_REST_Unit_Test_Case {
 		$this->assertEquals( 'Push token could not be found.', $data['message'] );
 	}

+	/**
+	 * @testdox Test it returns 500 when wp_delete_post fails.
+	 */
+	public function test_it_returns_500_when_wp_delete_post_fails() {
+		$data = array(
+			'user_id'     => $this->user_id,
+			'token'       => str_repeat( 'a', 64 ),
+			'platform'    => PushToken::PLATFORM_APPLE,
+			'device_uuid' => 'device-delete-fail',
+			'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+		);
+
+		$data_store = wc_get_container()->get( PushTokensDataStore::class );
+		$push_token = $data_store->create( $data );
+		$token_id   = $push_token->get_id();
+
+		wp_set_current_user( $this->user_id );
+
+		$this->mock_jetpack_connection_manager_is_connected( true );
+
+		add_filter( 'pre_delete_post', '__return_false' );
+
+		try {
+			$request  = new WP_REST_Request( 'DELETE', '/wc-push-notifications/push-tokens/' . $token_id );
+			$response = $this->server->dispatch( $request );
+
+			$this->assertEquals( WP_Http::INTERNAL_SERVER_ERROR, $response->get_status() );
+
+			$data = $response->get_data();
+
+			$this->assertEquals( 'woocommerce_internal_error', $data['code'] );
+			$this->assertEquals( 'Internal server error', $data['message'] );
+		} finally {
+			remove_filter( 'pre_delete_post', '__return_false' );
+		}
+	}
+
 	/**
 	 * @testdox Test authorize returns false when push notifications are
 	 * disabled.
diff --git a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/DataStores/PushTokensDataStoreTest.php b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/DataStores/PushTokensDataStoreTest.php
index a02b31d27f..31af803d1d 100644
--- a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/DataStores/PushTokensDataStoreTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/DataStores/PushTokensDataStoreTest.php
@@ -47,14 +47,15 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	public function test_it_can_create_push_token() {
 		$data_store = new PushTokensDataStore();

-		$push_token = new PushToken();
-		$push_token->set_user_id( 1 );
-		$push_token->set_token( 'test_token_12345' );
-		$push_token->set_platform( PushToken::PLATFORM_APPLE );
-		$push_token->set_device_uuid( 'device-uuid-123' );
-		$push_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
+		$data = array(
+			'user_id'     => 1,
+			'token'       => 'test_token_12345',
+			'platform'    => PushToken::PLATFORM_APPLE,
+			'device_uuid' => 'device-uuid-123',
+			'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+		);

-		$data_store->create( $push_token );
+		$push_token = $data_store->create( $data );

 		$this->assertNotNull( $push_token->get_id() );
 		$this->assert_push_token_in_db( $push_token );
@@ -70,17 +71,14 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 		$data_store = new PushTokensDataStore();

 		$original_push_token = $this->create_test_push_token();
-		$new_push_token      = new PushToken();
-		$new_push_token->set_id( $original_push_token->get_id() );
-
-		$data_store->read( $new_push_token );
-
-		$this->assertEquals( $original_push_token->get_id(), $new_push_token->get_id() );
-		$this->assertEquals( $original_push_token->get_user_id(), $new_push_token->get_user_id() );
-		$this->assertEquals( $original_push_token->get_platform(), $new_push_token->get_platform() );
-		$this->assertEquals( $original_push_token->get_token(), $new_push_token->get_token() );
-		$this->assertEquals( $original_push_token->get_device_uuid(), $new_push_token->get_device_uuid() );
-		$this->assertEquals( $original_push_token->get_origin(), $new_push_token->get_origin() );
+		$read_push_token     = $data_store->read( $original_push_token->get_id() );
+
+		$this->assertEquals( $original_push_token->get_id(), $read_push_token->get_id() );
+		$this->assertEquals( $original_push_token->get_user_id(), $read_push_token->get_user_id() );
+		$this->assertEquals( $original_push_token->get_platform(), $read_push_token->get_platform() );
+		$this->assertEquals( $original_push_token->get_token(), $read_push_token->get_token() );
+		$this->assertEquals( $original_push_token->get_device_uuid(), $read_push_token->get_device_uuid() );
+		$this->assertEquals( $original_push_token->get_origin(), $read_push_token->get_origin() );
 	}

 	/**
@@ -89,12 +87,15 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	public function test_it_can_update_push_token() {
 		$data_store = new PushTokensDataStore();
 		$push_token = $this->create_test_push_token();
+
 		$push_token->set_token( 'updated_token' );
 		$push_token->set_device_uuid( 'updated-device-uuid' );
-
 		$data_store->update( $push_token );

-		$this->assert_push_token_in_db( $push_token );
+		$updated_token = $data_store->read( $push_token->get_id() );
+
+		$this->assertEquals( 'updated_token', $updated_token->get_token() );
+		$this->assertEquals( 'updated-device-uuid', $updated_token->get_device_uuid() );

 		$post = get_post( $push_token->get_id() );
 		$this->assertEquals( 'private', $post->post_status );
@@ -126,7 +127,7 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	public function test_it_can_delete_push_token() {
 		$data_store = new PushTokensDataStore();
 		$push_token = $this->create_test_push_token();
-		$data_store->delete( $push_token );
+		$data_store->delete( $push_token->get_id() );

 		$this->assertNull( get_post( $push_token->get_id() ) );
 	}
@@ -138,29 +139,28 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	public function test_it_throws_exception_when_creating_push_token_with_incomplete_data() {
 		$data_store = new PushTokensDataStore();

-		$push_token = new PushToken();
-		$push_token->set_user_id( 1 );
-		$push_token->set_token( 'test_token' );
+		$data = array(
+			'user_id' => 1,
+			'token'   => 'test_token',
+		);

 		$this->expectException( PushTokenInvalidDataException::class );
 		$this->expectExceptionMessage( 'Can\'t create push token because the push token data provided is invalid.' );

-		$data_store->create( $push_token );
+		$data_store->create( $data );
 	}

 	/**
-	 * @testdox Tests the read method throws exception when push token has no
-	 * ID.
+	 * @testdox Tests the read method throws exception when push token ID is
+	 * invalid.
 	 */
-	public function test_it_throws_exception_when_reading_push_token_without_id() {
+	public function test_it_throws_exception_when_reading_push_token_with_invalid_id() {
 		$data_store = new PushTokensDataStore();

-		$push_token = new PushToken();
-
 		$this->expectException( PushTokenInvalidDataException::class );
-		$this->expectExceptionMessage( 'Can\'t read push token because the push token data provided is invalid.' );
+		$this->expectExceptionMessage( 'ID must be a positive integer.' );

-		$data_store->read( $push_token );
+		$data_store->read( 0 );
 	}

 	/**
@@ -170,13 +170,10 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	public function test_it_throws_exception_when_reading_push_token_that_does_not_exist() {
 		$data_store = new PushTokensDataStore();

-		$push_token = new PushToken();
-		$push_token->set_id( 999999 );
-
 		$this->expectException( PushTokenNotFoundException::class );
 		$this->expectExceptionMessage( 'Push token could not be found.' );

-		$data_store->read( $push_token );
+		$data_store->read( 999999 );
 	}

 	/**
@@ -194,13 +191,10 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 			)
 		);

-		$push_token = new PushToken();
-		$push_token->set_id( $post_id );
-
 		$this->expectException( PushTokenNotFoundException::class );
 		$this->expectExceptionMessage( 'Push token could not be found.' );

-		$data_store->read( $push_token );
+		$data_store->read( $post_id );
 	}

 	/**
@@ -223,94 +217,39 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 			)
 		);

-		$push_token = new PushToken();
-		$push_token->set_id( $post_id );
-
 		$this->expectException( PushTokenInvalidDataException::class );
 		$this->expectExceptionMessage( 'Can\'t read push token because the push token record is malformed.' );

-		$data_store->read( $push_token );
+		$data_store->read( $post_id );
 	}

 	/**
-	 * @testdox Tests the update method throws exception when push token data is
-	 * incomplete.
+	 * @testdox Tests the update method throws exception when push token data
+	 * would result in invalid state.
 	 */
-	public function test_it_throws_exception_when_updating_push_token_with_incomplete_data() {
+	public function test_it_throws_exception_when_updating_push_token_with_invalid_data() {
 		$data_store = new PushTokensDataStore();
-
-		$push_token = new PushToken();
-		$push_token->set_id( 1 );
-		$push_token->set_user_id( 1 );
+		$push_token = $this->create_test_push_token();

 		$this->expectException( PushTokenInvalidDataException::class );
 		$this->expectExceptionMessage( 'Can\'t update push token because the push token data provided is invalid.' );

-		$data_store->update( $push_token );
-	}
-
-	/**
-	 * @testdox Tests the update method throws exception when push token does
-	 * not exist.
-	 */
-	public function test_it_throws_exception_when_updating_push_token_that_does_not_exist() {
-		$data_store = new PushTokensDataStore();
-
-		$push_token = new PushToken();
-		$push_token->set_id( 999999 );
-		$push_token->set_user_id( 1 );
-		$push_token->set_token( 'test_token' );
 		$push_token->set_platform( PushToken::PLATFORM_APPLE );
-		$push_token->set_device_uuid( 'device-uuid' );
-		$push_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
-
-		$this->expectException( PushTokenNotFoundException::class );
-		$this->expectExceptionMessage( 'Push token could not be found.' );
-
+		$push_token->set_device_uuid( null );
 		$data_store->update( $push_token );
 	}

 	/**
-	 * @testdox Tests the update method throws exception when the post exists
-	 * but is not the correct post type.
+	 * @testdox Tests the delete method throws exception when push token ID is
+	 * invalid.
 	 */
-	public function test_it_throws_exception_when_updating_push_token_with_wrong_post_type() {
+	public function test_it_throws_exception_when_deleting_push_token_with_invalid_id() {
 		$data_store = new PushTokensDataStore();

-		$post_id = wp_insert_post(
-			array(
-				'post_title'  => 'Test Post',
-				'post_type'   => 'post',
-				'post_status' => 'private',
-			)
-		);
-
-		$push_token = new PushToken();
-		$push_token->set_id( $post_id );
-		$push_token->set_user_id( 1 );
-		$push_token->set_token( 'test_token' );
-		$push_token->set_platform( PushToken::PLATFORM_APPLE );
-		$push_token->set_device_uuid( 'device-uuid' );
-		$push_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
-
 		$this->expectException( PushTokenNotFoundException::class );
 		$this->expectExceptionMessage( 'Push token could not be found.' );

-		$data_store->update( $push_token );
-	}
-
-	/**
-	 * @testdox Tests the delete method throws exception when push token has no
-	 * ID.
-	 */
-	public function test_it_throws_exception_when_deleting_push_token_without_id() {
-		$data_store = new PushTokensDataStore();
-		$push_token = new PushToken();
-
-		$this->expectException( PushTokenInvalidDataException::class );
-		$this->expectExceptionMessage( 'Can\'t delete push token because the push token data provided is invalid.' );
-
-		$data_store->delete( $push_token );
+		$data_store->delete( 0 );
 	}

 	/**
@@ -328,13 +267,10 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 			)
 		);

-		$push_token = new PushToken();
-		$push_token->set_id( $post_id );
-
 		$this->expectException( PushTokenNotFoundException::class );
 		$this->expectExceptionMessage( 'Push token could not be found.' );

-		$data_store->delete( $push_token );
+		$data_store->delete( $post_id );
 	}

 	/**
@@ -346,14 +282,15 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {

 		$original_push_token = $this->create_test_push_token();

-		$new_push_token = new PushToken();
-		$new_push_token->set_user_id( $original_push_token->get_user_id() );
-		$new_push_token->set_token( $original_push_token->get_token() );
-		$new_push_token->set_platform( $original_push_token->get_platform() );
-		$new_push_token->set_origin( $original_push_token->get_origin() );
-		$new_push_token->set_device_uuid( 'different-device' );
+		$data = array(
+			'user_id'     => $original_push_token->get_user_id(),
+			'token'       => $original_push_token->get_token(),
+			'platform'    => $original_push_token->get_platform(),
+			'origin'      => $original_push_token->get_origin(),
+			'device_uuid' => 'different-device',
+		);

-		$found_token = $data_store->get_by_token_or_device_id( $new_push_token );
+		$found_token = $data_store->get_by_token_or_device_id( $data );

 		$this->assertNotNull( $found_token );
 		$this->assertEquals( $original_push_token->get_id(), $found_token->get_id() );
@@ -369,14 +306,15 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {

 		$original_push_token = $this->create_test_push_token();

-		$new_push_token = new PushToken();
-		$new_push_token->set_user_id( $original_push_token->get_user_id() );
-		$new_push_token->set_platform( $original_push_token->get_platform() );
-		$new_push_token->set_origin( $original_push_token->get_origin() );
-		$new_push_token->set_device_uuid( $original_push_token->get_device_uuid() );
-		$new_push_token->set_token( 'different_token' );
+		$data = array(
+			'user_id'     => $original_push_token->get_user_id(),
+			'platform'    => $original_push_token->get_platform(),
+			'origin'      => $original_push_token->get_origin(),
+			'device_uuid' => $original_push_token->get_device_uuid(),
+			'token'       => 'different_token',
+		);

-		$found_token = $data_store->get_by_token_or_device_id( $new_push_token );
+		$found_token = $data_store->get_by_token_or_device_id( $data );

 		$this->assertNotNull( $found_token );
 		$this->assertEquals( $original_push_token->get_id(), $found_token->get_id() );
@@ -392,14 +330,15 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {

 		$original_push_token = $this->create_test_push_token();

-		$new_push_token = new PushToken();
-		$new_push_token->set_user_id( $original_push_token->get_user_id() );
-		$new_push_token->set_platform( $original_push_token->get_platform() );
-		$new_push_token->set_origin( $original_push_token->get_origin() );
-		$new_push_token->set_device_uuid( 'different-device' );
-		$new_push_token->set_token( 'different_token' );
+		$data = array(
+			'user_id'     => $original_push_token->get_user_id(),
+			'platform'    => $original_push_token->get_platform(),
+			'origin'      => $original_push_token->get_origin(),
+			'device_uuid' => 'different-device',
+			'token'       => 'different_token',
+		);

-		$found_token = $data_store->get_by_token_or_device_id( $new_push_token );
+		$found_token = $data_store->get_by_token_or_device_id( $data );

 		$this->assertNull( $found_token );
 	}
@@ -413,14 +352,15 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {

 		$original_push_token = $this->create_test_push_token();

-		$new_push_token = new PushToken();
-		$new_push_token->set_user_id( 999 );
-		$new_push_token->set_platform( $original_push_token->get_platform() );
-		$new_push_token->set_origin( $original_push_token->get_origin() );
-		$new_push_token->set_device_uuid( $original_push_token->get_device_uuid() );
-		$new_push_token->set_token( $original_push_token->get_token() );
+		$data = array(
+			'user_id'     => 999,
+			'platform'    => $original_push_token->get_platform(),
+			'origin'      => $original_push_token->get_origin(),
+			'device_uuid' => $original_push_token->get_device_uuid(),
+			'token'       => $original_push_token->get_token(),
+		);

-		$found_token = $data_store->get_by_token_or_device_id( $new_push_token );
+		$found_token = $data_store->get_by_token_or_device_id( $data );

 		$this->assertNull( $found_token );
 	}
@@ -434,14 +374,15 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {

 		$original_push_token = $this->create_test_push_token();

-		$new_push_token = new PushToken();
-		$new_push_token->set_user_id( $original_push_token->get_user_id() );
-		$new_push_token->set_platform( PushToken::PLATFORM_ANDROID );
-		$new_push_token->set_origin( $original_push_token->get_origin() );
-		$new_push_token->set_device_uuid( $original_push_token->get_device_uuid() );
-		$new_push_token->set_token( $original_push_token->get_token() );
+		$data = array(
+			'user_id'     => $original_push_token->get_user_id(),
+			'platform'    => PushToken::PLATFORM_ANDROID,
+			'origin'      => $original_push_token->get_origin(),
+			'device_uuid' => $original_push_token->get_device_uuid(),
+			'token'       => $original_push_token->get_token(),
+		);

-		$found_token = $data_store->get_by_token_or_device_id( $new_push_token );
+		$found_token = $data_store->get_by_token_or_device_id( $data );

 		$this->assertNull( $found_token );
 	}
@@ -455,14 +396,15 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {

 		$original_push_token = $this->create_test_push_token();

-		$new_push_token = new PushToken();
-		$new_push_token->set_user_id( $original_push_token->get_user_id() );
-		$new_push_token->set_platform( $original_push_token->get_platform() );
-		$new_push_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS_DEV );
-		$new_push_token->set_device_uuid( $original_push_token->get_device_uuid() );
-		$new_push_token->set_token( $original_push_token->get_token() );
+		$data = array(
+			'user_id'     => $original_push_token->get_user_id(),
+			'platform'    => $original_push_token->get_platform(),
+			'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS_DEV,
+			'device_uuid' => $original_push_token->get_device_uuid(),
+			'token'       => $original_push_token->get_token(),
+		);

-		$found_token = $data_store->get_by_token_or_device_id( $new_push_token );
+		$found_token = $data_store->get_by_token_or_device_id( $data );

 		$this->assertNull( $found_token );
 	}
@@ -477,37 +419,42 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 		/**
 		 * Create first browser token for user.
 		 */
-		$browser_token_1 = new PushToken();
-		$browser_token_1->set_user_id( 1 );
-		$browser_token_1->set_token( 'browser_token_1_' . wp_rand() );
-		$browser_token_1->set_platform( PushToken::PLATFORM_BROWSER );
-		$browser_token_1->set_device_uuid( null );
-		$browser_token_1->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
-		$data_store->create( $browser_token_1 );
+		$browser_token_1 = $data_store->create(
+			array(
+				'user_id'     => 1,
+				'token'       => 'browser_token_1_' . wp_rand(),
+				'platform'    => PushToken::PLATFORM_BROWSER,
+				'device_uuid' => null,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
+		);

 		/**
 		 * Create second browser token for same user (different browser/tab).
 		 */
-		$browser_token_2 = new PushToken();
-		$browser_token_2->set_user_id( 1 );
-		$browser_token_2->set_token( 'browser_token_2_' . wp_rand() );
-		$browser_token_2->set_platform( PushToken::PLATFORM_BROWSER );
-		$browser_token_2->set_device_uuid( null );
-		$browser_token_2->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
-		$data_store->create( $browser_token_2 );
+		$browser_token_2 = $data_store->create(
+			array(
+				'user_id'     => 1,
+				'token'       => 'browser_token_2_' . wp_rand(),
+				'platform'    => PushToken::PLATFORM_BROWSER,
+				'device_uuid' => null,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
+		);

 		/**
 		 * Try to find browser_token_1 by its token - should only match itself,
 		 * not browser_token_2.
 		 */
-		$search_token = new PushToken();
-		$search_token->set_user_id( 1 );
-		$search_token->set_token( $browser_token_1->get_token() );
-		$search_token->set_platform( PushToken::PLATFORM_BROWSER );
-		$search_token->set_device_uuid( null );
-		$search_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
+		$data = array(
+			'user_id'     => 1,
+			'token'       => $browser_token_1->get_token(),
+			'platform'    => PushToken::PLATFORM_BROWSER,
+			'device_uuid' => null,
+			'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+		);

-		$found_token = $data_store->get_by_token_or_device_id( $search_token );
+		$found_token = $data_store->get_by_token_or_device_id( $data );

 		$this->assertNotNull( $found_token, 'Should find browser_token_1 by its token value' );
 		$this->assertEquals( $browser_token_1->get_id(), $found_token->get_id(), 'Should match browser_token_1 ID' );
@@ -518,12 +465,11 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 		 * Now search with a DIFFERENT token - should return null, not match by
 		 * empty device_uuid.
 		 */
-		$different_token = new PushToken();
-		$different_token->set_user_id( 1 );
-		$different_token->set_platform( PushToken::PLATFORM_BROWSER );
-		$different_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
-		$different_token->set_token(
-			wp_json_encode(
+		$different_data = array(
+			'user_id'  => 1,
+			'platform' => PushToken::PLATFORM_BROWSER,
+			'origin'   => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			'token'    => wp_json_encode(
 				array(
 					'endpoint' => 'https://example.com/push/subscription3',
 					'keys'     => array(
@@ -531,10 +477,10 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 						'p256dh' => 'p3',
 					),
 				)
-			)
+			),
 		);

-		$found = $data_store->get_by_token_or_device_id( $different_token );
+		$found = $data_store->get_by_token_or_device_id( $different_data );
 		$this->assertNull( $found, 'Should not match existing tokens by empty device_uuid' );
 	}

@@ -545,16 +491,17 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	public function test_it_throws_exception_when_getting_by_token_or_device_id_without_user_id() {
 		$data_store = new PushTokensDataStore();

-		$push_token = new PushToken();
-		$push_token->set_platform( PushToken::PLATFORM_APPLE );
-		$push_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
-		$push_token->set_token( 'test_token' );
-		$push_token->set_device_uuid( 'test_device' );
+		$data = array(
+			'platform'    => PushToken::PLATFORM_APPLE,
+			'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			'token'       => 'test_token',
+			'device_uuid' => 'test_device',
+		);

 		$this->expectException( PushTokenInvalidDataException::class );
 		$this->expectExceptionMessage( 'Can\'t retrieve push token because the push token data provided is invalid.' );

-		$data_store->get_by_token_or_device_id( $push_token );
+		$data_store->get_by_token_or_device_id( $data );
 	}

 	/**
@@ -564,16 +511,17 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	public function test_it_throws_exception_when_getting_by_token_or_device_id_without_platform() {
 		$data_store = new PushTokensDataStore();

-		$push_token = new PushToken();
-		$push_token->set_user_id( 1 );
-		$push_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
-		$push_token->set_token( 'test_token' );
-		$push_token->set_device_uuid( 'test_device' );
+		$data = array(
+			'user_id'     => 1,
+			'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			'token'       => 'test_token',
+			'device_uuid' => 'test_device',
+		);

 		$this->expectException( PushTokenInvalidDataException::class );
 		$this->expectExceptionMessage( 'Can\'t retrieve push token because the push token data provided is invalid.' );

-		$data_store->get_by_token_or_device_id( $push_token );
+		$data_store->get_by_token_or_device_id( $data );
 	}

 	/**
@@ -583,16 +531,17 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	public function test_it_throws_exception_when_getting_by_token_or_device_id_without_origin() {
 		$data_store = new PushTokensDataStore();

-		$push_token = new PushToken();
-		$push_token->set_user_id( 1 );
-		$push_token->set_platform( PushToken::PLATFORM_APPLE );
-		$push_token->set_token( 'test_token' );
-		$push_token->set_device_uuid( 'test_device' );
+		$data = array(
+			'user_id'     => 1,
+			'platform'    => PushToken::PLATFORM_APPLE,
+			'token'       => 'test_token',
+			'device_uuid' => 'test_device',
+		);

 		$this->expectException( PushTokenInvalidDataException::class );
 		$this->expectExceptionMessage( 'Can\'t retrieve push token because the push token data provided is invalid.' );

-		$data_store->get_by_token_or_device_id( $push_token );
+		$data_store->get_by_token_or_device_id( $data );
 	}

 	/**
@@ -602,15 +551,16 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	public function test_it_throws_exception_when_getting_by_token_or_device_id_without_token_and_device_uuid() {
 		$data_store = new PushTokensDataStore();

-		$push_token = new PushToken();
-		$push_token->set_user_id( 1 );
-		$push_token->set_platform( PushToken::PLATFORM_APPLE );
-		$push_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
+		$data = array(
+			'user_id'  => 1,
+			'platform' => PushToken::PLATFORM_APPLE,
+			'origin'   => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+		);

 		$this->expectException( PushTokenInvalidDataException::class );
 		$this->expectExceptionMessage( 'Can\'t retrieve push token because the push token data provided is invalid.' );

-		$data_store->get_by_token_or_device_id( $push_token );
+		$data_store->get_by_token_or_device_id( $data );
 	}

 	/**
@@ -620,20 +570,18 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	public function test_it_can_create_and_read_browser_token_without_device_uuid() {
 		$data_store = new PushTokensDataStore();

-		$push_token = new PushToken();
-		$push_token->set_user_id( 1 );
-		$push_token->set_token( '{"endpoint":"https://example.com/push","keys":{"auth":"test","p256dh":"test"}}' );
-		$push_token->set_platform( PushToken::PLATFORM_BROWSER );
-		$push_token->set_origin( PushToken::ORIGIN_BROWSER );
+		$data = array(
+			'user_id'  => 1,
+			'token'    => '{"endpoint":"https://example.com/push","keys":{"auth":"test","p256dh":"test"}}',
+			'platform' => PushToken::PLATFORM_BROWSER,
+			'origin'   => PushToken::ORIGIN_BROWSER,
+		);

-		$data_store->create( $push_token );
+		$push_token = $data_store->create( $data );

 		$this->assertNotNull( $push_token->get_id() );

-		$read_token = new PushToken();
-		$read_token->set_id( $push_token->get_id() );
-
-		$data_store->read( $read_token );
+		$read_token = $data_store->read( $push_token->get_id() );

 		$this->assertEquals( $push_token->get_id(), $read_token->get_id() );
 		$this->assertEquals( $push_token->get_user_id(), $read_token->get_user_id() );
@@ -651,16 +599,15 @@ class PushTokensDataStoreTest extends WC_Unit_Test_Case {
 	private function create_test_push_token(): PushToken {
 		$data_store = new PushTokensDataStore();

-		$push_token = new PushToken();
-		$push_token->set_user_id( 1 );
-		$push_token->set_token( 'test_token_' . wp_rand() );
-		$push_token->set_platform( PushToken::PLATFORM_APPLE );
-		$push_token->set_device_uuid( 'test-device-uuid-' . wp_rand() );
-		$push_token->set_origin( PushToken::ORIGIN_WOOCOMMERCE_IOS );
-
-		$data_store->create( $push_token );
+		$data = array(
+			'user_id'     => 1,
+			'token'       => 'test_token_' . wp_rand(),
+			'platform'    => PushToken::PLATFORM_APPLE,
+			'device_uuid' => 'test-device-uuid-' . wp_rand(),
+			'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+		);

-		return $push_token;
+		return $data_store->create( $data );
 	}

 	/**
diff --git a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Entities/PushTokenTest.php b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Entities/PushTokenTest.php
index cd09e876de..ac5b79a0a2 100644
--- a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Entities/PushTokenTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/Entities/PushTokenTest.php
@@ -68,13 +68,14 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_created returns true when all fields are set except ID.
 	 */
 	public function test_it_can_be_created_when_all_fields_are_set_except_id() {
-		$push_token = PushToken::get_new_instance(
-			null,
-			1,
-			'test_token',
-			'test-device-uuid',
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'user_id'     => 1,
+				'token'       => 'test_token',
+				'device_uuid' => 'test-device-uuid',
+				'platform'    => PushToken::PLATFORM_APPLE,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertTrue( $push_token->can_be_created() );
@@ -84,13 +85,15 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_created returns false when ID is already set.
 	 */
 	public function test_it_cannot_be_created_when_id_is_set() {
-		$push_token = PushToken::get_new_instance(
-			1,
-			1,
-			'test_token',
-			'test-device-uuid',
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'id'          => 1,
+				'user_id'     => 1,
+				'token'       => 'test_token',
+				'device_uuid' => 'test-device-uuid',
+				'platform'    => PushToken::PLATFORM_APPLE,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_created() );
@@ -100,13 +103,13 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_created returns false when user ID is missing.
 	 */
 	public function test_it_cannot_be_created_when_user_id_is_missing() {
-		$push_token = PushToken::get_new_instance(
-			null,
-			null,
-			'test_token',
-			'test-device-uuid',
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'token'       => 'test_token',
+				'device_uuid' => 'test-device-uuid',
+				'platform'    => PushToken::PLATFORM_APPLE,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_created() );
@@ -116,13 +119,13 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_created returns false when platform is missing.
 	 */
 	public function test_it_cannot_be_created_when_platform_is_missing() {
-		$push_token = PushToken::get_new_instance(
-			null,
-			1,
-			'test_token',
-			'test-device-uuid',
-			null,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'user_id'     => 1,
+				'token'       => 'test_token',
+				'device_uuid' => 'test-device-uuid',
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_created() );
@@ -132,13 +135,13 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_created returns false when token is missing.
 	 */
 	public function test_it_cannot_be_created_when_token_is_missing() {
-		$push_token = PushToken::get_new_instance(
-			null,
-			1,
-			null,
-			'test-device-uuid',
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'user_id'     => 1,
+				'device_uuid' => 'test-device-uuid',
+				'platform'    => PushToken::PLATFORM_APPLE,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_created() );
@@ -148,13 +151,13 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_created returns false when device UUID is missing.
 	 */
 	public function test_it_cannot_be_created_when_device_uuid_is_missing() {
-		$push_token = PushToken::get_new_instance(
-			null,
-			1,
-			'test_token',
-			null,
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'user_id'  => 1,
+				'token'    => 'test_token',
+				'platform' => PushToken::PLATFORM_APPLE,
+				'origin'   => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_created() );
@@ -165,13 +168,15 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * set.
 	 */
 	public function test_it_can_be_updated_when_all_fields_are_set() {
-		$push_token = PushToken::get_new_instance(
-			1,
-			1,
-			'test_token',
-			'test-device-uuid',
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'id'          => 1,
+				'user_id'     => 1,
+				'token'       => 'test_token',
+				'device_uuid' => 'test-device-uuid',
+				'platform'    => PushToken::PLATFORM_APPLE,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertTrue( $push_token->can_be_updated() );
@@ -181,13 +186,14 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_updated returns false when ID is not set.
 	 */
 	public function test_it_cannot_be_updated_when_id_is_not_set() {
-		$push_token = PushToken::get_new_instance(
-			null,
-			1,
-			'test_token',
-			'test-device-uuid',
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'user_id'     => 1,
+				'token'       => 'test_token',
+				'device_uuid' => 'test-device-uuid',
+				'platform'    => PushToken::PLATFORM_APPLE,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_updated() );
@@ -197,13 +203,14 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_updated returns false when user ID is not set.
 	 */
 	public function test_it_cannot_be_updated_when_user_id_is_not_set() {
-		$push_token = PushToken::get_new_instance(
-			1,
-			null,
-			'test_token',
-			'test-device-uuid',
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'id'          => 1,
+				'token'       => 'test_token',
+				'device_uuid' => 'test-device-uuid',
+				'platform'    => PushToken::PLATFORM_APPLE,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_updated() );
@@ -213,13 +220,14 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_updated returns false when platform is not set.
 	 */
 	public function test_it_cannot_be_updated_when_platform_is_not_set() {
-		$push_token = PushToken::get_new_instance(
-			1,
-			1,
-			'test_token',
-			'test-device-uuid',
-			null,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'id'          => 1,
+				'user_id'     => 1,
+				'token'       => 'test_token',
+				'device_uuid' => 'test-device-uuid',
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_updated() );
@@ -229,13 +237,14 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_updated returns false when device UUID is not set.
 	 */
 	public function test_it_cannot_be_updated_when_device_uuid_is_not_set() {
-		$push_token = PushToken::get_new_instance(
-			1,
-			1,
-			'test_token',
-			null,
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'id'       => 1,
+				'user_id'  => 1,
+				'token'    => 'test_token',
+				'platform' => PushToken::PLATFORM_APPLE,
+				'origin'   => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_updated() );
@@ -245,13 +254,14 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_updated returns false when token is not set.
 	 */
 	public function test_it_cannot_be_updated_when_token_is_not_set() {
-		$push_token = PushToken::get_new_instance(
-			1,
-			1,
-			null,
-			'test-device-uuid',
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'id'          => 1,
+				'user_id'     => 1,
+				'device_uuid' => 'test-device-uuid',
+				'platform'    => PushToken::PLATFORM_APPLE,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_updated() );
@@ -321,13 +331,13 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * device UUID.
 	 */
 	public function test_it_can_be_created_for_browser_without_device_uuid() {
-		$push_token = PushToken::get_new_instance(
-			null,
-			1,
-			'test_token',
-			null,
-			PushToken::PLATFORM_BROWSER,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'user_id'  => 1,
+				'token'    => 'test_token',
+				'platform' => PushToken::PLATFORM_BROWSER,
+				'origin'   => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertTrue( $push_token->can_be_created() );
@@ -338,13 +348,14 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * device UUID.
 	 */
 	public function test_it_can_be_updated_for_browser_without_device_uuid() {
-		$push_token = PushToken::get_new_instance(
-			1,
-			1,
-			'test_token',
-			null,
-			PushToken::PLATFORM_BROWSER,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+		$push_token = new PushToken(
+			array(
+				'id'       => 1,
+				'user_id'  => 1,
+				'token'    => 'test_token',
+				'platform' => PushToken::PLATFORM_BROWSER,
+				'origin'   => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertTrue( $push_token->can_be_updated() );
@@ -354,13 +365,13 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_created returns false when origin is missing.
 	 */
 	public function test_it_cannot_be_created_when_origin_is_missing() {
-		$push_token = PushToken::get_new_instance(
-			null,
-			1,
-			'test_token',
-			'test-device-uuid',
-			PushToken::PLATFORM_APPLE,
-			null
+		$push_token = new PushToken(
+			array(
+				'user_id'     => 1,
+				'token'       => 'test_token',
+				'device_uuid' => 'test-device-uuid',
+				'platform'    => PushToken::PLATFORM_APPLE,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_created() );
@@ -370,13 +381,14 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	 * @testdox Tests can_be_updated returns false when origin is missing.
 	 */
 	public function test_it_cannot_be_updated_when_origin_is_missing() {
-		$push_token = PushToken::get_new_instance(
-			1,
-			1,
-			'test_token',
-			'test-device-uuid',
-			PushToken::PLATFORM_APPLE,
-			null
+		$push_token = new PushToken(
+			array(
+				'id'          => 1,
+				'user_id'     => 1,
+				'token'       => 'test_token',
+				'device_uuid' => 'test-device-uuid',
+				'platform'    => PushToken::PLATFORM_APPLE,
+			)
 		);

 		$this->assertFalse( $push_token->can_be_updated() );
@@ -529,16 +541,18 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	}

 	/**
-	 * @testdox Tests get_new_instance creates a PushToken with all specified properties.
+	 * @testdox Tests constructor creates a PushToken with all specified properties.
 	 */
-	public function test_get_new_instance_creates_token_with_all_properties() {
-		$push_token = PushToken::get_new_instance(
-			123,
-			456,
-			'test_token_value',
-			'device-uuid-123',
-			PushToken::PLATFORM_APPLE,
-			PushToken::ORIGIN_WOOCOMMERCE_IOS
+	public function test_constructor_creates_token_with_all_properties() {
+		$push_token = new PushToken(
+			array(
+				'id'          => 123,
+				'user_id'     => 456,
+				'token'       => 'test_token_value',
+				'device_uuid' => 'device-uuid-123',
+				'platform'    => PushToken::PLATFORM_APPLE,
+				'origin'      => PushToken::ORIGIN_WOOCOMMERCE_IOS,
+			)
 		);

 		$this->assertSame( 123, $push_token->get_id() );
@@ -550,15 +564,15 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	}

 	/**
-	 * @testdox Tests get_new_instance creates a PushToken with only some properties.
+	 * @testdox Tests constructor creates a PushToken with only some properties.
 	 */
-	public function test_get_new_instance_creates_token_with_partial_properties() {
-		$push_token = PushToken::get_new_instance(
-			null,
-			789,
-			'partial_token',
-			null,
-			PushToken::PLATFORM_ANDROID
+	public function test_constructor_creates_token_with_partial_properties() {
+		$push_token = new PushToken(
+			array(
+				'user_id'  => 789,
+				'token'    => 'partial_token',
+				'platform' => PushToken::PLATFORM_ANDROID,
+			)
 		);

 		$this->assertNull( $push_token->get_id() );
@@ -570,18 +584,16 @@ class PushTokenTest extends WC_Unit_Test_Case {
 	}

 	/**
-	 * @testdox Tests get_new_instance throws exception for invalid values.
+	 * @testdox Tests constructor throws exception for invalid values.
 	 */
-	public function test_get_new_instance_throws_exception_for_invalid_platform() {
+	public function test_constructor_throws_exception_for_invalid_platform() {
 		$this->expectException( PushTokenInvalidDataException::class );
 		$this->expectExceptionMessage( 'Platform for PushToken is invalid.' );

-		PushToken::get_new_instance(
-			null,
-			null,
-			null,
-			null,
-			'invalid_platform'
+		new PushToken(
+			array(
+				'platform' => 'invalid_platform',
+			)
 		);
 	}
 }