Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
37 / 37
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
HasOnlyOneThatEquals
100.00% covered (success)
100.00%
37 / 37
100.00% covered (success)
100.00%
2 / 2
20
100.00% covered (success)
100.00%
1 / 1
 evaluate
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
14
 generateDefaultMessage
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
6
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Validator;
16
17/**
18 * Has one that equals validator class
19 *
20 * @category   Pop
21 * @package    Pop\Validator
22 * @author     Nick Sagona, III <nick@popphp.org>
23 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    5.0.0
26 */
27class HasOnlyOneThatEquals extends AbstractValidator
28{
29
30    /**
31     * Traits
32     */
33    use TraverseTrait;
34
35    /**
36     * Method to evaluate the validator
37     *
38     * @param  mixed $input
39     * @param  bool  $isDateTime
40     * @return bool
41     *@throws Exception
42     */
43    public function evaluate(mixed $input = null, bool $isDateTime = false): bool
44    {
45        // Set the input, if passed
46        if ($input !== null) {
47            $this->input = $input;
48        }
49
50        $result = false;
51
52        if (!is_array($this->input)) {
53            throw new Exception('Error: The evaluated input must be an array.');
54        }
55        if (!is_array($this->value)) {
56            throw new Exception("Error: The evaluated value must be an array of node name and value, e.g. ['node.name' => 3].");
57        }
58
59        $field         = array_key_first($this->value);
60        $requiredValue = reset($this->value);
61
62        // Set the default message
63        if (!$this->hasMessage()) {
64            $this->generateDefaultMessage();
65        }
66
67        if (!str_contains($field, '.')) {
68            throw new Exception("Error: The evaluated value must been an array with a column name, e.g. 'users.username'.");
69        }
70
71        $parent = substr($field, 0, strrpos($field, '.'));
72        $child  = substr($field, (strrpos($field, '.') + 1));
73        $value  = [];
74        $count  = 0;
75        self::traverseData($parent, $this->input, $value);
76
77        foreach ($value as $val) {
78            if (is_array($val)) {
79                foreach ($val as $item) {
80                    if (is_array($item) && isset($item[$child])) {
81                        if ($isDateTime) {
82                            if (strtotime($item[$child]) == strtotime($requiredValue)) {
83                                $count++;
84                            }
85                        } else {
86                            if ($item[$child] == $requiredValue) {
87                                $count++;
88                            }
89                        }
90                    }
91                }
92            }
93        }
94
95        return ($count == 1);
96    }
97
98    /**
99     * Generate default message
100
101     * @param  mixed $name
102     * @param  mixed $value
103     * @return string
104     */
105    public function generateDefaultMessage(mixed $name = null, mixed $value = null): string
106    {
107        $field = null;
108
109        if (($value !== null) && is_array($value)) {
110            $field = array_key_first($value);
111        } else if ($this->value !== null) {
112            $field = array_key_first($this->value);
113        }
114
115        $this->message = "The " . (($name !== null) ? "'" . $name . "'" : "input") .
116            " must contain only one item" . (($this->value !== null) ? " of '" . $field . "'" : "") .
117            " with the required value.";
118
119        return $this->message;
120    }
121
122}