1 | <?php |
||
2 | |||
3 | /* |
||
4 | * @copyright 2019 Mautic Contributors. All rights reserved |
||
5 | * @author Mautic |
||
6 | * |
||
7 | * @link http://mautic.org |
||
8 | * |
||
9 | * @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html |
||
10 | */ |
||
11 | |||
12 | namespace Mautic\PageBundle\EventListener; |
||
13 | |||
14 | use Mautic\CoreBundle\Event\DetermineWinnerEvent; |
||
15 | use Mautic\PageBundle\Entity\HitRepository; |
||
16 | use Mautic\PageBundle\PageEvents; |
||
17 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
||
18 | use Symfony\Component\Translation\TranslatorInterface; |
||
19 | |||
20 | class DetermineWinnerSubscriber implements EventSubscriberInterface |
||
21 | { |
||
22 | /** |
||
23 | * @var HitRepository |
||
24 | */ |
||
25 | private $hitRepository; |
||
26 | |||
27 | /** |
||
28 | * @var TranslatorInterface |
||
29 | */ |
||
30 | private $translator; |
||
31 | |||
32 | public function __construct(HitRepository $hitRepository, TranslatorInterface $translator) |
||
33 | { |
||
34 | $this->hitRepository = $hitRepository; |
||
35 | $this->translator = $translator; |
||
36 | } |
||
37 | |||
38 | /** |
||
39 | * @return array |
||
40 | */ |
||
41 | public static function getSubscribedEvents() |
||
42 | { |
||
43 | return [ |
||
44 | PageEvents::ON_DETERMINE_BOUNCE_RATE_WINNER => ['onDetermineBounceRateWinner', 0], |
||
45 | PageEvents::ON_DETERMINE_DWELL_TIME_WINNER => ['onDetermineDwellTimeWinner', 0], |
||
46 | ]; |
||
47 | } |
||
48 | |||
49 | /** |
||
50 | * Determines the winner of A/B test based on bounce rates. |
||
51 | */ |
||
52 | public function onDetermineBounceRateWinner(DetermineWinnerEvent $event) |
||
53 | { |
||
54 | //find the hits that did not go any further |
||
55 | $parent = $event->getParameters()['parent']; |
||
56 | $children = $event->getParameters()['children']; |
||
57 | $pageIds = $parent->getRelatedEntityIds(); |
||
58 | $startDate = $parent->getVariantStartDate(); |
||
59 | |||
60 | if (null != $startDate && !empty($pageIds)) { |
||
61 | //get their bounce rates |
||
62 | $counts = $this->hitRepository->getBounces($pageIds, $startDate, true); |
||
63 | if ($counts) { |
||
64 | // Group by translation |
||
65 | $combined = [ |
||
66 | $parent->getId() => $counts[$parent->getId()], |
||
67 | ]; |
||
68 | |||
69 | if ($parent->hasTranslations()) { |
||
70 | $translations = $parent->getTranslationChildren()->getKeys(); |
||
71 | |||
72 | foreach ($translations as $translation) { |
||
73 | $combined[$parent->getId()]['bounces'] += $counts[$translation]['bounces']; |
||
74 | $combined[$parent->getId()]['totalHits'] += $counts[$translation]['totalHits']; |
||
75 | $combined[$parent->getId()]['rate'] = ($combined[$parent->getId()]['totalHits']) ? round( |
||
76 | ($combined[$parent->getId()]['bounces'] / $combined[$parent->getId()]['totalHits']) * 100, |
||
77 | 2 |
||
78 | ) : 0; |
||
79 | } |
||
80 | } |
||
81 | |||
82 | foreach ($children as $child) { |
||
83 | $combined[$child->getId()] = $counts[$child->getId()]; |
||
84 | |||
85 | if ($child->hasTranslations()) { |
||
86 | $translations = $child->getTranslationChildren()->getKeys(); |
||
87 | foreach ($translations as $translation) { |
||
88 | $combined[$child->getId()]['bounces'] += $counts[$translation]['bounces']; |
||
89 | $combined[$child->getId()]['totalHits'] += $counts[$translation]['totalHits']; |
||
90 | $combined[$child->getId()]['rate'] = ($combined[$child->getId()]['totalHits']) ? round( |
||
91 | ($combined[$child->getId()]['bounces'] / $combined[$child->getId()]['totalHits']) * 100, |
||
92 | 2 |
||
93 | ) : 0; |
||
94 | } |
||
95 | } |
||
96 | } |
||
97 | unset($counts); |
||
98 | |||
99 | //let's arrange by rate |
||
100 | $rates = []; |
||
101 | $support['data'] = []; |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Loading history...
|
|||
102 | $support['labels'] = []; |
||
103 | $bounceLabel = $this->translator->trans('mautic.page.abtest.label.bounces'); |
||
104 | |||
105 | foreach ($combined as $pid => $stats) { |
||
106 | $rates[$pid] = $stats['rate']; |
||
107 | $support['data'][$bounceLabel][] = $rates[$pid]; |
||
108 | $support['labels'][] = $pid.':'.$stats['title']; |
||
109 | } |
||
110 | |||
111 | // investigate the rate calculation, seems that lowest value should be the winner |
||
112 | $max = max($rates); |
||
113 | $support['step_width'] = (ceil($max / 10) * 10); |
||
114 | |||
115 | $winners = ($max > 0) ? array_keys($rates, $max) : []; |
||
116 | |||
117 | $event->setAbTestResults([ |
||
118 | 'winners' => $winners, |
||
119 | 'support' => $support, |
||
120 | 'basedOn' => 'page.bouncerate', |
||
121 | 'supportTemplate' => 'MauticPageBundle:SubscribedEvents\AbTest:bargraph.html.php', |
||
122 | ]); |
||
123 | |||
124 | return; |
||
125 | } |
||
126 | } |
||
127 | |||
128 | $event->setAbTestResults([ |
||
129 | 'winners' => [], |
||
130 | 'support' => [], |
||
131 | 'basedOn' => 'page.bouncerate', |
||
132 | ]); |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Determines the winner of A/B test based on dwell time rates. |
||
137 | */ |
||
138 | public function onDetermineDwellTimeWinner(DetermineWinnerEvent $event) |
||
139 | { |
||
140 | //find the hits that did not go any further |
||
141 | $parent = $event->getParameters()['parent']; |
||
142 | $pageIds = $parent->getRelatedEntityIds(); |
||
143 | $startDate = $parent->getVariantStartDate(); |
||
144 | |||
145 | if (null != $startDate && !empty($pageIds)) { |
||
146 | //get their bounce rates |
||
147 | $counts = $this->hitRepository->getDwellTimesForPages($pageIds, ['fromDate' => $startDate]); |
||
148 | $support = []; |
||
149 | |||
150 | if ($counts) { |
||
151 | //in order to get a fair grade, we have to compare the averages here since a page that is only shown |
||
152 | //25% of the time will have a significantly lower sum than a page shown 75% of the time |
||
153 | $avgs = []; |
||
154 | $support['data'] = []; |
||
155 | $support['labels'] = []; |
||
156 | foreach ($counts as $pid => $stats) { |
||
157 | $avgs[$pid] = $stats['average']; |
||
158 | $support['data'][$this->translator->trans('mautic.page.abtest.label.dewlltime.average')][] = $stats['average']; |
||
159 | $support['labels'][] = $pid.':'.$stats['title']; |
||
160 | } |
||
161 | |||
162 | //set max for scales |
||
163 | $max = max($avgs); |
||
164 | $support['step_width'] = (ceil($max / 10) * 10); |
||
165 | |||
166 | //get the page ids with the greatest average dwell time |
||
167 | $winners = ($max > 0) ? array_keys($avgs, $max) : []; |
||
168 | |||
169 | $event->setAbTestResults([ |
||
170 | 'winners' => $winners, |
||
171 | 'support' => $support, |
||
172 | 'basedOn' => 'page.dwelltime', |
||
173 | 'supportTemplate' => 'MauticPageBundle:SubscribedEvents\AbTest:bargraph.html.php', |
||
174 | ]); |
||
175 | |||
176 | return; |
||
177 | } |
||
178 | } |
||
179 | |||
180 | $event->setAbTestResults([ |
||
181 | 'winners' => [], |
||
182 | 'support' => [], |
||
183 | 'basedOn' => 'page.dwelltime', |
||
184 | ]); |
||
185 | } |
||
186 | } |
||
187 |