Files
dev-chiefworks f76abffdcd first commit
2022-05-31 16:21:53 -04:00

329 lines
12 KiB
PHP

<?php if (!defined('BASEPATH')) {
exit('No direct script access allowed');
}
class Geofence_area_model extends CI_Model
{
const GEOFENCING_AREA_TYPES = [
'postal',
'radius',
'polygon'
];
private $read_replica;
public function __construct()
{
parent::__construct();
$this->read_replica = $this->load->database('savvy_replica', TRUE);
}
public function getAllWithPagination($page = 1, $perPage = 10, $filterData = [])
{
$offset = ($page - 1) * $perPage;
if ($offset < 0) {
$offset = 0;
}
$whereQuery = '';
if (!empty($filterData)) {
if (!empty($filterData['city_id'])) {
$whereQuery .= ' WHERE geo_city.id = ' . $this->read_replica->escape($filterData['city_id']) . ' ';
}
}
$totalQueryString =
'SELECT
geo.id, geo.name, geo.area, geo_city.city as city_name, geo_city.id as city_id, geo.type,
geo.country as country_code, geo.latitude, geo.longitude, geo.boundaries,
country.country as country_name
FROM
geofence_area as geo
JOIN country ON country.code = geo.country
JOIN geofence_area_city as geo_city ON geo_city.id = geo.city_id
' . $whereQuery;
$queryString =
'SELECT
geo.id, geo.name, geo.area, geo_city.city as city_name, geo_city.id as city_id, geo.type,
geo.country as country_code, geo.latitude, geo.longitude, geo.boundaries,
country.country as country_name
FROM
geofence_area as geo
JOIN country ON country.code = geo.country
JOIN geofence_area_city as geo_city ON geo_city.id = geo.city_id
' . $whereQuery . '
ORDER BY id DESC
LIMIT ' . pg_escape_string($perPage) . ' OFFSET ' . pg_escape_string($offset);
$totalQuery = $this->read_replica->query($totalQueryString);
$query = $this->read_replica->query($queryString);
return [
'total' => count($totalQuery->result()),
'data' => $query->result(),
'page' => $page
];
}
public function getAllAreas()
{
$query = "SELECT
geofence_area.id, geofence_area.name, geofence_area_city.city, geofence_area.latitude, geofence_area.longitude,
geofence_area.location, geofence_area.type, geofence_area.boundaries
FROM
geofence_area
JOIN geofence_area_city ON geofence_area_city.id = geofence_area.city_id
";
$query = $this->read_replica->query($query);
return $query->result();
}
public function getItem($id)
{
$queryString =
'SELECT
geo.id, geo.name, geo.area, geo_city.city as city_name, geo_city.id as city_id, geo.type,
geo.country as country_code, geo.latitude, geo.longitude, geo.boundaries,
country.country as country_name
FROM
geofence_area as geo
JOIN country ON country.code = geo.country
JOIN geofence_area_city as geo_city ON geo_city.id = geo.city_id
WHERE
geo.id = ?
LIMIT 1
';
$query = $this->read_replica->query($queryString, $id);
return $query->row_array();
}
public function create($inputData)
{
$test = $this->db->insert('geofence_area', $inputData);
$insertId= $this->db->insert_id();
// update location field
$this->db->query("UPDATE geofence_area SET location = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326) WHERE id = {$insertId} ");
}
public function update($id, $inputData)
{
$this->db->where('id', $id);
$this->db->update('geofence_area', $inputData);
// update location field
$this->db->query("UPDATE geofence_area SET location = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326) WHERE id = {$id} ");
}
public function delete($id)
{
$this->db->delete('geofence_area', ['id' => $id]);
}
public function priceComparison($startAreaId, $endAreaId)
{
// validate id
if (!is_numeric($startAreaId) || !is_numeric($endAreaId)) {
return false;
}
// 1) Define geofenced areas, get list of areas
$startArea = $this->getArea($startAreaId);
$endArea = $this->getArea($endAreaId);
if (!$startArea || !$endArea) {
return [
'success' => false,
'message' => 'Can not find area.'
];
}
// 2. Select trips where "from" falls into origin area and "to" falls into destination area
$whereQuery = '';
$startBoundaries = json_decode($startArea['boundaries'], true);
$endBoundaries = json_decode($endArea['boundaries'], true);
if ($startArea['type'] === 'radius') {
if (isset($startBoundaries['radius'])) {
$radius = $startBoundaries['radius'];
$condition = " ST_DWithin('" . $startArea['location'] . "', startAddr.geometry, " . $radius . ") ";
$whereQuery = $this->checkCondition($condition, $whereQuery);
} else {
return [
'success' => false,
'message' => 'Missing radius in boundaries field.'
];
}
} else if ($startArea['type'] === 'postal') {
if (is_array($startBoundaries) && array_key_exists("postal_code",$startBoundaries) && is_array($startBoundaries["postal_code"]) && count($startBoundaries["postal_code"]) > 0) {
$condition = "";
foreach ($startBoundaries['postal_code'] as $code) {
if ($condition != "") {
$condition .= " OR ";
}
$condition .= " LEFT(startAddr.postal, " . strlen($code) . ") = '${code}' ";
}
$condition = "(${condition})";
$whereQuery = $this->checkCondition($condition, $whereQuery);
} else {
return [
'success' => false,
'message' => 'Missing postal_code in boundaries field.'
];
}
} else if ($startArea['type'] === 'polygon') {
if (isset($startBoundaries['polygon'])) {
$polygon = $startBoundaries['polygon'];
$polygonCoords = [];
foreach ($polygon as $coord) {
$polygonCoords[] = "$coord[0] $coord[1]";
}
$polygonCoordsString = implode(",", $polygonCoords);
$condition = " ST_Contains(ST_GeomFromText('POLYGON((${polygonCoordsString}))', 4326), startAddr.geometry::geometry) ";
$whereQuery = $this->checkCondition($condition, $whereQuery);
} else {
return [
'success' => false,
'message' => 'Missing polygon in boundaries field.'
];
}
}
if ($endArea['type'] === 'radius') {
if (isset($endBoundaries['radius'])) {
$radius = $endBoundaries['radius'];
$condition = " ST_DWithin('" . $endArea['location'] . "', endAddr.geometry, " . $radius . ") ";
$whereQuery = $this->checkCondition($condition, $whereQuery);
} else {
return [
'success' => false,
'message' => 'Missing radius in boundaries field.'
];
}
} else if ($endArea['type'] === 'postal') {
if (is_array($endBoundaries) && array_key_exists("postal_code",$endBoundaries) && is_array($endBoundaries["postal_code"]) && count($endBoundaries["postal_code"]) > 0) {
$condition = "";
foreach ($endBoundaries['postal_code'] as $code) {
if ($condition != "") {
$condition .= " OR ";
}
$condition .= " LEFT(endAddr.postal, " . strlen($code) . ") = '${code}' ";
}
$condition = "(${condition})";
$whereQuery = $this->checkCondition($condition, $whereQuery);
} else {
return [
'success' => false,
'message' => 'Missing postal_code in boundaries field.'
];
}
} else if ($endArea['type'] === 'polygon') {
if (isset($endBoundaries['polygon'])) {
$polygon = $endBoundaries['polygon'];
$polygonCoords = [];
foreach ($polygon as $coord) {
$polygonCoords[] = "$coord[0] $coord[1]";
}
$polygonCoordsString = implode(",", $polygonCoords);
$condition = " ST_Contains(ST_GeomFromText('POLYGON((${polygonCoordsString}))', 4326), endAddr.geometry::geometry) ";
$whereQuery = $this->checkCondition($condition, $whereQuery);
} else {
return [
'success' => false,
'message' => 'Missing polygon in boundaries field.'
];
}
}
// 3. Filter pricing by transport_provider_id and calculate average within last year
// only get trips within last year
$numberOfDays = 365;
$condition = " parsedemail_item.travel_date BETWEEN NOW() - INTERVAL '" . $numberOfDays . " days' AND NOW() ";
$whereQuery = $this->checkCondition($condition, $whereQuery);
$tripQuery =
"SELECT
ROUND(AVG(parsedemail_item.cost), 2) as avg_price, parsedemail_item.transport_provider_id,
transport_providers.name as transport_provider_name
FROM
parsedemail_item
JOIN transport_providers ON transport_providers.id = parsedemail_item.transport_provider_id
JOIN address AS startAddr ON (startAddr.id = parsedemail_item.location_start_id AND transport_provider_id IS NOT NULL
AND LOWER(startAddr.country) = '" . strtolower($startArea['country_code']) . "')
JOIN address AS endAddr ON (endAddr.id = parsedemail_item.location_end_id
AND LOWER(endAddr.country) = '" . strtolower($endArea['country_code']) . "')
" . $whereQuery . "
GROUP BY parsedemail_item.transport_provider_id, transport_providers.name
";
$query = $this->read_replica->query($tripQuery);
$result = [
'success' => true,
'from_area' => $startArea,
'to_area' => $endArea,
'price_comparison' => $query->result_array() ?: []
];
return $result;
}
private function checkCondition($condition, $query)
{
if (strpos($query, 'WHERE') === false) {
$query .= " WHERE $condition";
} else {
$query .= " AND $condition";
}
return $query;
}
public function getArea($id)
{
$query = "SELECT
geofence_area.id, geofence_area.name, geofence_area.country as country_code, geofence_area.latitude, geofence_area.longitude,
geofence_area.location, geofence_area.type, geofence_area.boundaries
FROM
geofence_area
WHERE
geofence_area.id = $id
LIMIT 1
";
$query = $this->read_replica->query($query);
$data = $query->result_array();
return !empty($data) ? $data[0] : null;
}
public function getLocationByID($id) {
$this->read_replica->select('*');
$this->read_replica->from('geofence_area');
$this->read_replica->where('id', $id);
$query = $this->read_replica->get();
return $query->result_array();
}
public function getLocationByCityID($city_id) {
$this->read_replica->select('ga.id AS id, ga.name AS geo_area_name');
$this->read_replica->from('geofence_area ga');
$this->read_replica->join('geofence_area_city gac', 'gac.id = ga.city_id');
$this->read_replica->where('gac.id', $city_id);
$this->read_replica->order_by('geo_area_name');
return $this->read_replica->get()->result_array();
}
}