/lib/phpspreadsheet/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/Logical.php

https://github.com/markn86/moodle · PHP · 390 lines · 158 code · 41 blank · 191 comment · 52 complexity · 7b0da7b74d60a080d369fdb1a2e1f728 MD5 · raw file

  1. <?php
  2. namespace PhpOffice\PhpSpreadsheet\Calculation;
  3. class Logical
  4. {
  5. /**
  6. * TRUE.
  7. *
  8. * Returns the boolean TRUE.
  9. *
  10. * Excel Function:
  11. * =TRUE()
  12. *
  13. * @return bool True
  14. */
  15. public static function true()
  16. {
  17. return true;
  18. }
  19. /**
  20. * FALSE.
  21. *
  22. * Returns the boolean FALSE.
  23. *
  24. * Excel Function:
  25. * =FALSE()
  26. *
  27. * @return bool False
  28. */
  29. public static function false()
  30. {
  31. return false;
  32. }
  33. private static function countTrueValues(array $args)
  34. {
  35. $returnValue = 0;
  36. foreach ($args as $arg) {
  37. // Is it a boolean value?
  38. if (is_bool($arg)) {
  39. $returnValue += $arg;
  40. } elseif ((is_numeric($arg)) && (!is_string($arg))) {
  41. $returnValue += ((int) $arg != 0);
  42. } elseif (is_string($arg)) {
  43. $arg = strtoupper($arg);
  44. if (($arg == 'TRUE') || ($arg == Calculation::getTRUE())) {
  45. $arg = true;
  46. } elseif (($arg == 'FALSE') || ($arg == Calculation::getFALSE())) {
  47. $arg = false;
  48. } else {
  49. return Functions::VALUE();
  50. }
  51. $returnValue += ($arg != 0);
  52. }
  53. }
  54. return $returnValue;
  55. }
  56. /**
  57. * LOGICAL_AND.
  58. *
  59. * Returns boolean TRUE if all its arguments are TRUE; returns FALSE if one or more argument is FALSE.
  60. *
  61. * Excel Function:
  62. * =AND(logical1[,logical2[, ...]])
  63. *
  64. * The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
  65. * or references that contain logical values.
  66. *
  67. * Boolean arguments are treated as True or False as appropriate
  68. * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  69. * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
  70. * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
  71. *
  72. * @param mixed ...$args Data values
  73. *
  74. * @return bool|string the logical AND of the arguments
  75. */
  76. public static function logicalAnd(...$args)
  77. {
  78. $args = Functions::flattenArray($args);
  79. if (count($args) == 0) {
  80. return Functions::VALUE();
  81. }
  82. $args = array_filter($args, function ($value) {
  83. return $value !== null || (is_string($value) && trim($value) == '');
  84. });
  85. $argCount = count($args);
  86. $returnValue = self::countTrueValues($args);
  87. if (is_string($returnValue)) {
  88. return $returnValue;
  89. }
  90. return ($returnValue > 0) && ($returnValue == $argCount);
  91. }
  92. /**
  93. * LOGICAL_OR.
  94. *
  95. * Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE.
  96. *
  97. * Excel Function:
  98. * =OR(logical1[,logical2[, ...]])
  99. *
  100. * The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
  101. * or references that contain logical values.
  102. *
  103. * Boolean arguments are treated as True or False as appropriate
  104. * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  105. * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
  106. * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
  107. *
  108. * @param mixed $args Data values
  109. *
  110. * @return bool|string the logical OR of the arguments
  111. */
  112. public static function logicalOr(...$args)
  113. {
  114. $args = Functions::flattenArray($args);
  115. if (count($args) == 0) {
  116. return Functions::VALUE();
  117. }
  118. $args = array_filter($args, function ($value) {
  119. return $value !== null || (is_string($value) && trim($value) == '');
  120. });
  121. $returnValue = self::countTrueValues($args);
  122. if (is_string($returnValue)) {
  123. return $returnValue;
  124. }
  125. return $returnValue > 0;
  126. }
  127. /**
  128. * LOGICAL_XOR.
  129. *
  130. * Returns the Exclusive Or logical operation for one or more supplied conditions.
  131. * i.e. the Xor function returns TRUE if an odd number of the supplied conditions evaluate to TRUE, and FALSE otherwise.
  132. *
  133. * Excel Function:
  134. * =XOR(logical1[,logical2[, ...]])
  135. *
  136. * The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
  137. * or references that contain logical values.
  138. *
  139. * Boolean arguments are treated as True or False as appropriate
  140. * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  141. * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
  142. * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
  143. *
  144. * @param mixed $args Data values
  145. *
  146. * @return bool|string the logical XOR of the arguments
  147. */
  148. public static function logicalXor(...$args)
  149. {
  150. $args = Functions::flattenArray($args);
  151. if (count($args) == 0) {
  152. return Functions::VALUE();
  153. }
  154. $args = array_filter($args, function ($value) {
  155. return $value !== null || (is_string($value) && trim($value) == '');
  156. });
  157. $returnValue = self::countTrueValues($args);
  158. if (is_string($returnValue)) {
  159. return $returnValue;
  160. }
  161. return $returnValue % 2 == 1;
  162. }
  163. /**
  164. * NOT.
  165. *
  166. * Returns the boolean inverse of the argument.
  167. *
  168. * Excel Function:
  169. * =NOT(logical)
  170. *
  171. * The argument must evaluate to a logical value such as TRUE or FALSE
  172. *
  173. * Boolean arguments are treated as True or False as appropriate
  174. * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
  175. * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
  176. * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
  177. *
  178. * @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE
  179. *
  180. * @return bool|string the boolean inverse of the argument
  181. */
  182. public static function NOT($logical = false)
  183. {
  184. $logical = Functions::flattenSingleValue($logical);
  185. if (is_string($logical)) {
  186. $logical = strtoupper($logical);
  187. if (($logical == 'TRUE') || ($logical == Calculation::getTRUE())) {
  188. return false;
  189. } elseif (($logical == 'FALSE') || ($logical == Calculation::getFALSE())) {
  190. return true;
  191. }
  192. return Functions::VALUE();
  193. }
  194. return !$logical;
  195. }
  196. /**
  197. * STATEMENT_IF.
  198. *
  199. * Returns one value if a condition you specify evaluates to TRUE and another value if it evaluates to FALSE.
  200. *
  201. * Excel Function:
  202. * =IF(condition[,returnIfTrue[,returnIfFalse]])
  203. *
  204. * Condition is any value or expression that can be evaluated to TRUE or FALSE.
  205. * For example, A10=100 is a logical expression; if the value in cell A10 is equal to 100,
  206. * the expression evaluates to TRUE. Otherwise, the expression evaluates to FALSE.
  207. * This argument can use any comparison calculation operator.
  208. * ReturnIfTrue is the value that is returned if condition evaluates to TRUE.
  209. * For example, if this argument is the text string "Within budget" and the condition argument evaluates to TRUE,
  210. * then the IF function returns the text "Within budget"
  211. * If condition is TRUE and ReturnIfTrue is blank, this argument returns 0 (zero). To display the word TRUE, use
  212. * the logical value TRUE for this argument.
  213. * ReturnIfTrue can be another formula.
  214. * ReturnIfFalse is the value that is returned if condition evaluates to FALSE.
  215. * For example, if this argument is the text string "Over budget" and the condition argument evaluates to FALSE,
  216. * then the IF function returns the text "Over budget".
  217. * If condition is FALSE and ReturnIfFalse is omitted, then the logical value FALSE is returned.
  218. * If condition is FALSE and ReturnIfFalse is blank, then the value 0 (zero) is returned.
  219. * ReturnIfFalse can be another formula.
  220. *
  221. * @param mixed $condition Condition to evaluate
  222. * @param mixed $returnIfTrue Value to return when condition is true
  223. * @param mixed $returnIfFalse Optional value to return when condition is false
  224. *
  225. * @return mixed The value of returnIfTrue or returnIfFalse determined by condition
  226. */
  227. public static function statementIf($condition = true, $returnIfTrue = 0, $returnIfFalse = false)
  228. {
  229. if (Functions::isError($condition)) {
  230. return $condition;
  231. }
  232. $condition = ($condition === null) ? true : (bool) Functions::flattenSingleValue($condition);
  233. $returnIfTrue = ($returnIfTrue === null) ? 0 : Functions::flattenSingleValue($returnIfTrue);
  234. $returnIfFalse = ($returnIfFalse === null) ? false : Functions::flattenSingleValue($returnIfFalse);
  235. return ($condition) ? $returnIfTrue : $returnIfFalse;
  236. }
  237. /**
  238. * STATEMENT_SWITCH.
  239. *
  240. * Returns corresponding with first match (any data type such as a string, numeric, date, etc).
  241. *
  242. * Excel Function:
  243. * =SWITCH (expression, value1, result1, value2, result2, ... value_n, result_n [, default])
  244. *
  245. * Expression
  246. * The expression to compare to a list of values.
  247. * value1, value2, ... value_n
  248. * A list of values that are compared to expression. The SWITCH function is looking for the first value that matches the expression.
  249. * result1, result2, ... result_n
  250. * A list of results. The SWITCH function returns the corresponding result when a value matches expression.
  251. * default
  252. * Optional. It is the default to return if expression does not match any of the values (value1, value2, ... value_n).
  253. *
  254. * @param mixed $arguments Statement arguments
  255. *
  256. * @return mixed The value of matched expression
  257. */
  258. public static function statementSwitch(...$arguments)
  259. {
  260. $result = Functions::VALUE();
  261. if (count($arguments) > 0) {
  262. $targetValue = Functions::flattenSingleValue($arguments[0]);
  263. $argc = count($arguments) - 1;
  264. $switchCount = floor($argc / 2);
  265. $switchSatisfied = false;
  266. $hasDefaultClause = $argc % 2 !== 0;
  267. $defaultClause = $argc % 2 === 0 ? null : $arguments[count($arguments) - 1];
  268. if ($switchCount) {
  269. for ($index = 0; $index < $switchCount; ++$index) {
  270. if ($targetValue == $arguments[$index * 2 + 1]) {
  271. $result = $arguments[$index * 2 + 2];
  272. $switchSatisfied = true;
  273. break;
  274. }
  275. }
  276. }
  277. if (!$switchSatisfied) {
  278. $result = $hasDefaultClause ? $defaultClause : Functions::NA();
  279. }
  280. }
  281. return $result;
  282. }
  283. /**
  284. * IFERROR.
  285. *
  286. * Excel Function:
  287. * =IFERROR(testValue,errorpart)
  288. *
  289. * @param mixed $testValue Value to check, is also the value returned when no error
  290. * @param mixed $errorpart Value to return when testValue is an error condition
  291. *
  292. * @return mixed The value of errorpart or testValue determined by error condition
  293. */
  294. public static function IFERROR($testValue = '', $errorpart = '')
  295. {
  296. $testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue);
  297. $errorpart = ($errorpart === null) ? '' : Functions::flattenSingleValue($errorpart);
  298. return self::statementIf(Functions::isError($testValue), $errorpart, $testValue);
  299. }
  300. /**
  301. * IFNA.
  302. *
  303. * Excel Function:
  304. * =IFNA(testValue,napart)
  305. *
  306. * @param mixed $testValue Value to check, is also the value returned when not an NA
  307. * @param mixed $napart Value to return when testValue is an NA condition
  308. *
  309. * @return mixed The value of errorpart or testValue determined by error condition
  310. */
  311. public static function IFNA($testValue = '', $napart = '')
  312. {
  313. $testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue);
  314. $napart = ($napart === null) ? '' : Functions::flattenSingleValue($napart);
  315. return self::statementIf(Functions::isNa($testValue), $napart, $testValue);
  316. }
  317. /**
  318. * IFS.
  319. *
  320. * Excel Function:
  321. * =IFS(testValue1;returnIfTrue1;testValue2;returnIfTrue2;...;testValue_n;returnIfTrue_n)
  322. *
  323. * testValue1 ... testValue_n
  324. * Conditions to Evaluate
  325. * returnIfTrue1 ... returnIfTrue_n
  326. * Value returned if corresponding testValue (nth) was true
  327. *
  328. * @param mixed ...$arguments Statement arguments
  329. *
  330. * @return mixed|string The value of returnIfTrue_n, if testValue_n was true. #N/A if none of testValues was true
  331. */
  332. public static function IFS(...$arguments)
  333. {
  334. if (count($arguments) % 2 != 0) {
  335. return Functions::NA();
  336. }
  337. // We use instance of Exception as a falseValue in order to prevent string collision with value in cell
  338. $falseValueException = new Exception();
  339. for ($i = 0; $i < count($arguments); $i += 2) {
  340. $testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]);
  341. $returnIfTrue = ($arguments[$i + 1] === null) ? '' : Functions::flattenSingleValue($arguments[$i + 1]);
  342. $result = self::statementIf($testValue, $returnIfTrue, $falseValueException);
  343. if ($result !== $falseValueException) {
  344. return $result;
  345. }
  346. }
  347. return Functions::NA();
  348. }
  349. }