Skip to content

Instantly share code, notes, and snippets.

@dimitrihilverda
Created June 22, 2020 07:17
Show Gist options
  • Save dimitrihilverda/dde5fa04b05bdb1a94634dba9b25e64a to your computer and use it in GitHub Desktop.
Save dimitrihilverda/dde5fa04b05bdb1a94634dba9b25e64a to your computer and use it in GitHub Desktop.
jsonQ advanced querying with AND and OR etc
<?php
//use \Flow\JSONPath\JSONPath;
use Nahid\JsonQ\Exceptions\ConditionNotAllowedException;
use Nahid\JsonQ\Exceptions\NullValueException;
use \Nahid\JsonQ\Jsonq;
class datamodel
{
/* @var Jobfeed $jobfeed */
private $jobfeed;
public $_operators = [
'=',
'equal',
'eq',
'==',
'strictEqual',
'seq',
'!=',
'notEqual',
'neq',
'!==',
'strictNotEqual',
'sneq',
'>',
'gt',
'greaterThan',
'<',
'lessThan',
'lt',
'>=',
'gte',
'greaterThanOrEqual',
'<=',
'lte',
'lessThanOrEqual',
'in',
'notin',
'notIn',
'null',
'isNull',
'notnull',
'isNotNull',
'startswith',
'startWith',
'endswith',
'endWith',
'match',
'contains',
];
private $_queryMethods = [
'OR',
];
/**
* constructor.
*/
public function __construct(modX &$modx)
{
$this->modx =& $modx;
require_once dirname(__FILE__).'/../../vendor/autoload.php';
$this->getJobfeed();
}
public function getJobfeed(): Jobfeed
{
if (empty($this->jobfeed)) {
$this->jobfeed = $this->modx->getService('jobfeed', 'Jobfeed', __DIR__.'/');
}
return $this->jobfeed;
}
/**
* @param string $query
* @param string $ctx
*
* @return array|object
* @throws ConditionNotAllowedException
* @throws \Nahid\JsonQ\Exceptions\FileNotFoundException
* @throws \Nahid\JsonQ\Exceptions\InvalidJsonException
* @throws NullValueException
*/
public function getData(?array $query = null, string $ctx = 'web'): ?array
{
$jsonData = json_decode(json_encode($this->getJobfeed()->getJobData($ctx)), true);
$jsonQO = new Jsonq();
//Custom
$jsonQO->macro(
'latlong',
function ($a, $b) {
$toCords = explode(',', $a);
$fromCords = explode(',', $b);
$straal = $fromCords[2] * 1000;
$distance = $this->haversineGreatCircleDistance($fromCords[0], $fromCords[1], $toCords[0], $toCords[1]);
if ($distance - $straal < 0) {
return true;
} else {
return false;
}
}
);
$jsonQO->collect($jsonData);
if (null !== $query) {
try {
$this->buildQuery($query, $jsonQO);
} catch (Exception $e) {
$this->modx->log(1, $e->getMessage());
return [];
}
//do the search on the result of the previous queries
if (key_exists('search', $query)) {
try {
$result = $jsonQO->from('vacancy')->get();
$jsonQO = new jsonQ();
$jsonQO->collect($result);
$this->buildQuery($query['search'], $jsonQO);
return $jsonQO->get();
} catch (Exception $e) {
$this->modx->log(1, $e->getMessage().'search');
}
} else {
try {
return $jsonQO->from('vacancy')->get();
} catch (ConditionNotAllowedException $e) {
$this->modx->log(1, $e->getMessage());
} catch (NullValueException $e) {
$this->modx->log(1, $e->getMessage());
}
}
} else {
try {
return $jsonQO->from('vacancy')->get();
} catch (ConditionNotAllowedException $e) {
$this->modx->log(1, $e->getMessage());
} catch (NullValueException $e) {
$this->modx->log(1, $e->getMessage());
}
}
return [];
}
/**
* @param $queryParts
* @param $jsonQO
*
* @return mixed
* @throws Exception
*/
private function buildQuery(array $queryParts, Jsonq &$jsonQO): void
{
//{
// "hallo:!==":"blaat",
// "OR:hallo:<":"ietsanders",
// "hallo": "ok"
//}
foreach ($queryParts as $key => $value) {
if ($key == 'search') {
continue;
}
$key = explode(':', $key);
switch (count($key)) {
default:
throw new Exception('Unsupported modified count supplied');
break;
case 3:
if (!in_array($key[0], $this->_queryMethods)) {
throw new Exception('Unsupported query method "'.$key[0].'"');
}
if (!in_array($key[2], $this->_operators)) {
if (stripos($key[1], 'macro')) {
} else {
throw new Exception('Unsupported operator "'.$key[2].'"');
}
}
switch ($key[0]) {
case 'OR':
$jsonQO->orWhere($key[1], $key[2], $value);
break;
}
break;
case 2:
if (in_array($key[0], $this->_queryMethods)) {
switch ($key[0]) {
case 'OR':
$jsonQO->orWhere($key[1], '=', $value);
break;
}
} elseif (in_array($key[1], $this->_operators)) {
$jsonQO->where($key[0], $key[1], $value);
} elseif ($key[1] == 'macro') {
$jsonQO->where($key[0], 'latlong', $value);
} else {
throw new Exception('Unsupported query supplied'.$key[1]);
}
break;
case 1:
$jsonQO->where($key[0], '=', $value);
break;
}
}
}
public function haversineGreatCircleDistance(
$latitudeFrom,
$longitudeFrom,
$latitudeTo,
$longitudeTo,
$earthRadius = 6371000
): int {
$latFrom = deg2rad($latitudeFrom);
$lonFrom = deg2rad($longitudeFrom);
$latTo = deg2rad($latitudeTo);
$lonTo = deg2rad($longitudeTo);
$latDelta = $latTo - $latFrom;
$lonDelta = $lonTo - $lonFrom;
$angle = 2 * asin(
sqrt(
pow(sin($latDelta / 2), 2) +
cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)
)
);
return $angle * $earthRadius;
}
public function getDataAsJson(?array $query = null, string $ctx = 'web', int $limit = 10, int $offset = 0): string
{
$result = $this->getData($query, $ctx);
$total = count($result);
$result = array_slice($result, $offset, $limit);
$output['result'] = $result;
$output['info']['total'] = $total;
return json_encode($output);
}
public function getDataAsArray(?array $query = null, string $ctx = 'web', int $limit = 10, int $offset = 0, int $sort = 0, string $sortby = 'DATE', string $sortdir = 'DESC', ?array $favs = null): array
{
$response = $this->getData($query, $ctx);
// filter favorites
if (count($favs) > 0) {
$result = array_filter(
$response,
function ($val, $key) use ($favs) {
return in_array($val['@attributes']['id'], $favs);
},
ARRAY_FILTER_USE_BOTH
);
} else {
$result = $response;
}
$total = count($result);
// if sorting is enabled
if ($sort === 1) {
if ($sortby === 'DATE') {
if ($sortdir === 'ASC') {
usort(
$result,
function ($a, $b) {
$c = strtotime($a['@attributes']['date']) > strtotime($b['@attributes']['date']);
return $c;
}
);
} else if ($sortdir === 'DESC') {
usort(
$result,
function ($a, $b) {
$c = strtotime($a['@attributes']['date']) < strtotime($b['@attributes']['date']);
return $c;
}
);
}
} else if ($sortby === 'TITLE') {
if ($sortdir === 'ASC') {
usort(
$result,
function ($a, $b) {
return strcmp(strtolower(preg_replace("/\s*\([^)]+\)\s*/", "", $a['Position']['JobTitle'])), strtolower(preg_replace("/\s*\([^)]+\)\s*/", "", $b['Position']['JobTitle'])));
}
);
} else if ($sortdir === 'DESC') {
usort(
$result,
function ($a, $b) {
return strcmp(strtolower(preg_replace("/\s*\([^)]+\)\s*/", "", $b['Position']['JobTitle'])), strtolower(preg_replace("/\s*\([^)]+\)\s*/", "", $a['Position']['JobTitle'])));
}
);
}
}
}
$result = array_slice($result, $offset, $limit);
$output['result'] = $result;
$output['info']['total'] = $total;
return $output;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment