Completed
Push — master ( 3bf2c1...87b10e )
by Andre
20s queued 17s
created

SalutationMapper::substituteWithSalutation()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
cc 4
nc 4
nop 2
1
<?php
2
3
namespace TheIconic\NameParser\Mapper;
4
5
use TheIconic\NameParser\Part\AbstractPart;
6
use TheIconic\NameParser\Part\Salutation;
7
8
class SalutationMapper extends AbstractMapper
9
{
10
    protected $salutations = [];
11
12
    protected $maxIndex = 0;
13
14
    public function __construct(array $salutations, $maxIndex = 0)
15
    {
16
        $this->salutations = $salutations;
17
        $this->maxIndex = $maxIndex;
18
    }
19
20
    /**
21
     * map salutations in the parts array
22
     *
23
     * @param array $parts the name parts
24
     * @return array the mapped parts
25
     */
26
    public function map(array $parts): array
27
    {
28
        $max = ($this->maxIndex > 0) ? $this->maxIndex : floor(count($parts) / 2);
29
30
        for ($k = 0; $k < $max; $k++) {
31
            if ($parts[$k] instanceof AbstractPart) {
32
                break;
33
            }
34
35
            $parts = $this->substituteWithSalutation($parts, $k);
36
        }
37
38
        return $parts;
39
    }
40
41
    /**
42
     * We pass the full parts array and the current position to allow
43
     * not only single-word matches but also combined matches with
44
     * subsequent words (parts).
45
     *
46
     * @param array $parts
47
     * @param int $start
48
     * @return array
49
     */
50
    protected function substituteWithSalutation(array $parts, int $start): array
51
    {
52
        if ($this->isSalutation($parts[$start])) {
53
            $parts[$start] = new Salutation($parts[$start], $this->salutations[$this->getKey($parts[$start])]);
54
            return $parts;
55
        }
56
57
        foreach ($this->salutations as $key => $salutation) {
58
            $keys = explode(' ', $key);
59
            $length = count($keys);
60
61
            $subset = array_slice($parts, $start, $length);
62
63
            if ($this->isMatchingSubset($keys, $subset)) {
64
                array_splice($parts, $start, $length, [new Salutation(implode(' ', $subset), $salutation)]);
65
                return $parts;
66
            }
67
        }
68
69
        return $parts;
70
    }
71
72
    /**
73
     * check if the given subset matches the given keys entry by entry,
74
     * which means word by word, except that we first need to key-ify
75
     * the subset words
76
     *
77
     * @param array $keys
78
     * @param array $subset
79
     * @return bool
80
     */
81
    private function isMatchingSubset(array $keys, array $subset): bool
82
    {
83
        for ($i = 0; $i < count($subset); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
84
            if ($this->getKey($subset[$i]) !== $keys[$i]) {
85
                return false;
86
            }
87
        }
88
89
        return true;
90
    }
91
92
    /**
93
     * check if the given word is a viable salutation
94
     *
95
     * @param string $word the word to check
96
     * @return bool
97
     */
98
    protected function isSalutation($word): bool
99
    {
100
        return (array_key_exists($this->getKey($word), $this->salutations));
101
    }
102
}
103