Skip to content

Commit

Permalink
findLocationsInRadius with DBAL/doctrine
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimruhs committed Nov 23, 2019
1 parent ff4526e commit 2744969
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 65 deletions.
208 changes: 148 additions & 60 deletions Classes/Domain/Repository/AddressRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/***************************************************************
* Copyright notice
*
* (c) Joachim Ruhs 2018
* (c) Joachim Ruhs 2018-2019
*
* All rights reserved
*
Expand All @@ -28,7 +28,10 @@

use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;

use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Extbase\Persistence\Generic\Query;
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;


/**
Expand All @@ -53,77 +56,162 @@ class AddressRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
*/
public function findLocationsInRadius($latLon, $radius, $categories, $storagePid, $limit, $page, $orderBy = 'distance', $categoryMode = true) {
$radius = intval($radius);
$pi = M_PI;
$lat = (float) $latLon->lat;
$lon = (float) $latLon->lon;
$lat = $latLon->lat;
$lon = $latLon->lon;
$query = $this->createQuery();

$limit = intval($page * $limit) . ',' . intval($limit);
// categoryAndSelect
if ($categoryMode == 'AND')
$categorySelectMode = ' AND ';
else $categorySelectMode = ' OR ';

$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
->getQueryBuilderForTable('tx_myttaddressmap_domain_model_address');

$queryBuilder->from('tt_address', 'a');

$arrayOfPids = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $storagePid, TRUE);
$storagePidList = implode(',', $arrayOfPids);

$queryBuilder->selectLiteral(
'distinct a.*', '(acos(sin(' . floatval($lat * M_PI / 180) . ') * sin(latitude * ' . floatval(M_PI / 180) . ') + cos(' . floatval($lat * M_PI / 180) . ') *
cos(latitude * ' . floatval(M_PI / 180) . ') * cos((' . floatval($lon) . ' - longitude) * ' . floatval(M_PI / 180) . '))) * 6370 as `distance`,
(SELECT GROUP_CONCAT(e.title ORDER BY e.title SEPARATOR \', \') from tt_address d, sys_category
e, sys_category_record_mm f
where f.uid_local = e.uid
AND f.uid_foreign= d.uid
and d.uid = a.uid
and e.pid in (' . $storagePidList . ')
) as categories
'
)

->where(
$queryBuilder->expr()->in(
'a.pid',
$queryBuilder->createNamedParameter(
$query->getQuerySettings()->getStoragePageIds(),
\Doctrine\DBAL\Connection::PARAM_INT_ARRAY
)
)
)

->orderBy('distance');

if ((!empty($categories))) {
$query = $this->createQuery();
$queryBuilder->having('`distance` <= ' . $queryBuilder->createNamedParameter($radius, \PDO::PARAM_INT));
$queryBuilder = $this->addCategoryQueryPart($categories, $categoryMode, $queryBuilder);

// sanitizing
$categories = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $categories, TRUE);
if ($categorySelectMode == ' OR ')
$queryBuilder->setMaxResults(intval($limit))->setFirstResult(intval($page * $limit));

$result = $queryBuilder->execute()->fetchAll();

$arrayOfCategories = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $categories, TRUE);

// categoryAndSelect
if ($categoryMode == 'AND')
$categorySelectMode = ' AND ';
else $categorySelectMode = ' OR ';

for ($i = 0; $i < count($categories); $i++) {
if ($categories[$i]) {
if ($i == 0) {
$categoryAndSelect = " AND (($categories[$i] in (select uid_local from sys_category_record_mm c
where c.uid_foreign = a.uid AND tablenames='tt_address' AND fieldname='categories'))";

} else {
$categoryAndSelect .= " $categorySelectMode ($categories[$i] in (select uid_local from sys_category_record_mm c
where c.uid_foreign = a.uid AND tablenames='tt_address' AND fieldname='categories'))";

}
if ($categorySelectMode == ' AND ' /*&& count($arrayOfCategories) */) {
// we have to check the location for $arrayOfCategories
$j = 0;
for ($i = 0; $i < count($result); $i++) {
$checkOk = $this->testLocationCategories($result[$i]['uid'], $arrayOfCategories);
if ($checkOk) $j++;
//echo $result[$i]['name'] . ' ' . $checkOk . '$j= ' .$j . '<' . $page * $limit . '&&' . $j . '<=' . intval(($page + 1) * $limit) . '<br />';
if (!($arrayOfCategories)) $checkOk = 1;

if ($checkOk && ($j > $page * $limit && $j <= intval(($page + 1) * $limit))) {
$newResult[] = $result[$i];
}
}
if ($categoryAndSelect) $categoryAndSelect .= ')';

$result = $query->statement("SELECT distinct a.*, (((acos(sin(($lat*$pi/180)) * sin((latitude*$pi/180)) + cos(($lat*$pi/180)) *
cos((latitude*$pi/180)) * cos((($lon - longitude)*$pi/180)))))*6370) as distance,
return $newResult;
}
return $result;
}

