From: Raphaël Gertz <git@rapsys.eu>
Date: Fri, 10 Nov 2023 12:11:40 +0000 (+0100)
Subject: Strict types
X-Git-Tag: 0.1~18
X-Git-Url: https://git.rapsys.eu/blogbundle/commitdiff_plain/ed28648958cc334b451590c91a74dd6c0784c1fe

Strict types
Remove old member functions
Inherit entity repository
Add find count, articles and article member functions
---

diff --git a/Repository/ArticleRepository.php b/Repository/ArticleRepository.php
index 9dd1556..0d5a069 100644
--- a/Repository/ArticleRepository.php
+++ b/Repository/ArticleRepository.php
@@ -1,101 +1,294 @@
-<?php
+<?php declare(strict_types=1);
+
+/*
+ * This file is part of the Rapsys BlogBundle 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\BlogBundle\Repository;
 
+use Doctrine\ORM\Query\ResultSetMapping;
+
 /**
  * ArticleRepository
  *
  * This class was generated by the Doctrine ORM. Add your own custom
  * repository methods below.
  */
-class ArticleRepository extends \Doctrine\ORM\EntityRepository {
+class ArticleRepository extends EntityRepository {
 	/**
-	 * Find article
+	 * Find article count as int
 	 *
-	 * @param string $_locale
-	 * @param string $_article
+	 * @return integer The articles count
 	 */
-	public function findArticle($_locale, $_article) {
-#		//TODO: voir comment faire ça sans gros hack sql ?
-#		//Declare all field
-#		$rsm = new \Doctrine\ORM\Query\ResultSetMapping();
-#		$rsm->addScalarResult('id', 'id');
-#		$rsm->addScalarResult('created', 'created');
-#		$rsm->addScalarResult('updated', 'updated');
-#		$rsm->addScalarResult('slug', 'slug');
-#		$rsm->addScalarResult('title', 'title');
-#		$rsm->addScalarResult('description', 'description');
-#		$rsm->addScalarResult('body', 'body');
-#		$rsm->addScalarResult('keywords', 'keywords');
-#		$rsm->addScalarResult('slugs', 'slugs');
-#
-#		//Fetch article
-#		$ret = $this->getEntityManager()
-#			#->createQuery('SELECT b.*, JSON(bl.iso6391, bat.slug) AS slugs FROM (SELECT a.id, a.created, a.updated, at.slug, at.title, at.description, at.body, JSON(kt.slug, kt.title) AS keywords FROM RapsysBlogBundle:Article a JOIN RapsysBlogBundle:ArticleTranslation at WITH (at.article_id = a.id AND at.slug = :_article) JOIN RapsysBlogBundle:Language AS l WITH (l.id = at.language_id AND l.iso6391 = :_locale) LEFT JOIN RapsysBlogBundle:ArticleKeyword ak WITH (ak.article_id = a.id) LEFT JOIN RapsysBlogBundle:KeywordTranslation kt WITH (kt.keyword_id = ak.keyword_id AND kt.language_id = at.language_id) GROUP BY a.id) b LEFT JOIN RapsysBlogBundle:Language AS bl WITH (bl.iso6391 <> :_locale) LEFT JOIN RapsysBlogBundle:ArticleTranslation bat WITH (bat.language_id = bl.id AND bat.article_id = b.id) GROUP BY b.id')
-#			->createNativeQuery('SELECT b.*, CONCAT(\'{\', GROUP_CONCAT(CONCAT(\'"\', REPLACE(bl.iso6391, \'"\', \'\\\\"\'), \'": "\', REPLACE(bat.slug, \'"\', \'\\\\"\'), \'"\')), \'}\') AS slugs FROM (SELECT a.id, a.created, a.updated, at.slug, at.title, at.description, at.body, CONCAT(\'{\', GROUP_CONCAT(CONCAT(\'"\', REPLACE(kt.slug, \'"\', \'\\\\"\'), \'": "\', REPLACE(kt.title, \'"\', \'\\\\"\'), \'"\')), \'}\') AS keywords FROM articles a JOIN articles_translations at ON (at.article_id = a.id AND at.slug = ?) JOIN languages AS l ON (l.id = at.language_id AND l.iso6391 = ?) LEFT JOIN articles_keywords ak ON (ak.article_id = a.id) LEFT JOIN keywords_translations kt ON (kt.keyword_id = ak.keyword_id AND kt.language_id = at.language_id) GROUP BY a.id) b LEFT JOIN languages AS bl ON (bl.iso6391 <> ?) LEFT JOIN articles_translations bat ON (bat.language_id = bl.id AND bat.article_id = b.id) GROUP BY b.id', $rsm)
-#			->setParameter(0, $_article)
-#			->setParameter(1, $_locale)
-#			->setParameter(2, $_locale)
-#			->getSingleResult();
-#		//Decode json
-#		if (!empty($ret['keywords'])) {
-#			$ret['keywords'] = json_decode($ret['keywords'], true);
-#		}
-#		if (!empty($ret['slugs'])) {
-#			$ret['slugs'] = json_decode($ret['slugs'], true);
-#		}
-#		//Send result
-#		return $ret;
-#
-		//Fetch article
-		$ret = $this->getEntityManager()
-			#->createQuery('SELECT b.*, JSON(bl.iso6391, bat.slug) AS slugs FROM (SELECT a.id, a.created, a.updated, at.slug, at.title, at.description, at.body, JSON(kt.slug, kt.title) AS keywords FROM RapsysBlogBundle:Article a JOIN RapsysBlogBundle:ArticleTranslation at WITH (at.article_id = a.id AND at.slug = :_article) JOIN RapsysBlogBundle:Language AS l WITH (l.id = at.language_id AND l.iso6391 = :_locale) LEFT JOIN RapsysBlogBundle:ArticleKeyword ak WITH (ak.article_id = a.id) LEFT JOIN RapsysBlogBundle:KeywordTranslation kt WITH (kt.keyword_id = ak.keyword_id AND kt.language_id = at.language_id) GROUP BY a.id) b LEFT JOIN RapsysBlogBundle:Language AS bl WITH (bl.iso6391 <> :_locale) LEFT JOIN RapsysBlogBundle:ArticleTranslation bat WITH (bat.language_id = bl.id AND bat.article_id = b.id) GROUP BY b.id')
-			->createQuery('SELECT a.id, a.created, a.updated, at.slug, at.title, at.description, at.body, JSON(kt.slug, kt.title) AS keywords FROM RapsysBlogBundle:Article a JOIN RapsysBlogBundle:ArticleTranslation at WITH (at.article_id = a.id AND at.slug = :_article) JOIN RapsysBlogBundle:Language AS l WITH (l.id = at.language_id AND l.iso6391 = :_locale) LEFT JOIN RapsysBlogBundle:ArticleKeyword ak WITH (ak.article_id = a.id) LEFT JOIN RapsysBlogBundle:KeywordTranslation kt WITH (kt.keyword_id = ak.keyword_id AND kt.language_id = at.language_id) GROUP BY a.id')
-			->setParameter('_locale', $_locale)
-			->setParameter('_article', $_article)
-			->getSingleResult();
-
-		//Decode json
-		if (!empty($ret['keywords'])) {
-			$ret['keywords'] = json_decode($ret['keywords'], true);
-		}
+	public function findCountAsInt(): int {
+		//Set the request
+		$req = <<<SQL
+SELECT COUNT(at.article_id) AS count
+FROM RapsysBlogBundle:ArticleTranslation AS at
+WHERE at.locale = :locale
+SQL;
 
-		//Fetch article's slugs in other locale
-		$slugs = $this->getEntityManager()
-			->createQuery('SELECT JSON(bl.iso6391, bat.slug) AS slugs FROM RapsysBlogBundle:Language bl LEFT JOIN RapsysBlogBundle:ArticleTranslation bat WITH (bat.article_id = :_article AND bat.language_id = bl.id) WHERE (bl.iso6391 <> :_locale) GROUP BY bat.article_id')
-			->setParameter('_locale', $_locale)
-			->setParameter('_article', $ret['id'])
-			->getSingleResult();
+		//Get result set mapping instance
+		$req = $this->replace($req);
 
-		//Decode json
-		if (!empty($slugs['slugs'])) {
-			$ret['slugs'] = json_decode($slugs['slugs'], true);
-		}
+		//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('count', 'count', 'integer');
 
-		//Send result
-		return $ret;
+		//Get result
+		return $this->_em
+			->createNativeQuery($req, $rsm)
+			->getSingleScalarResult();
 	}
 
 	/**
-	 * Find articles
+	 * Find articles as array
 	 *
-	 * @param string $_locale
+	 * @param integer $page The page
+	 * @param integer $count The count
+	 * @return array The articles array
 	 */
-	public function findArticles($_locale) {
-		//Fetch articles
-		$ret = $this->getEntityManager()
-                        ->createQuery('SELECT a.id, a.created, a.updated, at.slug, at.title, at.description, JSON(kt.slug, kt.title) AS keywords FROM RapsysBlogBundle:Article a JOIN RapsysBlogBundle:ArticleTranslation at WITH (at.article_id = a.id) JOIN RapsysBlogBundle:Language AS l WITH (l.id = at.language_id AND l.iso6391 = :_locale) LEFT JOIN RapsysBlogBundle:ArticleKeyword ak WITH (ak.article_id = a.id) LEFT JOIN RapsysBlogBundle:KeywordTranslation kt WITH (kt.keyword_id = ak.keyword_id AND kt.language_id = at.language_id) GROUP BY a.id')
-                        ->setParameter('_locale', $_locale)
-			->execute();
-		//Decode json
-		if (!empty($ret)) {
-			foreach ($ret as $id => $article) {
-				if (!empty($article['keywords'])) {
-					$ret[$id]['keywords'] = json_decode($article['keywords'], true);
-				}
+	public function findAllAsArray(int $page, int $count): array {
+		//Set the request
+		$req = <<<SQL
+SELECT
+	a.id,
+	GREATEST(a.created, at.created, k.created, kt.created) AS created,
+	GREATEST(a.updated, at.updated, k.updated, kt.updated) AS updated,
+	GREATEST(a.created, at.created, k.created, kt.created, a.updated, at.updated, k.updated, kt.updated) as modified,
+	at.body,
+	at.description,
+	at.slug,
+	at.title,
+	GROUP_CONCAT(k.id ORDER BY k.id SEPARATOR "\\n") AS k_ids,
+	GROUP_CONCAT(kt.slug ORDER BY k.id SEPARATOR "\\n") AS k_slugs,
+	GROUP_CONCAT(kt.title ORDER BY k.id SEPARATOR "\\n") AS k_titles
+FROM RapsysBlogBundle:Article AS a
+JOIN RapsysBlogBundle:ArticleTranslation AS at ON (at.article_id = a.id AND at.locale = :locale)
+LEFT JOIN RapsysBlogBundle:ArticleKeyword AS ak ON (ak.article_id = a.id)
+LEFT JOIN RapsysBlogBundle:Keyword AS k ON (k.id = ak.keyword_id)
+LEFT JOIN RapsysBlogBundle:KeywordTranslation AS kt ON (kt.keyword_id = k.id AND kt.locale = :locale)
+GROUP BY a.id
+ORDER BY updated, created DESC
+LIMIT :offset, :count
+SQL;
+
+		//Replace bundle entity name by table name
+		$req = $this->replace($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('id', 'id', 'integer')
+			->addScalarResult('body', 'body', 'string')
+			->addScalarResult('description', 'description', 'string')
+			->addScalarResult('slug', 'slug', 'string')
+			->addScalarResult('title', 'title', 'string')
+			->addScalarResult('k_ids', 'k_ids', 'string')
+			->addScalarResult('k_slugs', 'k_slugs', 'string')
+			->addScalarResult('k_titles', 'k_titles', 'string')
+			->addScalarResult('created', 'created', 'datetime')
+			->addScalarResult('updated', 'updated', 'datetime')
+			->addScalarResult('modified', 'modified', 'datetime')
+			->addIndexByScalar('id');
+
+		//Get result
+		$result = $this->_em
+			->createNativeQuery($req, $rsm)
+			->setParameter('offset', $page * $count)
+			->setParameter('count', $count)
+			->getArrayResult();
+
+		//Set return
+		$return = [];
+
+		//Iterate on each city
+		foreach($result as $data) {
+			//Add to return
+			$return[$data['id']] = [
+				'id' => $id = $data['id'],
+				'body' => $data['body'],
+				'description' => $data['description'],
+				'slug' => $slug = $data['slug'],
+				'title' => $data['title'],
+				'created' => $data['created'],
+				'updated' => $data['updated'],
+				'modified' => $data['modified'],
+				'link' => $this->router->generate('rapsys_blog_article_view', ['id' => $id, 'slug' => $slug]),
+				'keywords' => []
+			];
+
+			//Explode keyword ids
+			$data['k_ids'] = explode("\n", $data['k_ids']);
+
+			//Explode keyword slugs
+			$data['k_slugs'] = explode("\n", $data['k_slugs']);
+
+			//Explode keyword titles
+			$data['k_titles'] = explode("\n", $data['k_titles']);
+
+			foreach($data['k_ids'] as $k => $id) {
+				$return[$data['id']]['keywords'][$id] = [
+					'id' => $id,
+					'slug' => $slug = $data['k_slugs'][$k],
+					'title' => $data['k_titles'][$k],
+					'link' => $this->router->generate('rapsys_blog_keyword_view', ['id' => $id, 'slug' => $slug]),
+				];
 			}
 		}
-		//Send result
-		return $ret;
+
+		//Return return
+		return $return;
+	}
+
+	/**
+	 * Find article by id as array
+	 *
+	 * @param integer $id The article id
+	 * @return array The article array
+	 */
+	public function findByIdAsArray(int $id): array {
+		//Set the request
+		$req = <<<SQL
+SELECT
+	b.id,
+	b.created,
+	b.updated,
+	b.modified,
+	b.body,
+	b.description,
+	b.slug,
+	b.title,
+	b.k_ids,
+	b.k_slugs,
+	b.k_titles,
+	GROUP_CONCAT(kat.locale ORDER BY kat.locale SEPARATOR "\\n") AS kat_locales,
+	GROUP_CONCAT(kat.slug ORDER BY kat.locale SEPARATOR "\\n") AS kat_slugs,
+	GROUP_CONCAT(kat.title ORDER BY kat.locale SEPARATOR "\\n") AS kat_titles
+FROM (
+	SELECT
+		a.id,
+		GREATEST(a.created, at.created, k.created, kt.created) AS created,
+		GREATEST(a.updated, at.updated, k.updated, kt.updated) AS updated,
+		GREATEST(a.created, at.created, k.created, kt.created, a.updated, at.updated, k.updated, kt.updated) AS modified,
+		at.body,
+		at.description,
+		at.slug,
+		at.title,
+		GROUP_CONCAT(k.id ORDER BY k.id SEPARATOR "\\n") AS k_ids,
+		GROUP_CONCAT(kt.slug ORDER BY k.id SEPARATOR "\\n") AS k_slugs,
+		GROUP_CONCAT(kt.title ORDER BY k.id SEPARATOR "\\n") AS k_titles
+	FROM RapsysBlogBundle:Article AS a
+	JOIN RapsysBlogBundle:ArticleTranslation AS at ON (at.article_id = a.id AND at.locale = :locale)
+	LEFT JOIN RapsysBlogBundle:ArticleKeyword AS ak ON (ak.article_id = a.id)
+	LEFT JOIN RapsysBlogBundle:Keyword AS k ON (k.id = ak.keyword_id)
+	LEFT JOIN RapsysBlogBundle:KeywordTranslation AS kt ON (kt.keyword_id = k.id AND kt.locale = :locale)
+	WHERE a.id = :id
+	GROUP BY a.id
+	ORDER BY NULL
+	LIMIT 0, :limit
+) AS b
+LEFT JOIN RapsysBlogBundle:ArticleTranslation AS kat ON (kat.article_id = b.id AND kat.locale <> :locale)
+GROUP BY b.id
+SQL;
+
+		//Replace bundle entity name by table name
+		$req = $this->replace($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('id', 'id', 'integer')
+			->addScalarResult('body', 'body', 'string')
+			->addScalarResult('description', 'description', 'string')
+			->addScalarResult('slug', 'slug', 'string')
+			->addScalarResult('title', 'title', 'string')
+			->addScalarResult('k_ids', 'k_ids', 'string')
+			->addScalarResult('k_slugs', 'k_slugs', 'string')
+			->addScalarResult('k_titles', 'k_titles', 'string')
+			->addScalarResult('kat_locales', 'kat_locales', 'string')
+			->addScalarResult('kat_slugs', 'kat_slugs', 'string')
+			->addScalarResult('kat_titles', 'kat_titles', 'string')
+			->addScalarResult('created', 'created', 'datetime')
+			->addScalarResult('updated', 'updated', 'datetime')
+			->addScalarResult('modified', 'modified', 'datetime');
+
+		//Get data
+		$data = $this->_em
+			->createNativeQuery($req, $rsm)
+			->setParameter('id', $id)
+			->getOneOrNullResult();
+
+		//Set return
+		$return = [
+			'id' => $id = $data['id'],
+			'body' => $data['body'],
+			'description' => $data['description'],
+			'slug' => $slug = $data['slug'],
+			'title' => $data['title'],
+			'created' => $data['created'],
+			'updated' => $data['updated'],
+			'modified' => $data['modified'],
+			'link' => $this->router->generate('rapsys_blog_article_view', ['id' => $id, 'slug' => $slug]),
+			'alternates' => [],
+			'keywords' => []
+		];
+
+		//Explode keyword ids
+		$data['k_ids'] = explode("\n", $data['k_ids']);
+
+		//Explode keyword slugs
+		$data['k_slugs'] = explode("\n", $data['k_slugs']);
+
+		//Explode keyword titles
+		$data['k_titles'] = explode("\n", $data['k_titles']);
+
+		foreach($data['k_ids'] as $k => $kid) {
+			$return['keywords'][$kid] = [
+				'id' => $kid,
+				'slug' => $slug = $data['k_slugs'][$k],
+				'title' => $data['k_titles'][$k],
+				'link' => $this->router->generate('rapsys_blog_keyword_view', ['id' => $kid, 'slug' => $slug]),
+			];
+		}
+
+		//Explode alternate locales
+		$data['kat_locales'] = explode("\n", $data['kat_locales']);
+
+		//Explode alternate slugs
+		$data['kat_slugs'] = explode("\n", $data['kat_slugs']);
+
+		//Explode alternate titles
+		$data['kat_titles'] = explode("\n", $data['kat_titles']);
+
+		foreach($data['kat_locales'] as $k => $locale) {
+			$return['alternates'][$locale] = [
+				'locale' => $locale,
+				'slug' => $slug = $data['kat_slugs'][$k],
+				'title' => $data['kat_titles'][$k],
+				'link' => $this->router->generate('rapsys_blog_article_view', ['_locale' => $locale, 'id' => $id, 'slug' => $slug]),
+			];
+		}
+
+		//Return return
+		return $return;
 	}
 }