Throw custom exception in NoteTraits if notes are disabled (https://github.com/woocommerce/woocommerce-admin/pull/6771)

A custom exception `NotesUnavailableException` will be thrown on attempts to load the "admin-note" data store using the `Notes::load_data_store()` method introduced in this PR.

All calls to `\WC_Data_Store::load( 'admin-note' )` were replaced with calls to the above method.
This commit is contained in:
Waclaw Jacek 2021-04-26 23:57:39 +02:00 committed by GitHub
parent 7bed3d01e8
commit 4c17776815
17 changed files with 238 additions and 27 deletions

View File

@ -106,6 +106,7 @@ Release and roadmap notes are available on the [WooCommerce Developers Blog](htt
- Fix: Parsing bad JSON string data from user WooCommerce meta. #6819
- Fix: Remove PayPal for India #6828
- Fix: Report filters expecting specific ordering. #6847
- Fix: Throw exception if the data store cannot be loaded when trying to use notes. #6771
- Performance: Avoid updating customer info synchronously from the front end. #6765
- Tweak: Add settings_section event prop for CES #6762
- Tweak: Refactor payments to allow management of methods #6786

View File

@ -12,6 +12,8 @@ namespace Automattic\WooCommerce\Admin\Composer;
defined( 'ABSPATH' ) || exit;
use Automattic\WooCommerce\Admin\Notes\DeactivatePlugin;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Admin\Notes\NotesUnavailableException;
use Automattic\WooCommerce\Admin\FeaturePlugin;
/**
@ -152,8 +154,8 @@ class Package {
*/
private static function is_notes_initialized() {
try {
\WC_Data_Store::load( 'admin-note' );
} catch ( \Exception $e ) {
Notes::load_data_store();
} catch ( NotesUnavailableException $e ) {
return false;
}
return true;

View File

@ -76,7 +76,7 @@ class InstallJPAndWCSPlugins {
}
// Action any notes with a matching name.
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
foreach ( $note_ids as $note_id ) {

View File

@ -69,7 +69,7 @@ class MerchantEmailNotifications {
* Send all the notifications type `email`.
*/
public static function run() {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$notes = $data_store->get_notes(
array(
'type' => array( Note::E_WC_ADMIN_NOTE_EMAIL ),

View File

@ -35,7 +35,7 @@ class NavigationFeedbackFollowUp {
}
// Check that the first note was created.
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note_ids = $data_store->get_notes_with_name( 'wc-admin-navigation-feedback' );
if ( empty( $note_ids ) ) {
return;

View File

@ -68,7 +68,7 @@ class NavigationNudge {
return;
}
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
if ( ! empty( $note_ids ) ) {

View File

@ -84,7 +84,7 @@ class Note extends \WC_Data {
$this->set_object_read( true );
}
$this->data_store = \WC_Data_Store::load( 'admin-note' );
$this->data_store = Notes::load_data_store();
if ( $this->get_id() > 0 ) {
$this->data_store->read( $this );
}

View File

@ -27,9 +27,11 @@ trait NoteTraits {
/**
* Check if the note has been previously added.
*
* @throws NotesUnavailableException Throws exception when notes are unavailable.
*/
public static function note_exists() {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
return ! empty( $note_ids );
}
@ -38,6 +40,7 @@ trait NoteTraits {
* Checks if a note can and should be added.
*
* @return bool
* @throws NotesUnavailableException Throws exception when notes are unavailable.
*/
public static function can_be_added() {
$note = self::get_note();
@ -62,6 +65,8 @@ trait NoteTraits {
/**
* Add the note if it passes predefined conditions.
*
* @throws NotesUnavailableException Throws exception when notes are unavailable.
*/
public static function possibly_add_note() {
$note = self::get_note();
@ -75,6 +80,8 @@ trait NoteTraits {
/**
* Alias this method for backwards compatibility.
*
* @throws NotesUnavailableException Throws exception when notes are unavailable.
*/
public static function add_note() {
self::possibly_add_note();
@ -84,9 +91,11 @@ trait NoteTraits {
* Possibly delete the note, if it exists in the database. Note that this
* is a hard delete, for where it doesn't make sense to soft delete or
* action the note.
*
* @throws NotesUnavailableException Throws exception when notes are unavailable.
*/
public static function possibly_delete_note() {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
foreach ( $note_ids as $note_id ) {
@ -102,9 +111,10 @@ trait NoteTraits {
* Get if the note has been actioned.
*
* @return bool
* @throws NotesUnavailableException Throws exception when notes are unavailable.
*/
public static function has_note_been_actioned() {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
if ( ! empty( $note_ids ) ) {

View File

@ -34,7 +34,7 @@ class Notes {
* @return array Array of arrays.
*/
public static function get_notes( $context = 'edit', $args = array() ) {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = self::load_data_store();
$raw_notes = $data_store->get_notes( $args );
$notes = array();
foreach ( (array) $raw_notes as $raw_note ) {
@ -90,7 +90,7 @@ class Notes {
* @return int
*/
public static function get_notes_count( $type = array(), $status = array() ) {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = self::load_data_store();
return $data_store->get_notes_count( $type, $status );
}
@ -106,7 +106,7 @@ class Notes {
return;
}
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = self::load_data_store();
foreach ( $names as $name ) {
$note_ids = $data_store->get_notes_with_name( $name );
@ -163,7 +163,7 @@ class Notes {
* @return array Array of notes.
*/
public static function delete_all_notes() {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = self::load_data_store();
// Here we filter for the same params we are using to show the note list in client side.
$raw_notes = $data_store->get_notes(
array(
@ -196,7 +196,7 @@ class Notes {
* Clear note snooze status if the reminder date has been reached.
*/
public static function unsnooze_notes() {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = self::load_data_store();
$raw_notes = $data_store->get_notes(
array(
'status' => array( Note::E_WC_ADMIN_NOTE_SNOOZED ),
@ -247,7 +247,7 @@ class Notes {
return;
}
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = self::load_data_store();
$notes = $data_store->get_notes(
array(
'type' => array( Note::E_WC_ADMIN_NOTE_MARKETING ),
@ -266,7 +266,7 @@ class Notes {
* Delete actioned survey notes.
*/
public static function possibly_delete_survey_notes() {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = self::load_data_store();
$notes = $data_store->get_notes(
array(
'type' => array( Note::E_WC_ADMIN_NOTE_SURVEY ),
@ -290,7 +290,7 @@ class Notes {
* @return string|bool The note status.
*/
public static function get_note_status( $note_name ) {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = self::load_data_store();
$note_ids = $data_store->get_notes_with_name( $note_name );
if ( empty( $note_ids ) ) {
@ -434,4 +434,25 @@ class Notes {
}
return $screen_name;
}
/**
* Loads the data store.
*
* If the "admin-note" data store is unavailable, attempts to load it
* will result in an exception.
* This method catches that exception and throws a custom one instead.
*
* @return \WC_Data_Store The "admin-note" data store.
* @throws NotesUnavailableException Throws exception if data store loading fails.
*/
public static function load_data_store() {
try {
return \WC_Data_Store::load( 'admin-note' );
} catch ( \Exception $e ) {
throw new NotesUnavailableException(
'woocommerce_admin_notes_unavailable',
__( 'Notes are unavailable because the "admin-note" data store cannot be loaded.', 'woocommerce-admin' )
);
}
}
}

View File

@ -0,0 +1,15 @@
<?php
/**
* WooCommerce Admin Notes Unavailable Exception Class
*
* Exception class thrown when an attempt to use notes is made but notes are unavailable.
*/
namespace Automattic\WooCommerce\Admin\Notes;
defined( 'ABSPATH' ) || exit;
/**
* Notes\NotesUnavailableException class.
*/
class NotesUnavailableException extends \WC_Data_Exception {}

View File

@ -49,7 +49,7 @@ class WooCommercePayments {
return;
}
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
// We already have this note? Then mark the note as actioned.
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );

View File

@ -104,7 +104,7 @@ class WooSubscriptionsNotes {
*/
public function check_connection() {
if ( ! $this->is_connected() ) {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note_ids = $data_store->get_notes_with_name( self::CONNECTION_NOTE_NAME );
if ( ! empty( $note_ids ) ) {
// We already have a connection note. Exit early.
@ -216,7 +216,7 @@ class WooSubscriptionsNotes {
public function prune_inactive_subscription_notes() {
$active_product_ids = $this->get_subscription_active_product_ids();
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note_ids = $data_store->get_notes_with_name( self::SUBSCRIPTION_NOTE_NAME );
foreach ( (array) $note_ids as $note_id ) {
@ -239,7 +239,7 @@ class WooSubscriptionsNotes {
public function find_note_for_product_id( $product_id ) {
$product_id = intval( $product_id );
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note_ids = $data_store->get_notes_with_name( self::SUBSCRIPTION_NOTE_NAME );
foreach ( (array) $note_ids as $note_id ) {
$note = Notes::get_note( $note_id );

View File

@ -21,7 +21,7 @@ class SpecRunner {
* @param object $stored_state Stored state.
*/
public static function run_spec( $spec, $stored_state ) {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
// Create or update the note.
$existing_note_ids = $data_store->get_notes_with_name( $spec->slug );

View File

@ -39,7 +39,7 @@ class WC_Tests_Learn_More_About_Variable_Product extends WC_Unit_Test_Case {
wp_insert_post( $product );
// Then we should have LearnMoreAboutVariableProducts note.
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note_ids = $data_store->get_notes_with_name( LearnMoreAboutVariableProducts::NOTE_NAME );
$this->assertNotEmpty( $note_ids );
$this->assertCount( 1, $note_ids );
@ -111,7 +111,7 @@ class WC_Tests_Learn_More_About_Variable_Product extends WC_Unit_Test_Case {
* @return array
*/
protected function get_note_ids() {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
return $data_store->get_notes_with_name( LearnMoreAboutVariableProducts::NOTE_NAME );
}

View File

@ -18,7 +18,7 @@ class WC_Tests_Marketing_Notes extends WC_Unit_Test_Case {
* Tests that a marketing note can be added.
*/
public function test_add_remove_marketing_note() {
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$note = new Note();
$note->set_title( 'PHPUNIT_TEST_MARKETING_NOTE' );
@ -64,7 +64,7 @@ class WC_Tests_Marketing_Notes extends WC_Unit_Test_Case {
WooCommercePayments::possibly_add_note();
// Load all marketing notes and check that the note was not added.
$data_store = \WC_Data_Store::load( 'admin-note' );
$data_store = Notes::load_data_store();
$notes = $data_store->get_notes(
array(
'type' => array( Note::E_WC_ADMIN_NOTE_MARKETING ),

View File

@ -0,0 +1,127 @@
<?php
/**
* NoteTraits tests
*
* @package WooCommerce\Admin\Tests\Notes
*/
use Automattic\WooCommerce\Admin\Notes\NotesUnavailableException;
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
/**
* Class WC_Tests_NoteTraits
*/
class WC_Tests_NoteTraits extends WC_Unit_Test_Case {
/** Host the traits class we are testing */
use NoteTraits;
/**
* Constant required to use NoteTraits.
*/
const NOTE_NAME = 'Test note';
/**
* @doesNotPerformAssertions
* @dataProvider methods_causing_exception_if_data_store_cannot_be_loaded_provider
* @dataProvider methods_never_causing_exception_provider
*
* @param callable $callback Tested NoteTraits method.
*/
public function test_no_exception_is_thrown_if_data_store_can_be_loaded( $callback ) {
$callback();
}
/**
* @dataProvider methods_causing_exception_if_data_store_cannot_be_loaded_provider
*
* @param callable $callback Tested NoteTraits method.
*/
public function test_exception_is_thrown_if_data_store_cannot_be_loaded( $callback ) {
add_filter( 'woocommerce_data_stores', '__return_empty_array' );
$this->expectException( NotesUnavailableException::class );
$callback();
remove_filter( 'woocommerce_data_stores', '__return_empty_array' );
}
/**
* @doesNotPerformAssertions
* @dataProvider methods_never_causing_exception_provider
*
* @param callable $callback Tested NoteTraits method.
*/
public function test_no_exception_is_thrown_even_if_data_store_cannot_be_loaded( $callback ) {
add_filter( 'woocommerce_data_stores', '__return_empty_array' );
$callback();
remove_filter( 'woocommerce_data_stores', '__return_empty_array' );
}
/**
* Method required to use NoteTraits.
*
* @return Note
*/
public static function get_note() {
return new Note();
}
/**
* Data provider providing methods that should throw an exception
* only if the "admin-note" data store cannot be loaded.
*
* @return array[]
*/
public function methods_causing_exception_if_data_store_cannot_be_loaded_provider() {
return array(
array(
function () {
self::note_exists();
},
),
array(
function () {
self::can_be_added();
},
),
array(
function () {
self::possibly_add_note();
},
),
array(
function () {
self::add_note();
},
),
array(
function () {
self::possibly_delete_note();
},
),
array(
function () {
self::has_note_been_actioned();
},
),
);
}
/**
* Data provider providing methods that should not throw
* an exception regardless of the data store being available.
*
* @return array[]
*/
public function methods_never_causing_exception_provider() {
return array(
array(
function () {
self::wc_admin_active_for( 123 );
},
),
);
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
* Notes tests
*
* @package WooCommerce\Admin\Tests\Notes
*/
use Automattic\WooCommerce\Admin\Notes\NotesUnavailableException;
use Automattic\WooCommerce\Admin\Notes\Notes;
/**
* Class WC_Tests_Notes
*/
class WC_Tests_Notes extends WC_Unit_Test_Case {
/**
* If the "admin-note" data store exists, the data store should be
* loaded and returned.
*/
public function test_loads_data_store_if_exists() {
$this->assertInstanceOf( \WC_Data_Store::class, Notes::load_data_store() );
}
/**
* If the "admin-note" data store does not exist, a custom
* exception should be thrown.
*/
public function test_exception_is_thrown_if_data_store_does_not_exist() {
add_filter( 'woocommerce_data_stores', '__return_empty_array' );
$this->expectException( NotesUnavailableException::class );
Notes::load_data_store();
remove_filter( 'woocommerce_data_stores', '__return_empty_array' );
}
}