diff --git a/includes/Checker/Abstract_Check_Runner.php b/includes/Checker/Abstract_Check_Runner.php
index ce4b89af4..59138e1bd 100644
--- a/includes/Checker/Abstract_Check_Runner.php
+++ b/includes/Checker/Abstract_Check_Runner.php
@@ -368,7 +368,10 @@ final public function get_checks_to_run() {
$check_flags = $check_flags | Check_Repository::INCLUDE_EXPERIMENTAL;
}
- $checks = $this->check_repository->get_checks( $check_flags, $check_slugs );
+ $checks = $this->check_repository->get_checks( $check_flags )
+ ->require( $check_slugs ) // Ensures all of the given slugs are valid.
+ ->include( $check_slugs ) // Ensures only the checks with the given slugs are included.
+ ->to_map();
// Filters the checks by specific categories.
$categories = $this->get_categories();
diff --git a/includes/Checker/Check_Collection.php b/includes/Checker/Check_Collection.php
new file mode 100644
index 000000000..c5698cbe3
--- /dev/null
+++ b/includes/Checker/Check_Collection.php
@@ -0,0 +1,74 @@
+ $check_obj` pairs.
+ */
+ public function to_map(): array;
+
+ /**
+ * Returns a new check collection containing the subset of checks based on the given check filter function.
+ *
+ * @since n.e.x.t
+ *
+ * @param callable $filter_fn Filter function that accepts a single check object and should return a boolean for
+ * whether to include the check in the new collection.
+ * @return Check_Collection New check collection, effectively a subset of this one.
+ */
+ public function filter( callable $filter_fn ): Check_Collection;
+
+ /**
+ * Returns a new check collection containing the subset of checks based on the given check slugs.
+ *
+ * If the given list is empty, the same collection will be returned without any change.
+ *
+ * @since n.e.x.t
+ *
+ * @param array $check_slugs List of slugs to limit to only those. If empty, the same collection is returned.
+ * @return Check_Collection New check collection, effectively a subset of this one.
+ */
+ public function include( array $check_slugs ): Check_Collection;
+
+ /**
+ * Throws an exception if any of the given check slugs are not present, or returns the same collection otherwise.
+ *
+ * @since n.e.x.t
+ *
+ * @param array $check_slugs List of slugs to limit to only those. If empty, the same collection is returned.
+ * @return Check_Collection The unchanged check collection.
+ *
+ * @throws Exception Thrown when any of the given check slugs is not present in the collection.
+ */
+ public function require( array $check_slugs ): Check_Collection;
+}
diff --git a/includes/Checker/Check_Repository.php b/includes/Checker/Check_Repository.php
index 1c1141093..7c757d04b 100644
--- a/includes/Checker/Check_Repository.php
+++ b/includes/Checker/Check_Repository.php
@@ -63,9 +63,8 @@ public function register_check( $slug, Check $check );
*
* @since n.e.x.t
*
- * @param int $flags The check type flag.
- * @param array $check_slugs An array of check slugs to return.
- * @return array An indexed array of check instances.
+ * @param int $flags The check type flag.
+ * @return Check_Collection Check collection providing an indexed array of check instances.
*/
- public function get_checks( $flags = self::TYPE_ALL, array $check_slugs = array() );
+ public function get_checks( $flags = self::TYPE_ALL );
}
diff --git a/includes/Checker/Default_Check_Collection.php b/includes/Checker/Default_Check_Collection.php
new file mode 100644
index 000000000..de81e85b9
--- /dev/null
+++ b/includes/Checker/Default_Check_Collection.php
@@ -0,0 +1,232 @@
+ $check_obj` pairs.
+ *
+ * @since n.e.x.t
+ * @var array
+ */
+ private $checks;
+
+ /**
+ * List of check slugs, in the same order as `$checks` - effectively the keys of that array.
+ *
+ * @since n.e.x.t
+ * @var array
+ */
+ private $slugs;
+
+ /**
+ * Constructor.
+ *
+ * @since n.e.x.t
+ *
+ * @param array $checks Map of `$check_slug => $check_obj` pairs for the collection.
+ */
+ public function __construct( array $checks ) {
+ $this->checks = $checks;
+ $this->slugs = array_keys( $this->checks );
+ }
+
+ /**
+ * Returns the raw indexed array representation of this collection.
+ *
+ * @since n.e.x.t
+ *
+ * @return array The indexed array of check objects.
+ */
+ public function to_array(): array {
+ return array_values( $this->checks );
+ }
+
+ /**
+ * Returns the raw map of check slugs and their check objects as a representation of this collection.
+ *
+ * @since n.e.x.t
+ *
+ * @return array Map of `$check_slug => $check_obj` pairs.
+ */
+ public function to_map(): array {
+ return $this->checks;
+ }
+
+ /**
+ * Returns a new check collection containing the subset of checks based on the given check filter function.
+ *
+ * @since n.e.x.t
+ *
+ * @param callable $filter_fn Filter function that accepts a single check object and should return a boolean for
+ * whether to include the check in the new collection.
+ * @return Check_Collection New check collection, effectively a subset of this one.
+ */
+ public function filter( callable $filter_fn ): Check_Collection {
+ return new self(
+ array_filter(
+ $this->checks,
+ $filter_fn
+ )
+ );
+ }
+
+ /**
+ * Returns a new check collection containing the subset of checks based on the given check slugs.
+ *
+ * If the given list is empty, the same collection will be returned without any change.
+ *
+ * @since n.e.x.t
+ *
+ * @param array $check_slugs List of slugs to limit to only those. If empty, the same collection is returned.
+ * @return Check_Collection New check collection, effectively a subset of this one.
+ */
+ public function include( array $check_slugs ): Check_Collection {
+ // Return unmodified collection if no check slugs to limit to are given.
+ if ( ! $check_slugs ) {
+ return $this;
+ }
+
+ $check_slugs = array_flip( $check_slugs );
+
+ $checks = array();
+ foreach ( $this->checks as $slug => $check ) {
+ if ( ! isset( $check_slugs[ $slug ] ) ) {
+ continue;
+ }
+
+ $checks[ $slug ] = $check;
+ }
+
+ return new self( $checks );
+ }
+
+ /**
+ * Throws an exception if any of the given check slugs are not present, or returns the same collection otherwise.
+ *
+ * @since n.e.x.t
+ *
+ * @param array $check_slugs List of slugs to limit to only those. If empty, the same collection is returned.
+ * @return Check_Collection The unchanged check collection.
+ *
+ * @throws Exception Thrown when any of the given check slugs is not present in the collection.
+ */
+ public function require( array $check_slugs ): Check_Collection {
+ foreach ( $check_slugs as $slug ) {
+ if ( ! isset( $this->checks[ $slug ] ) ) {
+ throw new Exception(
+ sprintf(
+ /* translators: %s: The Check slug. */
+ __( 'Check with the slug "%s" does not exist.', 'plugin-check' ),
+ $slug
+ )
+ );
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Counts the checks in the collection.
+ *
+ * @since n.e.x.t
+ *
+ * @return int Number of checks in the collection.
+ */
+ public function count(): int {
+ return count( $this->checks );
+ }
+
+ /**
+ * Returns an iterator for the checks in the collection.
+ *
+ * @since n.e.x.t
+ *
+ * @return Traversable Checks iterator.
+ */
+ public function getIterator(): Traversable {
+ return new ArrayIterator( $this->checks );
+ }
+
+ /**
+ * Checks whether a check exists with the given slug or index.
+ *
+ * @since n.e.x.t
+ *
+ * @param string|int $offset Either a check slug (string) or index (integer).
+ * @return bool True if a check exists at the given slug or index, false otherwise.
+ */
+ public function offsetExists( $offset ) {
+ if ( is_string( $offset ) ) {
+ return isset( $this->checks[ $offset ] );
+ }
+
+ return isset( $this->slugs[ $offset ] );
+ }
+
+ /**
+ * Retrieves the check with the given slug or index.
+ *
+ * @since n.e.x.t
+ *
+ * @param string|int $offset Either a check slug (string) or index (integer).
+ * @return Check|null Check with the given slug or index, or null if it does not exist.
+ */
+ public function offsetGet( $offset ) {
+ if ( is_string( $offset ) ) {
+ if ( isset( $this->checks[ $offset ] ) ) {
+ return $this->checks[ $offset ];
+ }
+ return null;
+ }
+
+ if ( isset( $this->slugs[ $offset ] ) ) {
+ return $this->checks[ $this->slugs[ $offset ] ];
+ }
+
+ return null;
+ }
+
+ /**
+ * Sets a check in the collection.
+ *
+ * This method does nothing as the collection is read-only.
+ *
+ * @since n.e.x.t
+ *
+ * @param string|int $offset Either a check slug (string) or index (integer).
+ * @param mixed $value Value to set.
+ */
+ public function offsetSet( $offset, $value ) {
+ // Not implemented as this is a read-only collection.
+ }
+
+ /**
+ * Removes a check from the collection.
+ *
+ * This method does nothing as the collection is read-only.
+ *
+ * @since n.e.x.t
+ *
+ * @param string|int $offset Either a check slug (string) or index (integer).
+ */
+ public function offsetUnset( $offset ) {
+ // Not implemented as this is a read-only collection.
+ }
+}
diff --git a/includes/Checker/Default_Check_Repository.php b/includes/Checker/Default_Check_Repository.php
index 761b0fee3..aa1670c14 100644
--- a/includes/Checker/Default_Check_Repository.php
+++ b/includes/Checker/Default_Check_Repository.php
@@ -82,13 +82,10 @@ public function register_check( $slug, Check $check ) {
*
* @since n.e.x.t
*
- * @param int $flags The check type flag.
- * @param array $check_slugs An array of check slugs to return.
- * @return array An array of check instances.
- *
- * @throws Exception Thrown when invalid flag is passed, or Check slug does not exist.
+ * @param int $flags The check type flag.
+ * @return Check_Collection Check collection providing an indexed array of check instances.
*/
- public function get_checks( $flags = self::TYPE_ALL, array $check_slugs = array() ) {
+ public function get_checks( $flags = self::TYPE_ALL ) {
$checks = array();
if ( $flags & self::TYPE_STATIC ) {
@@ -99,34 +96,13 @@ public function get_checks( $flags = self::TYPE_ALL, array $check_slugs = array(
$checks += $this->runtime_checks;
}
- // Filter out the specific check slugs requested.
- if ( ! empty( $check_slugs ) ) {
- $checks = array_map(
- function ( $slug ) use ( $checks ) {
- if ( ! isset( $checks[ $slug ] ) ) {
- throw new Exception(
- sprintf(
- /* translators: %s: The Check slug. */
- __( 'Check with the slug "%s" does not exist.', 'plugin-check' ),
- $slug
- )
- );
- }
-
- return $checks[ $slug ];
- },
- $check_slugs
- );
- }
-
// Return all checks, including experimental if requested.
if ( $flags & self::INCLUDE_EXPERIMENTAL ) {
- return $checks;
+ return new Default_Check_Collection( $checks );
}
// Remove experimental checks before returning.
- return array_filter(
- $checks,
+ return ( new Default_Check_Collection( $checks ) )->filter(
static function ( $check ) {
return $check->get_stability() !== Check::STABILITY_EXPERIMENTAL;
}
diff --git a/phpmd.xml b/phpmd.xml
index 0dc175f0d..6e6f9cc61 100644
--- a/phpmd.xml
+++ b/phpmd.xml
@@ -11,6 +11,7 @@
+
@@ -19,6 +20,12 @@
+
+
+
+
+
+
diff --git a/tests/phpunit/Checker/Check_Categories_Tests.php b/tests/phpunit/Checker/Check_Categories_Tests.php
index a6d26035b..7399a80e6 100644
--- a/tests/phpunit/Checker/Check_Categories_Tests.php
+++ b/tests/phpunit/Checker/Check_Categories_Tests.php
@@ -44,7 +44,8 @@ public function test_filter_checks_by_categories( array $categories, array $all_
$this->repository->register_check( $check[0], $check[1] );
}
- $checks = $this->repository->get_checks();
+ $checks = $this->repository->get_checks()
+ ->to_map();
$check_categories = new Check_Categories();
$filtered_checks = $check_categories->filter_checks_by_categories( $checks, $categories );
diff --git a/tests/phpunit/Checker/Default_Check_Collection_Tests.php b/tests/phpunit/Checker/Default_Check_Collection_Tests.php
new file mode 100644
index 000000000..152e27370
--- /dev/null
+++ b/tests/phpunit/Checker/Default_Check_Collection_Tests.php
@@ -0,0 +1,93 @@
+checks = array(
+ 'static_check' => new Static_Check(),
+ 'runtime_check' => new Runtime_Check(),
+ );
+
+ $repository = new Default_Check_Repository();
+ foreach ( $this->checks as $slug => $check ) {
+ $repository->register_check( $slug, $check );
+ }
+
+ $this->collection = $repository->get_checks();
+ }
+
+ public function test_to_array() {
+ $this->assertSame(
+ array_values( $this->checks ),
+ $this->collection->to_array()
+ );
+ }
+
+ public function test_to_map() {
+ $this->assertSame(
+ $this->checks,
+ $this->collection->to_map()
+ );
+ }
+
+ public function test_filter() {
+ $this->assertSame(
+ array( $this->checks['runtime_check'] ),
+ $this->collection->filter(
+ function ( $check ) {
+ return $check instanceof Runtime_Check_Interface;
+ }
+ )->to_array()
+ );
+ }
+
+ public function test_include() {
+ $this->assertSame(
+ array( $this->checks['static_check'] ),
+ $this->collection->include( array( 'static_check' ) )->to_array()
+ );
+ }
+
+ public function test_include_with_empty() {
+ $this->assertSame(
+ array_values( $this->checks ),
+ $this->collection->include( array() )->to_array()
+ );
+ }
+
+ public function test_include_with_invalid() {
+ $this->assertSame(
+ array( $this->checks['runtime_check'] ),
+ $this->collection->include( array( 'runtime_check', 'invalid_check' ) )->to_array()
+ );
+ }
+
+ public function test_require() {
+ $this->assertSame(
+ array_values( $this->checks ),
+ $this->collection->require( array( 'static_check' ) )->to_array()
+ );
+ }
+
+ public function test_require_with_invalid() {
+ $this->expectException( 'Exception' );
+ $this->expectExceptionMessage( 'Check with the slug "invalid_check" does not exist.' );
+
+ $this->collection->require( array( 'static_check', 'invalid_check' ) );
+ }
+}
diff --git a/tests/phpunit/Checker/Default_Check_Repository_Tests.php b/tests/phpunit/Checker/Default_Check_Repository_Tests.php
index 8822ce622..b1a8898d9 100644
--- a/tests/phpunit/Checker/Default_Check_Repository_Tests.php
+++ b/tests/phpunit/Checker/Default_Check_Repository_Tests.php
@@ -16,6 +16,8 @@
class Default_Check_Repository_Tests extends WP_UnitTestCase {
+ private $repository;
+
public function set_up() {
parent::set_up();
@@ -26,14 +28,14 @@ public function test_register_static_check() {
$check = new Static_Check();
$this->repository->register_check( 'static_check', $check );
- $this->assertSame( array( 'static_check' => $check ), $this->repository->get_checks() );
+ $this->assertSame( array( 'static_check' => $check ), $this->repository->get_checks()->to_map() );
}
public function test_register_runtime_check() {
$check = new Runtime_Check();
$this->repository->register_check( 'runtime_check', $check );
- $this->assertSame( array( 'runtime_check' => $check ), $this->repository->get_checks() );
+ $this->assertSame( array( 'runtime_check' => $check ), $this->repository->get_checks()->to_map() );
}
public function test_register_exception_thrown_for_invalid_check() {
@@ -86,7 +88,7 @@ public function test_get_checks_returns_all_checks() {
'runtime_check' => $runtime_check,
);
- $this->assertSame( $expected, $this->repository->get_checks() );
+ $this->assertSame( $expected, $this->repository->get_checks()->to_map() );
}
public function test_get_checks_returns_static_checks_via_flag() {
@@ -96,7 +98,7 @@ public function test_get_checks_returns_static_checks_via_flag() {
$this->repository->register_check( 'static_check', $static_check );
$this->repository->register_check( 'runtime_check', $runtime_check );
- $this->assertSame( array( 'static_check' => $static_check ), $this->repository->get_checks( Check_Repository::TYPE_STATIC ) );
+ $this->assertSame( array( 'static_check' => $static_check ), $this->repository->get_checks( Check_Repository::TYPE_STATIC )->to_map() );
}
public function test_get_checks_returns_runtime_checks_via_flag() {
@@ -106,24 +108,7 @@ public function test_get_checks_returns_runtime_checks_via_flag() {
$this->repository->register_check( 'static_check', $static_check );
$this->repository->register_check( 'runtime_check', $runtime_check );
- $this->assertSame( array( 'runtime_check' => $runtime_check ), $this->repository->get_checks( Check_Repository::TYPE_RUNTIME ) );
- }
-
- public function test_get_checks_returns_checks_via_slug() {
- $static_check = new Static_Check();
- $runtime_check = new Runtime_Check();
-
- $this->repository->register_check( 'static_check', $static_check );
- $this->repository->register_check( 'runtime_check', $runtime_check );
-
- $this->assertSame( array( $static_check ), $this->repository->get_checks( Check_Repository::TYPE_ALL, array( 'static_check' ) ) );
- }
-
- public function test_get_checks_throws_exception_for_invalid_check_slug() {
- $this->expectException( 'Exception' );
- $this->expectExceptionMessage( 'Check with the slug "invalid_check" does not exist.' );
-
- $this->repository->get_checks( Check_Repository::TYPE_ALL, array( 'invalid_check' ) );
+ $this->assertSame( array( 'runtime_check' => $runtime_check ), $this->repository->get_checks( Check_Repository::TYPE_RUNTIME )->to_map() );
}
public function test_get_checks_returns_no_experimental_checks_by_default() {
@@ -142,7 +127,7 @@ public function test_get_checks_returns_no_experimental_checks_by_default() {
'runtime_check' => $runtime_check,
);
- $this->assertSame( $expected, $this->repository->get_checks() );
+ $this->assertSame( $expected, $this->repository->get_checks()->to_map() );
}
public function test_get_checks_returns_experimental_checks_with_flag() {
@@ -163,7 +148,7 @@ public function test_get_checks_returns_experimental_checks_with_flag() {
'experimental_runtime_check' => $experimental_runtime_check,
);
- $this->assertSame( $expected, $this->repository->get_checks( Check_Repository::TYPE_ALL | Check_Repository::INCLUDE_EXPERIMENTAL ) );
+ $this->assertSame( $expected, $this->repository->get_checks( Check_Repository::TYPE_ALL | Check_Repository::INCLUDE_EXPERIMENTAL )->to_map() );
}
public function test_get_checks_returns_experimental_static_checks_with_flag() {
@@ -182,7 +167,7 @@ public function test_get_checks_returns_experimental_static_checks_with_flag() {
'experimental_static_check' => $experimental_static_check,
);
- $this->assertSame( $expected, $this->repository->get_checks( Check_Repository::TYPE_STATIC | Check_Repository::INCLUDE_EXPERIMENTAL ) );
+ $this->assertSame( $expected, $this->repository->get_checks( Check_Repository::TYPE_STATIC | Check_Repository::INCLUDE_EXPERIMENTAL )->to_map() );
}
public function test_get_checks_returns_experimental_runtime_checks_with_flag() {
@@ -201,6 +186,6 @@ public function test_get_checks_returns_experimental_runtime_checks_with_flag()
'experimental_runtime_check' => $experimental_runtime_check,
);
- $this->assertSame( $expected, $this->repository->get_checks( Check_Repository::TYPE_RUNTIME | Check_Repository::INCLUDE_EXPERIMENTAL ) );
+ $this->assertSame( $expected, $this->repository->get_checks( Check_Repository::TYPE_RUNTIME | Check_Repository::INCLUDE_EXPERIMENTAL )->to_map() );
}
}