Passed
Push — develop ( 53b14c...3240e8 )
by Johnny
03:29 queued 01:41
created

Alternation::getCombinations()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 8
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 13
rs 10
1
<?php
2
/*
3
 * This file is part of Rivescript-php
4
 *
5
 * (c) Johnny Mast <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Axiom\Rivescript\Cortex\Triggers;
12
13
use Axiom\Rivescript\Cortex\Input;
14
use Axiom\Rivescript\Traits\Regex;
15
16
/**
17
 * Arrays class
18
 *
19
 * The Alternation class determines if a provided trigger
20
 * is an Alternation.
21
 *
22
 * PHP version 7.4 and higher.
23
 *
24
 * @category Core
25
 * @package  Cortext\Triggers
26
 * @author   Johnny Mast <[email protected]>
27
 * @license  https://opensource.org/licenses/MIT MIT
28
 * @link     https://github.com/axiom-labs/rivescript-php
29
 * @since    0.4.0
30
 */
31
class Alternation extends Trigger
32
{
33
    use Regex;
34
35
    /**
36
     * The Regex pattern to find sets
37
     * in the trigger.
38
     *
39
     * Note: This pattern ignores the set if a @ character
40
     * is inside to make sure we don't confuse them with arrays.
41
     *
42
     * @var string
43
     */
44
//    protected string $pattern = "/(\((?!\@)(.+?=*)\))|(\[(?!\@)(.+?=*)\])/ui";
45
    protected string $pattern = "/(\(|\[)(?!\@)(.+?=*)(\)|\])/ui";
46
47
    /**
48
     * Parse the trigger.
49
     *
50
     * @return bool|string
51
     */
52
    public function parse(string $trigger, Input $input): bool
53
    {
54
        if ($this->matchesPattern($this->pattern, $trigger) === true) {
55
            $triggerString = $trigger;
56
            $matches = $this->getMatchesFromPattern($this->pattern, $triggerString);
57
            $sets = [];
58
59
            /**
60
             * Replace every "set" in the trigger to their index number
61
             * found in the string.
62
             *
63
             * Example:
64
             *
65
             * "I (am|love) a robot. I like (my|style)"
66
             *
67
             * Will be replaced with:
68
             *
69
             * "I {0} a robot. I like {1}"
70
             */
71
            foreach ($matches as $index => $match) {
0 ignored issues
show
Bug introduced by
The expression $matches of type false is not traversable.
Loading history...
72
                $set = explode("|", $match[2]);
73
74
                if (count($set) > 0) {
75
                    $triggerString = str_replace($match[0], "{{$index}}", $triggerString);
76
                    $sets [] = $set;
77
                }
78
            }
79
80
            $combinations = $this->getCombinations(...$sets);
81
82
            if (count($combinations) > 0) {
83
                $sentences = [];
84
85
                foreach ($combinations as $combination) {
86
                    $tmp = $triggerString;
87
                    foreach ($combination as $index => $string) {
88
                        $tmp = str_replace("{{$index}}", $string, $tmp);
89
                    }
90
91
                    $sentences [] = $tmp;
92
                }
93
94
                $result = array_filter($sentences, static function (string $sentence) use ($input) {
95
                    return (strtolower($sentence) === strtolower($input->source()));
96
                });
97
98
                if (count($result) > 0) {
99
                    return $input->source();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $input->source() returns the type string which is incompatible with the type-hinted return boolean.
Loading history...
100
                }
101
            }
102
        }
103
        return false;
104
    }
105
106
    /**
107
     * Create a set of possible combinations for given arrays.
108
     *
109
     * Note: This function is taken from stackoverflow.com
110
     * first posted by Guilhermo Luna and later edited by user Amlette.
111
     *
112
     * @see https://stackoverflow.com/questions/8567082/how-to-generate-in-php-all-combinations-of-items-in-multiple-arrays/33259643#33259643
113
     *
114
     * @param array ...$arrays A set of arrays to combine.
115
     *
116
     * @return array|array[]
117
     *
118
     */
119
    private function getCombinations(array ...$arrays): array
120
    {
121
        $result = [[]];
122
        foreach ($arrays as $property => $property_values) {
123
            $tmp = [];
124
            foreach ($result as $result_item) {
125
                foreach ($property_values as $property_value) {
126
                    $tmp[] = array_merge($result_item, [$property => $property_value]);
127
                }
128
            }
129
            $result = $tmp;
130
        }
131
        return $result;
132
    }
133
}
134