/bundles/EcommerceFrameworkBundle/IndexService/ProductList/DefaultMysql/Dao.php

https://github.com/pimcore/pimcore · PHP · 315 lines · 218 code · 49 blank · 48 comment · 33 complexity · 122b7cba13a27ab3f508eafbd048352a MD5 · raw file

  1. <?php
  2. /**
  3. * Pimcore
  4. *
  5. * This source file is available under two different licenses:
  6. * - GNU General Public License version 3 (GPLv3)
  7. * - Pimcore Commercial License (PCL)
  8. * Full copyright and license information is available in
  9. * LICENSE.md which is distributed with this source code.
  10. *
  11. * @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12. * @license http://www.pimcore.org/license GPLv3 and PCL
  13. */
  14. namespace Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\DefaultMysql;
  15. use Doctrine\DBAL\Connection;
  16. use Monolog\Logger;
  17. use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\DefaultMysql;
  18. use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\ProductListInterface;
  19. use Pimcore\Db\ConnectionInterface;
  20. /**
  21. * @internal
  22. */
  23. class Dao
  24. {
  25. /**
  26. * @var ConnectionInterface|Connection
  27. */
  28. private $db;
  29. /**
  30. * @var DefaultMysql
  31. */
  32. private $model;
  33. /**
  34. * @var int
  35. */
  36. private $lastRecordCount;
  37. /**
  38. * @var Logger
  39. */
  40. protected $logger;
  41. public function __construct(DefaultMysql $model, Logger $logger)
  42. {
  43. $this->model = $model;
  44. $this->db = \Pimcore\Db::get();
  45. $this->logger = $logger;
  46. }
  47. public function load($condition, $orderBy = null, $limit = null, $offset = null)
  48. {
  49. if ($condition) {
  50. $condition = 'WHERE ' . $condition;
  51. }
  52. if ($orderBy) {
  53. $orderBy = ' ORDER BY ' . $orderBy;
  54. }
  55. if ($limit) {
  56. if ($offset) {
  57. $limit = 'LIMIT ' . $offset . ', ' . $limit;
  58. } else {
  59. $limit = 'LIMIT ' . $limit;
  60. }
  61. }
  62. if ($this->model->getVariantMode() == ProductListInterface::VARIANT_MODE_INCLUDE_PARENT_OBJECT) {
  63. if ($orderBy) {
  64. $query = 'SELECT SQL_CALC_FOUND_ROWS DISTINCT o_virtualProductId as o_id, priceSystemName FROM '
  65. . $this->model->getCurrentTenantConfig()->getTablename() . ' a '
  66. . $this->model->getCurrentTenantConfig()->getJoins()
  67. . $condition . ' GROUP BY o_virtualProductId, priceSystemName' . $orderBy . ' ' . $limit;
  68. } else {
  69. $query = 'SELECT SQL_CALC_FOUND_ROWS DISTINCT o_virtualProductId as o_id, priceSystemName FROM '
  70. . $this->model->getCurrentTenantConfig()->getTablename() . ' a '
  71. . $this->model->getCurrentTenantConfig()->getJoins()
  72. . $condition . ' ' . $limit;
  73. }
  74. } else {
  75. $query = 'SELECT SQL_CALC_FOUND_ROWS a.o_id, priceSystemName FROM '
  76. . $this->model->getCurrentTenantConfig()->getTablename() . ' a '
  77. . $this->model->getCurrentTenantConfig()->getJoins()
  78. . $condition . $orderBy . ' ' . $limit;
  79. }
  80. $this->logger->info('Query: ' . $query);
  81. $result = $this->db->fetchAllAssociative($query);
  82. $this->lastRecordCount = (int)$this->db->fetchOne('SELECT FOUND_ROWS()');
  83. $this->logger->info('Query done.');
  84. return $result;
  85. }
  86. public function loadGroupByValues($fieldname, $condition, $countValues = false)
  87. {
  88. if ($condition) {
  89. $condition = 'WHERE ' . $condition;
  90. }
  91. if ($countValues) {
  92. if ($this->model->getVariantMode() == ProductListInterface::VARIANT_MODE_INCLUDE_PARENT_OBJECT) {
  93. $query = "SELECT TRIM(`$fieldname`) as `value`, count(DISTINCT o_virtualProductId) as `count` FROM "
  94. . $this->model->getCurrentTenantConfig()->getTablename() . ' a '
  95. . $this->model->getCurrentTenantConfig()->getJoins()
  96. . $condition . ' GROUP BY TRIM(`' . $fieldname . '`)';
  97. } else {
  98. $query = "SELECT TRIM(`$fieldname`) as `value`, count(*) as `count` FROM "
  99. . $this->model->getCurrentTenantConfig()->getTablename() . ' a '
  100. . $this->model->getCurrentTenantConfig()->getJoins()
  101. . $condition . ' GROUP BY TRIM(`' . $fieldname . '`)';
  102. }
  103. $this->logger->info('Query: ' . $query);
  104. $result = $this->db->fetchAllAssociative($query);
  105. $this->logger->info('Query done.');
  106. return $result;
  107. } else {
  108. $query = 'SELECT ' . $this->db->quoteIdentifier($fieldname) . ' FROM '
  109. . $this->model->getCurrentTenantConfig()->getTablename() . ' a '
  110. . $this->model->getCurrentTenantConfig()->getJoins()
  111. . $condition . ' GROUP BY ' . $this->db->quoteIdentifier($fieldname);
  112. $this->logger->info('Query: ' . $query);
  113. $result = $this->db->fetchFirstColumn($query);
  114. $this->logger->info('Query done.');
  115. return $result;
  116. }
  117. }
  118. public function loadGroupByRelationValues($fieldname, $condition, $countValues = false)
  119. {
  120. if ($condition) {
  121. $condition = 'WHERE ' . $condition;
  122. }
  123. if ($countValues) {
  124. if ($this->model->getVariantMode() == ProductListInterface::VARIANT_MODE_INCLUDE_PARENT_OBJECT) {
  125. $query = 'SELECT dest as `value`, count(DISTINCT src_virtualProductId) as `count` FROM '
  126. . $this->model->getCurrentTenantConfig()->getRelationTablename() . ' a '
  127. . 'WHERE fieldname = ' . $this->quote($fieldname);
  128. } else {
  129. $query = 'SELECT dest as `value`, count(*) as `count` FROM '
  130. . $this->model->getCurrentTenantConfig()->getRelationTablename() . ' a '
  131. . 'WHERE fieldname = ' . $this->quote($fieldname);
  132. }
  133. $subquery = 'SELECT a.o_id FROM '
  134. . $this->model->getCurrentTenantConfig()->getTablename() . ' a '
  135. . $this->model->getCurrentTenantConfig()->getJoins()
  136. . $condition;
  137. $query .= ' AND src IN (' . $subquery . ') GROUP BY dest';
  138. $this->logger->info('Query: ' . $query);
  139. $result = $this->db->fetchAllAssociative($query);
  140. $this->logger->info('Query done.');
  141. return $result;
  142. } else {
  143. $query = 'SELECT dest FROM ' . $this->model->getCurrentTenantConfig()->getRelationTablename() . ' a '
  144. . 'WHERE fieldname = ' . $this->quote($fieldname);
  145. $subquery = 'SELECT a.o_id FROM '
  146. . $this->model->getCurrentTenantConfig()->getTablename() . ' a '
  147. . $this->model->getCurrentTenantConfig()->getJoins()
  148. . $condition;
  149. $query .= ' AND src IN (' . $subquery . ') GROUP BY dest';
  150. $this->logger->info('Query: ' . $query);
  151. $result = $this->db->fetchFirstColumn($query);
  152. $this->logger->info('Query done.');
  153. return $result;
  154. }
  155. }
  156. public function getCount($condition, $orderBy = null, $limit = null, $offset = null)
  157. {
  158. if ($condition) {
  159. $condition = 'WHERE ' . $condition;
  160. }
  161. if ($orderBy) {
  162. $orderBy = ' ORDER BY ' . $orderBy;
  163. }
  164. if ($limit) {
  165. if ($offset) {
  166. $limit = 'LIMIT ' . $offset . ', ' . $limit;
  167. } else {
  168. $limit = 'LIMIT ' . $limit;
  169. }
  170. }
  171. if ($this->model->getVariantMode() == ProductListInterface::VARIANT_MODE_INCLUDE_PARENT_OBJECT) {
  172. $query = 'SELECT count(DISTINCT o_virtualProductId) FROM '
  173. . $this->model->getCurrentTenantConfig()->getTablename() . ' a '
  174. . $this->model->getCurrentTenantConfig()->getJoins()
  175. . $condition . $orderBy . ' ' . $limit;
  176. } else {
  177. $query = 'SELECT count(*) FROM '
  178. . $this->model->getCurrentTenantConfig()->getTablename() . ' a '
  179. . $this->model->getCurrentTenantConfig()->getJoins()
  180. . $condition . $orderBy . ' ' . $limit;
  181. }
  182. $this->logger->info('Query: ' . $query);
  183. $result = $this->db->fetchOne($query);
  184. $this->logger->info('Query done.');
  185. return $result;
  186. }
  187. public function quote($value)
  188. {
  189. return $this->db->quote($value);
  190. }
  191. /**
  192. * returns order by statement for simularity calculations based on given fields and object ids
  193. *
  194. * @param array $fields
  195. * @param int $objectId
  196. *
  197. * @return string
  198. */
  199. public function buildSimularityOrderBy($fields, $objectId)
  200. {
  201. try {
  202. $fieldString = '';
  203. $maxFieldString = '';
  204. foreach ($fields as $f) {
  205. if (!empty($fieldString)) {
  206. $fieldString .= ',';
  207. $maxFieldString .= ',';
  208. }
  209. $fieldString .= $this->db->quoteIdentifier($f->getField());
  210. $maxFieldString .= 'MAX(' . $this->db->quoteIdentifier($f->getField()) . ') as ' . $this->db->quoteIdentifier($f->getField());
  211. }
  212. $query = 'SELECT ' . $fieldString . ' FROM ' . $this->model->getCurrentTenantConfig()->getTablename() . ' a WHERE a.o_id = ?;';
  213. $this->logger->info('Query: ' . $query);
  214. $objectValues = $this->db->fetchAssociative($query, [$objectId]);
  215. $this->logger->info('Query done.');
  216. $query = 'SELECT ' . $maxFieldString . ' FROM ' . $this->model->getCurrentTenantConfig()->getTablename() . ' a';
  217. $this->logger->info('Query: ' . $query);
  218. $maxObjectValues = $this->db->fetchAssociative($query);
  219. $this->logger->info('Query done.');
  220. if (!empty($objectValues)) {
  221. $subStatement = [];
  222. foreach ($fields as $f) {
  223. $subStatement[] =
  224. '(' .
  225. $this->db->quoteIdentifier($f->getField()) . '/' . $maxObjectValues[$f->getField()] .
  226. ' - ' .
  227. $objectValues[$f->getField()] / $maxObjectValues[$f->getField()] .
  228. ') * ' . $f->getWeight();
  229. }
  230. $statement = 'ABS(' . implode(' + ', $subStatement) . ')';
  231. $this->logger->info('Similarity Statement: ' . $statement);
  232. return $statement;
  233. } else {
  234. throw new \Exception('Field array for given object id is empty');
  235. }
  236. } catch (\Exception $e) {
  237. $this->logger->error((string) $e);
  238. return '';
  239. }
  240. }
  241. /**
  242. * returns where statement for fulltext search index
  243. *
  244. * @param array $fields
  245. * @param string $searchstring
  246. *
  247. * @return string
  248. */
  249. public function buildFulltextSearchWhere($fields, $searchstring)
  250. {
  251. $columnNames = [];
  252. foreach ($fields as $c) {
  253. $columnNames[] = $this->db->quoteIdentifier($c);
  254. }
  255. return 'MATCH (' . implode(',', $columnNames) . ') AGAINST (' . $this->db->quote($searchstring) . ' IN BOOLEAN MODE)';
  256. }
  257. /**
  258. * get the record count for the last select query
  259. *
  260. * @return int
  261. */
  262. public function getLastRecordCount()
  263. {
  264. return $this->lastRecordCount;
  265. }
  266. }