PageRenderTime 86ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/core/lib/Drupal/Component/Assertion/Inspector.php

https://gitlab.com/geeta7/drupal
PHP | 428 lines | 148 code | 26 blank | 254 comment | 26 complexity | 6dda9a0eaaa70e3192fafea34f5e6d4f MD5 | raw file
  1. <?php
  2. /**
  3. * @file
  4. * Contains \Drupal\Component\Assertion\Inspector.
  5. */
  6. namespace Drupal\Component\Assertion;
  7. use Traversable;
  8. /**
  9. * Generic inspections for the assert() statement.
  10. *
  11. * This is a static function collection for inspecting variable contents. All
  12. * functions in this collection check a variable against an assertion about its
  13. * structure.
  14. *
  15. * Example call:
  16. * @code
  17. * assert('Drupal\\Component\\Assertion\\Inspector::assertAllStrings($array)');
  18. * @endcode
  19. *
  20. * @ingroup php_assert
  21. */
  22. class Inspector {
  23. /**
  24. * Asserts argument can be traversed with foreach.
  25. *
  26. * @param mixed $traversable
  27. * Variable to be examined.
  28. *
  29. * @return bool
  30. * TRUE if $traversable can be traversed with foreach.
  31. */
  32. public static function assertTraversable($traversable) {
  33. return is_array($traversable) || $traversable instanceof Traversable;
  34. }
  35. /**
  36. * Asserts callback returns TRUE for each member of a traversable.
  37. *
  38. * This is less memory intensive than using array_filter() to build a second
  39. * array and then comparing the arrays. Many of the other functions in this
  40. * collection alias this function passing a specific callback to make the
  41. * code more readable.
  42. *
  43. * @param callable $callable
  44. * Callback function.
  45. * @param mixed $traversable
  46. * Variable to be examined.
  47. *
  48. * @return bool
  49. * TRUE if $traversable can be traversed and $callable returns TRUE on
  50. * all members.
  51. *
  52. * @see http://php.net/manual/language.types.callable.php
  53. */
  54. public static function assertAll(callable $callable, $traversable) {
  55. if (static::assertTraversable($traversable)) {
  56. foreach ($traversable as $member) {
  57. if (!$callable($member)) {
  58. return FALSE;
  59. }
  60. }
  61. return TRUE;
  62. }
  63. return FALSE;
  64. }
  65. /**
  66. * Asserts that all members are strings.
  67. *
  68. * Use this only if it is vital that the members not be objects, otherwise
  69. * test with ::assertAllStringable().
  70. *
  71. * @param mixed $traversable
  72. * Variable to be examined.
  73. *
  74. * @return bool
  75. * TRUE if $traversable can be traversed and all members are strings.
  76. */
  77. public static function assertAllStrings($traversable) {
  78. return static::assertAll('is_string', $traversable);
  79. }
  80. /**
  81. * Asserts all members are strings or objects with magic __toString() method.
  82. *
  83. * @param mixed $traversable
  84. * Variable to be examined.
  85. *
  86. * @return bool
  87. * TRUE if $traversable can be traversed and all members are strings or
  88. * objects with __toString().
  89. */
  90. public static function assertAllStringable($traversable) {
  91. if (static::assertTraversable($traversable)) {
  92. foreach ($traversable as $member) {
  93. if (!static::assertStringable($member)) {
  94. return FALSE;
  95. }
  96. }
  97. return TRUE;
  98. }
  99. return FALSE;
  100. }
  101. /**
  102. * Asserts argument is a string or an object castable to a string.
  103. *
  104. * Use this instead of is_string() alone unless the argument being an object
  105. * in any way will cause a problem.
  106. *
  107. * @param mixed string
  108. * Variable to be examined
  109. *
  110. * @return bool
  111. * TRUE if $string is a string or an object castable to a string.
  112. */
  113. public static function assertStringable($string) {
  114. return is_string($string) || (is_object($string) && method_exists($string, '__toString'));
  115. }
  116. /**
  117. * Asserts that all members are arrays.
  118. *
  119. * @param mixed $traversable
  120. * Variable to be examined.
  121. *
  122. * @return bool
  123. * TRUE if $traversable can be traversed and all members are arrays.
  124. */
  125. public static function assertAllArrays($traversable) {
  126. return static::assertAll('is_array', $traversable);
  127. }
  128. /**
  129. * Asserts that the array is strict.
  130. *
  131. * What PHP calls arrays are more formally called maps in most other
  132. * programming languages. A map is a datatype that associates values to keys.
  133. * The term 'strict array' here refers to a 0-indexed array in the classic
  134. * sense found in programming languages other than PHP.
  135. *
  136. * @param mixed $array
  137. * Variable to be examined.
  138. *
  139. * @return bool
  140. * TRUE if $traversable is a 0-indexed array.
  141. *
  142. * @see http://php.net/manual/language.types.array.php
  143. */
  144. public static function assertStrictArray($array) {
  145. if (!is_array($array)) {
  146. return FALSE;
  147. }
  148. $i = 0;
  149. foreach (array_keys($array) as $key) {
  150. if ($i !== $key) {
  151. return FALSE;
  152. }
  153. $i++;
  154. }
  155. return TRUE;
  156. }
  157. /**
  158. * Asserts all members are strict arrays.
  159. *
  160. * @param mixed $traversable
  161. * Variable to be examined.
  162. *
  163. * @return bool
  164. * TRUE if $traversable can be traversed and all members are strict arrays.
  165. *
  166. * @see ::assertStrictArray
  167. */
  168. public static function assertAllStrictArrays($traversable) {
  169. return static::assertAll([__CLASS__, 'assertStrictArray'], $traversable);
  170. }
  171. /**
  172. * Asserts all given keys exist in every member array.
  173. *
  174. * Drupal has several data structure arrays that require certain keys be set.
  175. * You can overload this function to specify a list of required keys. All
  176. * of the keys must be set for this method to return TRUE.
  177. *
  178. * As an example, this assertion tests for the keys of a theme registry.
  179. *
  180. * @code
  181. * assert('Drupal\\Component\\Assertion\\Inspector::assertAllHaveKey(
  182. * $arrayToTest, "type", "theme path", "function", "template", "variables", "render element", "preprocess functions")');
  183. * @endcode
  184. *
  185. * Note: If a method requires certain keys to be present it will usually be
  186. * specific about the data types for the values of those keys. Therefore it
  187. * will be best to write a specific test for it. Such tests are either bound
  188. * to the object that uses them, or are collected into one assertion set for
  189. * the package.
  190. *
  191. * @param mixed $traversable
  192. * Variable to be examined.
  193. * @param string ...
  194. * Keys to be searched for.
  195. *
  196. * @return bool
  197. * TRUE if $traversable can be traversed and all members have all keys.
  198. */
  199. public static function assertAllHaveKey() {
  200. $args = func_get_args();
  201. $traversable = array_shift($args);
  202. if (static::assertTraversable($traversable)) {
  203. foreach ($traversable as $member) {
  204. foreach ($args as $key) {
  205. if (!array_key_exists($key, $member)) {
  206. return FALSE;
  207. }
  208. }
  209. }
  210. return TRUE;
  211. }
  212. return FALSE;
  213. }
  214. /**
  215. * Asserts that all members are integer values.
  216. *
  217. * @param mixed $traversable
  218. * Variable to be examined.
  219. *
  220. * @return bool
  221. * TRUE if $traversable can be traversed and all members are integers.
  222. */
  223. public static function assertAllIntegers($traversable) {
  224. return static::assertAll('is_int', $traversable);
  225. }
  226. /**
  227. * Asserts that all members are float values.
  228. *
  229. * @param mixed $traversable
  230. * Variable to be examined.
  231. *
  232. * @return bool
  233. * TRUE if $traversable can be traversed and all members are floating point
  234. * numbers.
  235. */
  236. public static function assertAllFloat($traversable) {
  237. return static::assertAll('is_float', $traversable);
  238. }
  239. /**
  240. * Asserts that all members are callable.
  241. *
  242. * @param mixed $traversable
  243. * Variable to be examined.
  244. *
  245. * @return bool
  246. * TRUE if $traversable can be traversed and all members are callable.
  247. */
  248. public static function assertAllCallable($traversable) {
  249. return static::assertAll('is_callable', $traversable);
  250. }
  251. /**
  252. * Asserts that all members are not empty.
  253. *
  254. * @param mixed $traversable
  255. * Variable to be examined.
  256. *
  257. * @return bool
  258. * TRUE if $traversable can be traversed and all members not empty.
  259. */
  260. public static function assertAllNotEmpty($traversable) {
  261. if (static::assertTraversable($traversable)) {
  262. foreach ($traversable as $member) {
  263. if (empty($member)) {
  264. return FALSE;
  265. }
  266. }
  267. return TRUE;
  268. }
  269. return FALSE;
  270. }
  271. /**
  272. * Asserts all members are numeric data types or strings castable to such.
  273. *
  274. * @param mixed $traversable
  275. * Variable to be examined.
  276. *
  277. * @return bool
  278. * TRUE if $traversable can be traversed and all members are numeric.
  279. */
  280. public static function assertAllNumeric($traversable) {
  281. return static::assertAll('is_numeric', $traversable);
  282. }
  283. /**
  284. * Asserts that all members are strings that contain the specified string.
  285. *
  286. * This runs faster than the regular expression equivalent.
  287. *
  288. * @param string $pattern
  289. * The needle to find.
  290. * @param mixed $traversable
  291. * Variable to examine.
  292. * @param bool $case_sensitive
  293. * TRUE to use strstr(), FALSE to use stristr() which is case insensitive.
  294. *
  295. * @return bool
  296. * TRUE if $traversable can be traversed and all members are strings
  297. * containing $pattern.
  298. */
  299. public static function assertAllMatch($pattern, $traversable, $case_sensitive = FALSE) {
  300. if (static::assertTraversable($traversable)) {
  301. if ($case_sensitive) {
  302. foreach ($traversable as $member) {
  303. if (!(is_string($member) && strstr($member, $pattern))) {
  304. return FALSE;
  305. }
  306. }
  307. }
  308. else {
  309. foreach ($traversable as $member) {
  310. if (!(is_string($member) && stristr($member, $pattern))) {
  311. return FALSE;
  312. }
  313. }
  314. }
  315. return TRUE;
  316. }
  317. return FALSE;
  318. }
  319. /**
  320. * Asserts that all members are strings matching a regular expression.
  321. *
  322. * @param string $pattern
  323. * Regular expression string to find.
  324. * @param mixed $traversable
  325. * Variable to be examined.
  326. *
  327. * @return bool
  328. * TRUE if $traversable can be traversed and all members are strings
  329. * matching $pattern.
  330. */
  331. public static function assertAllRegularExpressionMatch($pattern, $traversable) {
  332. if (static::assertTraversable($traversable)) {
  333. foreach ($traversable as $member) {
  334. if (!is_string($member)) {
  335. return FALSE;
  336. }
  337. if (!preg_match($pattern, $member)) {
  338. return FALSE;
  339. }
  340. }
  341. return TRUE;
  342. }
  343. return FALSE;
  344. }
  345. /**
  346. * Asserts that all members are objects.
  347. *
  348. * When testing if a collection is composed of objects those objects should
  349. * be given a common interface to implement and the test should be written to
  350. * search for just that interface. While this method will allow tests for
  351. * just object status or for multiple classes and interfaces this was done to
  352. * allow tests to be written for existing code without altering it. Only use
  353. * this method in that manner when testing code from third party vendors.
  354. *
  355. * Here are some examples:
  356. * @code
  357. * // Just test all are objects, like a cache.
  358. * assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects(
  359. * $collection');
  360. *
  361. * // Test if traversable objects (arrays won't pass this)
  362. * assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects(
  363. * $collection', \'\\Traversable\');
  364. *
  365. * // Test for the Foo class or Bar\None interface
  366. * assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects(
  367. * $collection', \'\\Foo\', \'\\Bar\\None\'');
  368. * @endcode
  369. *
  370. * @param mixed $traversable
  371. * Variable to be examined.
  372. * @param string ...
  373. * Classes and interfaces to test objects against.
  374. *
  375. * @return bool
  376. * TRUE if $traversable can be traversed and all members are objects with
  377. * at least one of the listed classes or interfaces.
  378. */
  379. public static function assertAllObjects() {
  380. $args = func_get_args();
  381. $traversable = array_shift($args);
  382. if (static::assertTraversable($traversable)) {
  383. foreach ($traversable as $member) {
  384. if (count($args) > 0) {
  385. foreach ($args as $instance) {
  386. if ($member instanceof $instance) {
  387. // We're continuing to the next member on the outer loop.
  388. // @see http://php.net/continue
  389. continue 2;
  390. }
  391. }
  392. return FALSE;
  393. }
  394. elseif (!is_object($member)) {
  395. return FALSE;
  396. }
  397. }
  398. return TRUE;
  399. }
  400. return FALSE;
  401. }
  402. }