--- /dev/null
+<?php declare(strict_types=1);
+
+/*
+ * This file is part of the Rapsys AirBundle package.
+ *
+ * (c) Raphaël Gertz <symfony@rapsys.eu>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Rapsys\AirBundle\Repository;
+
+use Doctrine\ORM\AbstractQuery;
+use Doctrine\ORM\Query\ResultSetMapping;
+
+use Rapsys\AirBundle\Repository;
+
+/**
+ * GoogleTokenRepository
+ */
+class GoogleTokenRepository extends Repository {
+ /**
+ * Find google tokens indexed by id
+ *
+ * @return array The google tokens array
+ */
+ public function findAllIndexed(): array {
+ //Set the request
+ $req = <<<SQL
+SELECT
+ t.id AS tid,
+ t.mail AS gmail,
+ t.user_id AS uid,
+ t.access,
+ t.refresh,
+ t.expired,
+ GROUP_CONCAT(c.id ORDER BY c.id SEPARATOR "\\n") AS cids,
+ GROUP_CONCAT(c.mail ORDER BY c.id SEPARATOR "\\n") AS cmails,
+ GROUP_CONCAT(c.summary ORDER BY c.id SEPARATOR "\\n") AS csummaries,
+ GROUP_CONCAT(IFNULL(c.synchronized, 'NULL') ORDER BY c.id SEPARATOR "\\n") AS csynchronizeds
+FROM RapsysAirBundle:GoogleToken AS t
+JOIN RapsysAirBundle:GoogleCalendar AS c ON (c.google_token_id = t.id)
+GROUP BY t.id
+ORDER BY NULL
+SQL;
+
+ //Replace bundle entity name by table name
+ $req = str_replace($this->tableKeys, $this->tableValues, $req);
+
+ //Get result set mapping instance
+ //XXX: DEBUG: see ../blog.orig/src/Rapsys/BlogBundle/Repository/ArticleRepository.php
+ $rsm = new ResultSetMapping();
+
+ //Declare all fields
+ //XXX: see vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/Types.php
+ //addScalarResult($sqlColName, $resColName, $type = 'string');
+ $rsm
+ ->addScalarResult('tid', 'tid', 'integer')
+ ->addScalarResult('gmail', 'gmail', 'string')
+ ->addScalarResult('uid', 'uid', 'integer')
+ ->addScalarResult('access', 'access', 'string')
+ ->addScalarResult('refresh', 'refresh', 'string')
+ ->addScalarResult('expired', 'expired', 'datetime')
+ ->addScalarResult('cids', 'cids', 'string')
+ ->addScalarResult('cmails', 'cmails', 'string')
+ ->addScalarResult('csummaries', 'csummaries', 'string')
+ ->addScalarResult('csynchronizeds', 'csynchronizeds', 'string')
+ ->addIndexByScalar('tid');
+
+ //Set result array
+ $result = [];
+
+ //Get tokens
+ $tokens = $this->_em
+ ->createNativeQuery($req, $rsm)
+ ->getArrayResult();
+
+ //Iterate on tokens
+ foreach($tokens as $tid => $token) {
+ //Set cids
+ $cids = explode("\n", $token['cids']);
+
+ //Set cmails
+ $cmails = explode("\n", $token['cmails']);
+
+ //Set csummaries
+ $csummaries = explode("\n", $token['csummaries']);
+
+ //Set csynchronizeds
+ $csynchronizeds = array_map(function($v){return new \DateTime($v);}, explode("\n", $token['csynchronizeds']));
+
+ //Set result
+ $result[$tid] = [
+ 'id' => $tid,
+ 'mail' => $token['gmail'],
+ 'uid' => $token['uid'],
+ 'access' => $token['access'],
+ 'refresh' => $token['refresh'],
+ 'expired' => $token['expired'],
+ 'calendars' => []
+ ];
+
+ //Iterate on
+ foreach($cids as $k => $cid) {
+ $result[$tid]['calendars'][$cid] = [
+ 'id' => $cid,
+ 'mail' => $cmails[$k],
+ 'summary' => $csummaries[$k],
+ 'synchronized' => $csynchronizeds[$k]
+ ];
+ }
+ }
+
+ //Return result
+ return $result;
+ }
+}