(SELECT GROUP_CONCAT(e.title ORDER BY e.title SEPARATOR ', ') from tt_address d, sys_category
e, sys_category_record_mm f
where f.uid_local = e.uid AND
f.uid_foreign= d.uid
AND f.uid_foreign = d.uid
and d.uid = a.uid
and e.pid = " . intval($storagePid) ."
) as categories
FROM tt_address a
WHERE a.latitude != 0 AND a.longitude != 0 AND a.hidden = 0 AND a.deleted = 0 AND a.pid in (" . $storagePid . ")
$categoryAndSelect
having distance <=" . intval($radius) . " order by " . $orderBy . " limit " . $limit )->execute(TRUE);

} else {
$result = $query->statement("SELECT distinct a.*, (((acos(sin(($lat*$pi/180)) * sin((latitude*$pi/180)) + cos(($lat*$pi/180)) *
cos((latitude*$pi/180)) * cos((($lon - longitude)*$pi/180)))))*6370) as distance,
(SELECT GROUP_CONCAT(e.title ORDER BY e.title SEPARATOR ', ') from tt_address d, sys_category
e, sys_category_record_mm f
where f.uid_local = e.uid AND
f.uid_foreign= d.uid
AND f.uid_foreign = d.uid
and d.uid = a.uid
and e.pid = " . intval($storagePid) ."
) as categories
FROM tt_address a
WHERE a.latitude != 0 AND a.longitude != 0 AND a.hidden = 0 AND a.deleted = 0 AND a.pid in (" . $storagePid . ")
having distance <=" . intval($radius) . " order by " . $orderBy . " limit " . $limit )->execute(TRUE);
/*
* check if location belongs to all categories of $arrayOfCategories
*
* @param int $locationUid
* @param array $arrayOfCategories
*
* @return bool $allCategoriesFound
*/
protected function testLocationCategories($locationUid, $arrayOfCategories)
{
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
->getQueryBuilderForTable('sys_category_record_mm');

$queryBuilder->from('sys_category_record_mm', 'a');
$queryBuilder->select('*');
$queryBuilder->where(
$queryBuilder->expr()->andX(
$queryBuilder->expr()->eq('a.uid_foreign', $queryBuilder->createNamedParameter($locationUid, \PDO::PARAM_INT)),
$queryBuilder->expr()->eq('a.tablenames', $queryBuilder->createNamedParameter('tt_address')),
$queryBuilder->expr()->eq('a.fieldname', $queryBuilder->createNamedParameter('categories')),
$queryBuilder->expr()->in('a.uid_local', $queryBuilder->createNamedParameter($arrayOfCategories, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY))
)
);

}
return $result;

$result = $queryBuilder->execute()->fetchAll();

for ($i = 0; $i < count($result); $i++) {
for ($j = 0; $j < count($arrayOfCategories); $j++) {
if ($arrayOfCategories[$j] == $result[$i]['uid_local']) {
$f++;
$i++;
continue;
}
}
}
$allCategoriesFound = (count($arrayOfCategories) == $f)? 1 : 0;
return $allCategoriesFound; // if $f == count($arrayOfCategories) all categories are found for this location
}


/*
* adopted from EXT storefinder
*
* @param string $categories
* @param QueryBuilder $queryBuilder
*
* @return QueryBuilder
*/
protected function addCategoryQueryPart($categoryList, $categoryMode, QueryBuilder $queryBuilder): QueryBuilder
{
$arrayOfCategories = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $categoryList, TRUE);

if (!empty($arrayOfCategories)) {
$expression = $queryBuilder->expr();
$queryBuilder->innerJoin(
'a',
'sys_category_record_mm',
'c',
$expression->andX(
$expression->eq('a.uid', $queryBuilder->quoteIdentifier('c.uid_foreign')),
$expression->eq(
'c.tablenames',
$queryBuilder->createNamedParameter('tt_address')
),
$expression->eq(
'c.fieldname',
$queryBuilder->createNamedParameter('categories')
)

)
);
$queryBuilder->andWhere(
$expression->in(
'c.uid_local',
$queryBuilder->createNamedParameter($arrayOfCategories, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
)
);
}
return $queryBuilder;
}




Expand Down
4 changes: 2 additions & 2 deletions Documentation/Settings.cfg
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[general]
copyright = 2018
copyright = 2019
project = Myleaflet
release = 0.4.0
release = 0.4.3
version = 0.4

[html_theme_options]
Expand Down
4 changes: 2 additions & 2 deletions Documentation/Settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

---
conf.py:
copyright: 2018
copyright: 2019
project: Myleaflet
version: 0.4
release: 0.4.0
release: 0.4.3
latex_documents:
- - Index
- myleaflet.tex
Expand Down
2 changes: 1 addition & 1 deletion ext_emconf.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
'uploadfolder' => true,
'createDirs' => 'uploads/tx_myleaflet/icons',
'clearCacheOnLoad' => 0,
'version' => '0.4.1',
'version' => '0.4.3',
'constraints' =>
array (
'depends' =>
Expand Down

0 comments on commit 2744969

Please sign in to comment.