Completed
Pull Request — master (#24)
by
unknown
26:22 queued 11:24
created

AbTesting::getCompletedGoals()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 3
cts 4
cp 0.75
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2.0625
1
<?php
2
3
namespace Ben182\AbTesting;
4
5
use Ben182\AbTesting\Models\Goal;
6
use Illuminate\Support\Collection;
7
use Ben182\AbTesting\Models\Experiment;
8
use Jaybizzle\CrawlerDetect\CrawlerDetect;
9
use Ben182\AbTesting\Exceptions\InvalidConfiguration;
10
11
class AbTesting
12
{
13
    protected $experiments;
14
15
    const SESSION_KEY_EXPERIMENT = 'ab_testing_experiment';
16
    const SESSION_KEY_GOALS = 'ab_testing_goals';
17
18
    public function __construct()
19 51
    {
20
        $this->experiments = new Collection;
21 51
    }
22 51
23
    /**
24
     * Validates the config items and puts them into models.
25
     *
26
     * @return void
27
     */
28
    protected function start()
29 51
    {
30
        $configExperiments = config('ab-testing.experiments');
31 51
        $configGoals = config('ab-testing.goals');
32 51
33
        if (! count($configExperiments)) {
34 51
            throw InvalidConfiguration::noExperiment();
35 3
        }
36
37
        if (count($configExperiments) !== count(array_unique($configExperiments))) {
38 48
            throw InvalidConfiguration::experiment();
39 3
        }
40
41
        if (count($configGoals) !== count(array_unique($configGoals))) {
42 45
            throw InvalidConfiguration::goal();
43 3
        }
44
45
        foreach ($configExperiments as $configExperiment) {
46 42
            $this->experiments[] = $experiment = Experiment::firstOrCreate([
47 42
                'name' => $configExperiment,
48 42
            ], [
49
                'visitors' => 0,
50 42
            ]);
51
52
            foreach ($configGoals as $configGoal) {
53 42
                $experiment->goals()->firstOrCreate([
54 42
                    'name' => $configGoal,
55 42
                ], [
56
                    'hit' => 0,
57 42
                ]);
58
            }
59
        }
60
61
        session([
62 42
            self::SESSION_KEY_GOALS => new Collection,
63 42
        ]);
64
    }
65 42
66
    /**
67
     * Triggers a new visitor. Picks a new experiment and saves it to the session.
68
     *
69
     * @return \Ben182\AbTesting\Models\Experiment|void
70
     */
71
    public function pageView()
72 51
    {
73
        if (session(self::SESSION_KEY_EXPERIMENT)) {
74 51
            return;
75 51
        }
76 42
77
        $this->start();
78 42
        $this->setNextExperiment();
79
80 42
        return $this->getExperiment();
81
    }
82 9
83
    /**
84
     * Calculates a new experiment and sets it to the session.
85
     *
86
     * @return void
87
     */
88
    protected function setNextExperiment()
89 42
    {
90
        $next = $this->getNextExperiment();
91 42
        $next->visit();
92 42
93
        session([
94 42
            self::SESSION_KEY_EXPERIMENT => $next,
95 42
        ]);
96
    }
97 42
98
    /**
99
     * Calculates a new experiment.
100
     *
101
     * @return \Ben182\AbTesting\Models\Experiment|null
102
     */
103
    protected function getNextExperiment()
104 42
    {
105
        $sorted = $this->experiments->sortBy('visitors');
106 42
107
        return $sorted->first();
108 42
    }
109
110
    /**
111
     * Checks if the currently active experiment is the given one.
112
     *
113
     * @param string $name The experiments name
114
     *
115
     * @return bool
116
     */
117
    public function isExperiment(string $name)
118 9
    {
119
        $this->pageView();
120 9
121
        return $this->getExperiment()->name === $name;
122 9
    }
123
124
    /**
125
     * Completes a goal by incrementing the hit property of the model and setting its ID in the session.
126
     *
127
     * @param string $goal The goals name
128
     *
129
     * @return \Ben182\AbTesting\Models\Goal|false
130
     */
131
    public function completeGoal(string $goal)
132 15
    {
133
        if (! $this->getExperiment()) {
134 15
            $this->pageView();
135 12
        }
136
137
        $goal = $this->getExperiment()->goals->where('name', $goal)->first();
138 15
139
        if (! $goal) {
140 15
            return false;
141 3
        }
142
143
        if (session(self::SESSION_KEY_GOALS)->contains($goal->id)) {
144 12
            return false;
145 3
        }
146
147
        session(self::SESSION_KEY_GOALS)->push($goal->id);
148 12
149
        $goal->complete();
150 12
151 12
        return $goal;
152
    }
153 12
154
    /**
155
     * Returns the currently active experiment.
156
     *
157
     * @return \Ben182\AbTesting\Models\Experiment|null
158
     */
159
    public function getExperiment()
160
    {
161 42
        return session(self::SESSION_KEY_EXPERIMENT);
162
    }
163 42
164
    /**
165
     * Returns all the completed goals.
166
     *
167
     * @return \Illuminate\Support\Collection|false
168
     */
169
    public function getCompletedGoals()
170
    {
171 3
        if (! session(self::SESSION_KEY_GOALS)) {
172
            return false;
173 3
        }
174
175
        return session(self::SESSION_KEY_GOALS)->map(function ($goalId) {
176
            return Goal::find($goalId);
177
        });
178 3
    }
179 3
180
    /**
181
     * Check if the current request is from a crawler or bot and config option is enabled.
182
     *
183
     * @return bool
184
     */
185
    public function isCrawler()
186
    {
187
        return config('ab-testing.ignore_crawlers')
188
            && (new CrawlerDetect)->isCrawler();
189
    }
190
}
191