Completed
Push — master ( aeb3a4...04afb5 )
by brian
01:57
created

Negotiator::matchClientPreferences()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4286
cc 2
eloc 4
nc 2
nop 3
crap 2
1
<?php
2
3
/**
4
 * @copyright   (c) 2006-present brian ridley
5
 * @author      brian ridley <[email protected]>
6
 * @license     http://opensource.org/licenses/MIT MIT
7
 */
8
9
namespace ptlis\ConNeg\Negotiator;
10
11
use ptlis\ConNeg\Negotiator\Matcher\AbsentMatcher;
12
use ptlis\ConNeg\Negotiator\Matcher\ExactMatcher;
13
use ptlis\ConNeg\Negotiator\Matcher\MatcherInterface;
14
use ptlis\ConNeg\Negotiator\Matcher\PartialLanguageMatcher;
15
use ptlis\ConNeg\Negotiator\Matcher\SubtypeWildcardMatcher;
16
use ptlis\ConNeg\Negotiator\Matcher\WildcardMatcher;
17
use ptlis\ConNeg\Preference\Builder\PreferenceBuilderInterface;
18
use ptlis\ConNeg\Preference\Matched\MatchedPreference;
19
use ptlis\ConNeg\Preference\Matched\MatchedPreferenceComparator;
20
use ptlis\ConNeg\Preference\Matched\MatchedPreferenceInterface;
21
use ptlis\ConNeg\Preference\Matched\MatchedPreferenceSort;
22
use ptlis\ConNeg\Preference\PreferenceInterface;
23
24
/**
25
 * Negotiator for Accept-Charset, Accept-Encoding & Accept-Language fields.
26
 */
27
class Negotiator implements NegotiatorInterface
0 ignored issues
show
Complexity introduced by
The class Negotiator has a coupling between objects value of 14. Consider to reduce the number of dependencies under 13.
Loading history...
28
{
29
    /**
30
     * @var PreferenceBuilderInterface
31
     */
32
    private $prefBuilder;
33
34
    /**
35
     * @var PreferenceBuilderInterface
36
     */
37
    private $mimePrefBuilder;
38
39
    /**
40
     * @var MatcherInterface[]
41
     */
42
    private $matcherList;
43
44
45
    /**
46
     * Constructor.
47
     *
48
     * @param PreferenceBuilderInterface $prefBuilder
49
     * @param PreferenceBuilderInterface $mimePrefBuilder
50
     * @param MatcherInterface[] $matcherList Objects implementing MatcherInterface, matching is attempted in the order
51
     *      of the matcher objects in the array. When a match is found no further match tests are done and the testing
52
     *      loop will exit.
53
     */
54 76
    public function __construct(
55
        PreferenceBuilderInterface $prefBuilder,
56
        PreferenceBuilderInterface $mimePrefBuilder,
57
        array $matcherList = array()
58
    ) {
59 76
        $this->prefBuilder = $prefBuilder;
60 76
        $this->mimePrefBuilder = $mimePrefBuilder;
61
62 76
        if (!count($matcherList)) {
63
            $matcherList = array(
64 76
                new WildcardMatcher(),
65 76
                new PartialLanguageMatcher(),
66 76
                new SubtypeWildcardMatcher(),
67 76
                new ExactMatcher(new MatchedPreferenceComparator()),
68 76
                new AbsentMatcher($this->prefBuilder, $this->mimePrefBuilder)
69 76
            );
70 76
        }
71 76
        $this->matcherList = $matcherList;
72 76
    }
73
74
    /**
75
     * @inheritDoc
76
     */
77 76
    public function negotiateAll(array $clientPrefList, array $serverPrefList, $fromField)
78
    {
79 76
        $emptyPref = $this->getBuilder($fromField)
80 76
            ->setFromField($fromField)
81 76
            ->get();
82
83 76
        $sort = new MatchedPreferenceSort();
84
85 76
        $matchingList = array();
86
87 76
        foreach ($serverPrefList as $serverPref) {
88 54
            $matchingList[] = new MatchedPreference(
89 54
                $fromField,
90 54
                $emptyPref,
91
                $serverPref
92 54
            );
93 76
        }
94
95 76
        $matchingList = $this->matchClientPreferences($fromField, $clientPrefList, $matchingList);
96
97 76
        return $sort->sortDescending($matchingList);
98
    }
99
100
    /**
101
     * @inheritDoc
102
     */
103 36
    public function negotiateBest(array $clientPrefList, array $serverPrefList, $fromField)
104
    {
105 36
        $pairCollection = $this->negotiateAll($clientPrefList, $serverPrefList, $fromField);
106
107 36
        if (count($pairCollection)) {
108 32
            $best = $pairCollection[0];
109 32
        } else {
110 4
            $emptyPref = $this->getBuilder($fromField)
111 4
                ->setFromField($fromField)
112 4
                ->get();
113
114 4
            $best = new MatchedPreference($fromField, $emptyPref, $emptyPref);
115
        }
116
117 36
        return $best;
118
    }
119
120
    /**
121
     * Match client variants to server variants.
122
     *
123
     * @param string $fromField
124
     * @param PreferenceInterface[] $clientPrefList
125
     * @param MatchedPreferenceInterface[] $matchingList
126
     *
127
     * @return MatchedPreferenceInterface[]
128
     */
129 76
    private function matchClientPreferences($fromField, array $clientPrefList, array $matchingList)
130
    {
131 76
        foreach ($clientPrefList as $clientPref) {
132 54
            $matchingList = $this->matchSingleClientPreference($fromField, $clientPref, $matchingList);
133 76
        }
134
135 76
        return $matchingList;
136
    }
137
138
    /**
139
     * Match a single client variant to the server variants.
140
     *
141
     * @param string $fromField
142
     * @param PreferenceInterface $clientPreference
143
     * @param MatchedPreferenceInterface[] $matchingList
144
     *
145
     * @return MatchedPreferenceInterface[]
146
     */
147 54
    private function matchSingleClientPreference($fromField, PreferenceInterface $clientPreference, array $matchingList)
148
    {
149 54
        foreach ($this->matcherList as $matcher) {
150 54
            if ($matcher->hasMatch($fromField, $matchingList, $clientPreference)) {
151 54
                $matchingList = $matcher->match($fromField, $matchingList, $clientPreference);
152
153 54
                break;
154
            }
155 54
        }
156
157 54
        return $matchingList;
158
    }
159
160
    /**
161
     * Get a preference builder for the specified HTTP field.
162
     *
163
     * @param string $fromField
164
     *
165
     * @return PreferenceBuilderInterface
166
     */
167 76
    private function getBuilder($fromField)
168
    {
169 76
        if (PreferenceInterface::MIME === $fromField) {
170 28
            return $this->mimePrefBuilder;
171
        } else {
172 48
            return $this->prefBuilder;
173
        }
174
    }
175
}
176