Ich bin jetzt schon seit längerem ein großer Fan von Symfony 2 und verwende Doctrine als ORM. Das klappt alles super, manchmal muss man sich aber in die Grenzgebiete wagen.
Im vorliegenden Fall ging es um Statistikwerte in einer Tabelle. Im wesentlichen besteht die Tabelle (neben einer ID) noch aus einem Timestamp und um einen Wert, der im aktuelle Fall immer zwischen 1 und 3 liegt und eine Bewertung darstellt. Die Tabelle selbst wird auch in einer Entität abgebildet folgende einfache Query sollte aber nun umgesetzt werden:
SELECT DATE(created_at), rating, COUNT(rating)
FROM ratings
GROUP BY DATE(created_at), rating
ORDER BY DATE(created_at) ASC, rating ASC;
Damit wollte ich also eine Zeitreihe erhalten, die neben dem Datum noch enthält, wie häufig die entsprechende Bewertung an dem Tag vorkam.
Hierzu musste ich auf die NativeQuery von Doctrine zurückgreifen. Die Ergebnisse werden aber trotzdem von Doctrine verwaltet und verlangen ein ResultSetMapping, damit Doctrine weiß, wie die Ergebnisdaten umgesetzt werden sollen. Damit lässt sich zum Beispiel bewerkstelligen, dass Doctrine automatisch passende Objekte zurückgibt, die die Daten enthalten.
In meinem Fall wollte ich aber nur die nackten Zahlen haben, da ich die Werte zur späteren Visualisierung in JS eh noch einmal umschreiben muss. Den Code habe ich in einem EntityRepository gekapselt, wer einen ähnlichen Code in einem Service oder einer Controller-Action verwenden will, muss sich ggf. anderweitig den EntityManager besorgen. So sieht der Code aus:
$rsm = new \Doctrine\ORM\Query\ResultSetMapping();
$rsm->addEntityResult('CfMainBundle:Rating', 'r');
$rsm->addScalarResult('dateCreatedAt', 'date');
$rsm->addScalarResult('rating', 'rating');
$rsm->addScalarResult('countRating', 'count');
$data = $this->getEntityManager()
->createNativeQuery(
'SELECT DATE(r.created_at) AS dateCreatedAt, r.rating, COUNT(r.rating) AS countRating
FROM ratings r
GROUP BY DATE(r.created_at), r.rating
ORDER BY DATE(r.created_at) ASC, rating ASC',
$rsm
)
->getResult();
Das Ergebnisarray sieht so aus:
Array
(
[0] => Array
(
[date] => 2013-01-05
[rating] => 1
[count] => 8
)
[1] => Array
(
[date] => 2013-01-05
[rating] => 2
[count] => 4
)
[2] => Array
(
[date] => 2013-01-05
[rating] => 3
[count] => 1
)
[3] => Array
(
[date] => 2013-01-07
[rating] => 1
[count] => 22
)
...
)
Damit kann man nun prima weiterarbeiten. Zu beachten ist, dass in der Query die Originalnamen der Spalten aus der Datenbank genutzt werden müssen und nicht die Namen der gemappten Attribute aus der Entität. Dazu gibt es auch eine Abhilfe, die in der Doctrine-Dokumentation zur NativeQuery erklärt wird.