CakePHP Tutorial: Epsilon-Greedy-Tests - ein Plugin erstellen
Kategorien: CakePHP, PHP, Programmieren and Tutorials
Letzte Woche habe ich auf Pixeltuner.de die Epsilon-Greedy-Methode zur Optimierung von Landingpages vorgestellt. Epsilon-Greedy-Tests sind im Grunde modifizierte A/B-Tests. In diesem Artikel möchte ich Dir zeigen, wie Du ein CakePHP-Plugin schreiben kannst. Als Beispiel erstellen wir ein CakePHP-Tutorial, mit dem wir Epsilon-Greedy-Tests durchführen können.
Obwohl ich zwar auf dem Ergebnis der letzten Artikel dieser Serie aufbaue, brauchst Du diese nicht unbedingt gelesen haben, denn das Plugin wird sich automatisch in diese und jede andere CakePHP-App einfügen. Viel wichtiger ist, dass du meinen Artikel über Epsilon-Greedy-Tests gelesen hast, damit du weißt, was ein Epsilon-Greedy-Test ist und wie er funktioniert.
Artikelserie: CakePHP-Tutorial: Web-Anwendung mit MVC
Dieser Artikel ist Teil einer mehrteiligen Artikelserie. Lies dir auch die restlichen Teile durch!
- CakePHP Tutorial: Grundfunktionen und Hallo Welt
- CakePHP Tutorial: Views, Layouts und Helpers
- CakePHP Tutorial - Model und Controller - ein Gästebuch programmieren
- CakePHP Tutorial: Admin-Routen und Login - erweitertes Gästebuch
- CakePHP Tutorial: Epsilon-Greedy-Tests - ein Plugin erstellen
Schritt 1: Datenbank-Tabelle für die Test anlegen
Als erstes legen wir in unserer Datenbank eine neue Tabelle epsilongreedy_variants
an:
Spalte | Typ |
---|---|
id | bigint(20) unsigned Auto-Inkrement |
test | varchar(100) |
key | varchar(100) |
views | bigint(20) unsigned NULL [1] |
actions | bigint(20) unsigned NULL [1] |
Schritt 2: Plugin anlegen
Als nächstes legen wir im Ordner app/Plugins
einen neuen Ordner EpsilonGreedy
an. In diesem Ordner befindet sich später unser gesamtes Plugin. In diesem Ordner müssen wir nun noch die Ordner Controller
, Model
und View
an. In diesen können wir später, wie in der regulären App, Controller, Componenten und alle anderen CakePHP-Klassen anlegen.
Im Ordner EpsilonGreedy/Model
legen wir nun die Datei EpsilonGreedyAppModel.php
an. In dieser können wir für alle Models des Plugins Einstellungen vornehmen, was wir jetzt auch tun.
<?php
class EpsilonGreedyAppModel extends AppModel
{
public $tablePrefix;
public function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
$this->tablePrefix .= 'epsilongreedy_';
}
}
?>
Hier legen wir fest, dass alle Models ihren Tabellen den Prefix »epsilongreedy_« hinzufügen. So vermeiden wir, dass wir versehentlich mit einer Tabelle der App kollidieren.
Nun legen wir noch schnell das Model für die Tabelle an, die wir eben angelegt haben.
<?php
class Variant extends EpsilonGreedyAppModel
{
}
?>
Schritt 3: EpsilonGreedyComponent
Als nächstes legen wir die Component an, die sich um die Verwaltung der Epsilon-Greedy-Tests kümmert. Dazu legen wir zuerst den Ordner EpsilonGreedy/Controller/Component
an. Hier legen wir nun die Datei EpsilonGreedyComponent.php
an.
<?php
class EpsilonGreedyComponent extends Component
{
public $tests = array();
public $explore = .1;
public function beforeRender($controller) {
$controller->helpers['EpsilonGreedy.EpsilonGreedy'] = array('explore' => $this->explore);
$this->Variant = ClassRegistry::init('EpsilonGreedy.Variant');
foreach($this->tests as $test => $variants) {
foreach($variants as $key) {
$variant = $this->Variant->find('first', array(
'conditions' => array(
'test' => $test,
'key' => $key
)
));
if($variant == null) {
$this->Variant->create();
$this->Variant->save(array('Variant' => array(
'test' => $test,
'key' => $key
)), false);
}
}
}
if(isset($controller->request->query['eg'])) {
$data = unserialize(base64_decode($controller->request->query['eg']));
$this->success($data['test'], $data['option']);
$controller->redirect(array());
}
}
public function success($test, $option) {
$this->Variant->updateAll(
array(
'actions' => 'actions+1'
),
array(
'test' => $test,
'key' => $option
)
);
}
}
?>
Die Component speichert die Varianten in der Datenbank (Zeilen 13 - 30) und sorgt dafür, dass die Erfolge der Tests gezählt werden (Zeilen 32 - 50). Außerdem läd die Component den EpsilonGreedyHelper (Zeile 9), welchen wir als nächstes anlegen.
Schritt 4: EpsilonGreedyHelper
<?php
class EpsilonGreedyHelper extends AppHelper
{
public function getOption($test) {
$this->Variant = ClassRegistry::init('EpsilonGreedy.Variant');
$clickThroughRates = array();
$variants = $this->Variant->find('all', array(
'conditions' => array(
'test' => $test
)
));
foreach($variants as $variant) {
if($variant['Variant']['views'] == 0) {
$clickThroughRates[$variant['Variant']['key']] = 0;
} else {
$clickThroughRates[$variant['Variant']['key']] = $variant['Variant']['actions'] / $variant['Variant']['views'];
}
}
if(rand(0, 100) / 100 <= $this->settings['explore']) {
$choice = array_rand($clickThroughRates);
} else {
arsort($clickThroughRates);
$best = reset($clickThroughRates);
$winners = array();
foreach($clickThroughRates as $key => $value) {
if($value >= $best) {
$winners[$key] = $value;
}
}
$choice = array_rand($winners);
}
$this->Variant->updateAll(
array(
'views' => 'views+1'
),
array(
'test' => $test,
'key' => $choice
)
);
return $choice;
}
public function linkParam($test, $choice) {
return array('eg' => base64_encode(serialize(array('test' => $test, 'option' => $choice))));
}
}
?>
Der EpsilonGreedyHelper ist für das Frontend der Tests verantwortlich. Hier finden sich die Methoden zur Auswahl einer Variante (Zeilen 5 - 50) und generiert die Link-Parameter, welche zum Zählen der Erfolge benötigt werden (Zeilen 52 - 54).
Schritt 5: Anwendung des Plugins
Das Plugin funktiniert jetzt schon, wir müssen es nur noch anwenden. Dazu laden wir es zunächst über die Datei Config/bootstrap.php
:
CakePlugin::load('EpsilonGreedy');
Nun müssen wir die Component nur noch in den AppController laden:
<?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $helpers = array('Nav');
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array('controller' => 'entries', 'action' => 'index', 'admin' => true),
'logoutRedirect' => array('controller' => 'pages', 'action' => 'display', 'home', 'admin' => false),
'loginAction' => array('controller' => 'users', 'action' => 'login', 'admin' => false),
'authError' => 'Melde dich an, um diesen Bereich zu sehen!'
),
'EpsilonGreedy.EpsilonGreedy' => array(
'tests' => array(
'landingpage' => array(
'a', 'b', 'c'
)
)
)
);
public function beforeFilter() {
if(!empty($this->params['prefix']) && $this->params['prefix'] == 'admin'){
$this->Auth->deny();
} else {
$this->Auth->allow();
}
}
}
Über das Array tests
können wir die Epsilon-Greedy-Test einrichten. Hier pflegen wir in diesem Fall einen Test mit dem Titel »landingpage« ein. Die drei Varianten heißen hier a, b und c. Hier können beliebig viele Test und Varianten eingepflegt werden.
Als letztes müssen wir nur noch den Epsilon-Greedy-Test durchführen. Das können wir sehr einfach in jedem beliebigen View durchführen:
<?php
$test = 'landingpage';
$choice = $this->EpsilonGreedy->getOption($test);
?>
<h1>Landingpage</h1>
<?php echo $this->Html->link('Variante ' . $choice, array('controller' => 'pages', 'action' => 'display', 'home', '?' => $this->EpsilonGreedy->linkParam($test, $choice))); ?>
Über die Methode getOption
können wir eine Variante auswählen. Dann fügen wir den Link mit den entsprechenden Parametern ein. Hier sollten nun natürlich verschiedene Varianten des gleichen Contents angezeigt werden, um zu prüfen, welche Variante am effektivsten ist.
Und schon haben wir ein Plugin, um Epsilon-Greedy-Test durchzuführen. Ich hoffe, dir hat das Tutorial gefallen und alles hat funktioniert. Also schreib mir einen Kommentar, ich freue mich auf Dein Feedback!