Mercurial > hg > isophonics-drupal-site
diff core/lib/Drupal/Component/Assertion/Inspector.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/lib/Drupal/Component/Assertion/Inspector.php Wed Nov 29 16:09:58 2017 +0000 @@ -0,0 +1,424 @@ +<?php + +namespace Drupal\Component\Assertion; + +use Traversable; + +/** + * Generic inspections for the assert() statement. + * + * This is a static function collection for inspecting variable contents. All + * functions in this collection check a variable against an assertion about its + * structure. + * + * Example call: + * @code + * assert('Drupal\\Component\\Assertion\\Inspector::assertAllStrings($array)'); + * @endcode + * + * @ingroup php_assert + */ +class Inspector { + + /** + * Asserts argument can be traversed with foreach. + * + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed with foreach. + */ + public static function assertTraversable($traversable) { + return is_array($traversable) || $traversable instanceof Traversable; + } + + /** + * Asserts callback returns TRUE for each member of a traversable. + * + * This is less memory intensive than using array_filter() to build a second + * array and then comparing the arrays. Many of the other functions in this + * collection alias this function passing a specific callback to make the + * code more readable. + * + * @param callable $callable + * Callback function. + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and $callable returns TRUE on + * all members. + * + * @see http://php.net/manual/language.types.callable.php + */ + public static function assertAll(callable $callable, $traversable) { + if (static::assertTraversable($traversable)) { + foreach ($traversable as $member) { + if (!$callable($member)) { + return FALSE; + } + } + return TRUE; + } + return FALSE; + } + + /** + * Asserts that all members are strings. + * + * Use this only if it is vital that the members not be objects, otherwise + * test with ::assertAllStringable(). + * + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and all members are strings. + */ + public static function assertAllStrings($traversable) { + return static::assertAll('is_string', $traversable); + } + + /** + * Asserts all members are strings or objects with magic __toString() method. + * + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and all members are strings or + * objects with __toString(). + */ + public static function assertAllStringable($traversable) { + if (static::assertTraversable($traversable)) { + foreach ($traversable as $member) { + if (!static::assertStringable($member)) { + return FALSE; + } + } + return TRUE; + } + return FALSE; + } + + /** + * Asserts argument is a string or an object castable to a string. + * + * Use this instead of is_string() alone unless the argument being an object + * in any way will cause a problem. + * + * @param mixed $string + * Variable to be examined + * + * @return bool + * TRUE if $string is a string or an object castable to a string. + */ + public static function assertStringable($string) { + return is_string($string) || (is_object($string) && method_exists($string, '__toString')); + } + + /** + * Asserts that all members are arrays. + * + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and all members are arrays. + */ + public static function assertAllArrays($traversable) { + return static::assertAll('is_array', $traversable); + } + + /** + * Asserts that the array is strict. + * + * What PHP calls arrays are more formally called maps in most other + * programming languages. A map is a datatype that associates values to keys. + * The term 'strict array' here refers to a 0-indexed array in the classic + * sense found in programming languages other than PHP. + * + * @param mixed $array + * Variable to be examined. + * + * @return bool + * TRUE if $traversable is a 0-indexed array. + * + * @see http://php.net/manual/language.types.array.php + */ + public static function assertStrictArray($array) { + if (!is_array($array)) { + return FALSE; + } + $i = 0; + + foreach (array_keys($array) as $key) { + if ($i !== $key) { + return FALSE; + } + $i++; + } + return TRUE; + } + + /** + * Asserts all members are strict arrays. + * + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and all members are strict arrays. + * + * @see ::assertStrictArray + */ + public static function assertAllStrictArrays($traversable) { + return static::assertAll([__CLASS__, 'assertStrictArray'], $traversable); + } + + /** + * Asserts all given keys exist in every member array. + * + * Drupal has several data structure arrays that require certain keys be set. + * You can overload this function to specify a list of required keys. All + * of the keys must be set for this method to return TRUE. + * + * As an example, this assertion tests for the keys of a theme registry. + * + * @code + * assert('Drupal\\Component\\Assertion\\Inspector::assertAllHaveKey( + * $arrayToTest, "type", "theme path", "function", "template", "variables", "render element", "preprocess functions")'); + * @endcode + * + * Note: If a method requires certain keys to be present it will usually be + * specific about the data types for the values of those keys. Therefore it + * will be best to write a specific test for it. Such tests are either bound + * to the object that uses them, or are collected into one assertion set for + * the package. + * + * @param mixed $traversable + * Variable to be examined. + * @param string ... + * Keys to be searched for. + * + * @return bool + * TRUE if $traversable can be traversed and all members have all keys. + */ + public static function assertAllHaveKey($traversable) { + $args = func_get_args(); + unset($args[0]); + + if (static::assertTraversable($traversable)) { + foreach ($traversable as $member) { + foreach ($args as $key) { + if (!array_key_exists($key, $member)) { + return FALSE; + } + } + } + return TRUE; + } + return FALSE; + } + + /** + * Asserts that all members are integer values. + * + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and all members are integers. + */ + public static function assertAllIntegers($traversable) { + return static::assertAll('is_int', $traversable); + } + + /** + * Asserts that all members are float values. + * + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and all members are floating point + * numbers. + */ + public static function assertAllFloat($traversable) { + return static::assertAll('is_float', $traversable); + } + + /** + * Asserts that all members are callable. + * + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and all members are callable. + */ + public static function assertAllCallable($traversable) { + return static::assertAll('is_callable', $traversable); + } + + /** + * Asserts that all members are not empty. + * + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and all members not empty. + */ + public static function assertAllNotEmpty($traversable) { + if (static::assertTraversable($traversable)) { + foreach ($traversable as $member) { + if (empty($member)) { + return FALSE; + } + } + return TRUE; + } + return FALSE; + } + + /** + * Asserts all members are numeric data types or strings castable to such. + * + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and all members are numeric. + */ + public static function assertAllNumeric($traversable) { + return static::assertAll('is_numeric', $traversable); + } + + /** + * Asserts that all members are strings that contain the specified string. + * + * This runs faster than the regular expression equivalent. + * + * @param string $pattern + * The needle to find. + * @param mixed $traversable + * Variable to examine. + * @param bool $case_sensitive + * TRUE to use strstr(), FALSE to use stristr() which is case insensitive. + * + * @return bool + * TRUE if $traversable can be traversed and all members are strings + * containing $pattern. + */ + public static function assertAllMatch($pattern, $traversable, $case_sensitive = FALSE) { + if (static::assertTraversable($traversable)) { + if ($case_sensitive) { + foreach ($traversable as $member) { + if (!(is_string($member) && strstr($member, $pattern))) { + return FALSE; + } + } + } + else { + foreach ($traversable as $member) { + if (!(is_string($member) && stristr($member, $pattern))) { + return FALSE; + } + } + } + return TRUE; + } + return FALSE; + } + + + /** + * Asserts that all members are strings matching a regular expression. + * + * @param string $pattern + * Regular expression string to find. + * @param mixed $traversable + * Variable to be examined. + * + * @return bool + * TRUE if $traversable can be traversed and all members are strings + * matching $pattern. + */ + public static function assertAllRegularExpressionMatch($pattern, $traversable) { + if (static::assertTraversable($traversable)) { + foreach ($traversable as $member) { + if (!is_string($member)) { + return FALSE; + } + + if (!preg_match($pattern, $member)) { + return FALSE; + } + } + return TRUE; + } + return FALSE; + } + + /** + * Asserts that all members are objects. + * + * When testing if a collection is composed of objects those objects should + * be given a common interface to implement and the test should be written to + * search for just that interface. While this method will allow tests for + * just object status or for multiple classes and interfaces this was done to + * allow tests to be written for existing code without altering it. Only use + * this method in that manner when testing code from third party vendors. + * + * Here are some examples: + * @code + * // Just test all are objects, like a cache. + * assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects( + * $collection'); + * + * // Test if traversable objects (arrays won't pass this) + * assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects( + * $collection', \'\\Traversable\'); + * + * // Test for the Foo class or Bar\None interface + * assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects( + * $collection', \'\\Foo\', \'\\Bar\\None\''); + * @endcode + * + * @param mixed $traversable + * Variable to be examined. + * @param string ... + * Classes and interfaces to test objects against. + * + * @return bool + * TRUE if $traversable can be traversed and all members are objects with + * at least one of the listed classes or interfaces. + */ + public static function assertAllObjects($traversable) { + $args = func_get_args(); + unset($args[0]); + + if (static::assertTraversable($traversable)) { + foreach ($traversable as $member) { + if (count($args) > 0) { + foreach ($args as $instance) { + if ($member instanceof $instance) { + // We're continuing to the next member on the outer loop. + // @see http://php.net/continue + continue 2; + } + } + return FALSE; + } + elseif (!is_object($member)) { + return FALSE; + } + } + return TRUE; + } + return FALSE; + } + +}