Rebuild delta mode
This commit is contained in:
289
inc/Spot.php
289
inc/Spot.php
@@ -88,7 +88,7 @@ class Spot extends Main
|
||||
(
|
||||
'tables' => array
|
||||
(
|
||||
Feed::MSG_TABLE => array('ref_msg_id', Db::getId(Feed::FEED_TABLE), 'type', 'latitude', 'longitude', 'iso_time', 'site_time', 'timezone', 'unix_time', 'content', 'battery_state'),
|
||||
Feed::MSG_TABLE => array('ref_msg_id', Db::getId(Feed::FEED_TABLE), 'type', 'latitude', 'longitude', 'iso_time', 'site_time', 'timezone', 'unix_time', 'content', 'battery_state', 'posted_on'),
|
||||
Feed::FEED_TABLE => array('ref_feed_id', Db::getId(Feed::SPOT_TABLE), Db::getId(Project::PROJ_TABLE), 'name', 'description', 'status', 'last_update'),
|
||||
Feed::SPOT_TABLE => array('ref_spot_id', 'name', 'model'),
|
||||
Project::PROJ_TABLE => array('name', 'codename', 'active_from', 'active_to'),
|
||||
@@ -146,7 +146,10 @@ class Spot extends Main
|
||||
),
|
||||
'cascading_delete' => array
|
||||
(
|
||||
Feed::SPOT_TABLE => array(Feed::MSG_TABLE)
|
||||
Feed::SPOT_TABLE => array(Feed::FEED_TABLE),
|
||||
Feed::FEED_TABLE => array(Feed::MSG_TABLE),
|
||||
Project::PROJ_TABLE => array(Feed::FEED_TABLE, Media::MEDIA_TABLE, self::POST_TABLE),
|
||||
self::MAP_TABLE => array(self::MAPPING_TABLE)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -217,14 +220,13 @@ class Spot extends Main
|
||||
$oEmail->setDestInfo($this->oUser->getActiveUsersInfo());
|
||||
|
||||
//Add Position
|
||||
$asMessages = $this->getSpotMessages();
|
||||
$asLastMessage = end($asMessages);
|
||||
$asLastMessage = array_shift($this->getSpotMessages(array($this->oProject->getLastMessageId($this->getFeedConstraints(Feed::MSG_TABLE)))));
|
||||
$asLastMessage['token'] = Settings::GEO_SERVER_TOKEN;
|
||||
$oEmail->oTemplate->setTags($asLastMessage);
|
||||
$oEmail->oTemplate->setTag('date_time', 'time:'.$asLastMessage['unix_time'], 'd/m/Y, H:i');
|
||||
|
||||
//Add latest news feed
|
||||
$asNews = $this->getNewsFeed(0, 0, true);
|
||||
$asNews = $this->getNextFeed(0, true);
|
||||
$iPostCount = 0;
|
||||
foreach($asNews as $asPost) {
|
||||
if($asPost['type'] != 'message') {
|
||||
@@ -262,13 +264,15 @@ class Spot extends Main
|
||||
return self::getJsonResult($bSuccess, '');
|
||||
}
|
||||
|
||||
public function getMarkers()
|
||||
public function getMarkers($asMessageIds=array(), $asMediaIds=array(), $bInternal=false)
|
||||
{
|
||||
$asMessages = $this->getSpotMessages();
|
||||
$asMessages = $this->getSpotMessages($asMessageIds);
|
||||
usort($asMessages, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||
|
||||
//Add medias
|
||||
if(!empty($asMessages)) {
|
||||
$asMedias = $this->getMedias('taken_on');
|
||||
$asMedias = $this->getMedias('taken_on', $asMediaIds);
|
||||
usort($asMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||
|
||||
//Assign medias to closest message
|
||||
$iIndex = 0;
|
||||
@@ -277,7 +281,9 @@ class Spot extends Main
|
||||
while($iIndex <= $iMaxIndex && $asMedia['unix_time'] > $asMessages[$iIndex]['unix_time']) {
|
||||
$iIndex++;
|
||||
}
|
||||
if($iIndex == 0) $iMsgIndex = $iIndex;
|
||||
|
||||
//All medias before first message or after last message are assigned to first/last message respectively
|
||||
if($iIndex == 0) $iMsgIndex = $iIndex;
|
||||
elseif($iIndex > $iMaxIndex) $iMsgIndex = $iMaxIndex;
|
||||
else {
|
||||
$iHalfWayPoint = ($asMessages[$iIndex - 1]['unix_time'] + $asMessages[$iIndex]['unix_time'])/2;
|
||||
@@ -288,15 +294,17 @@ class Spot extends Main
|
||||
}
|
||||
}
|
||||
|
||||
//Add Project Last Update
|
||||
//Spot Last Update
|
||||
$asLastUpdate = array();
|
||||
$this->addTimeStamp($asLastUpdate, $this->oProject->getLastUpdate());
|
||||
|
||||
return self::getJsonResult(true, '', array(
|
||||
$asResult = array(
|
||||
'messages' => $asMessages,
|
||||
'maps' => $this->oProject->getMaps(),
|
||||
'last_update' => $asLastUpdate
|
||||
));
|
||||
);
|
||||
|
||||
return $bInternal?$asResult:self::getJsonResult(true, '', $asResult);
|
||||
}
|
||||
|
||||
public function subscribe($sEmail) {
|
||||
@@ -327,34 +335,35 @@ class Spot extends Main
|
||||
return $this->oLang->getTranslation($sDesc);
|
||||
}
|
||||
|
||||
private function getSpotMessages()
|
||||
private function getSpotMessages($asMsgIds=array())
|
||||
{
|
||||
$asMessages = array();
|
||||
$asConstraints = $this->getFeedConstraints(Feed::MSG_TABLE);
|
||||
if(!empty($asMsgIds)) {
|
||||
$asConstraints['constraint'][Db::getId(Feed::MSG_TABLE)] = $asMsgIds;
|
||||
$asConstraints['constOpe'][Db::getId(Feed::MSG_TABLE)] = 'IN';
|
||||
}
|
||||
|
||||
$asCombinedMessages = array();
|
||||
|
||||
//Get messages from all feeds belonging to the project
|
||||
$asFeeds = $this->oProject->getFeedIds();
|
||||
foreach($asFeeds as $iFeedId) {
|
||||
$oFeed = new Feed($this->oDb, $iFeedId);
|
||||
$asMessages = $oFeed->getMessages($this->oProject->getActivePeriod());
|
||||
foreach($asMessages as &$asMessage)
|
||||
$asMessages = $oFeed->getMessages($asConstraints);
|
||||
foreach($asMessages as $asMessage)
|
||||
{
|
||||
$asMessage['latitude'] = floatval($asMessage['latitude']);
|
||||
$asMessage['longitude'] = floatval($asMessage['longitude']);
|
||||
$asMessage['lat_dms'] = self::decToDms($asMessage['latitude'], 'lat');
|
||||
$asMessage['lon_dms'] = self::decToDms($asMessage['longitude'], 'lon');
|
||||
$asMessage['displayed_id'] = $asMessage[Db::getId(Feed::MSG_TABLE)];
|
||||
|
||||
$this->addTimeStamp($asMessage, $asMessage['unix_time'], $asMessage['timezone']);
|
||||
$asCombinedMessages[] = $asMessage;
|
||||
}
|
||||
}
|
||||
|
||||
//Sort chronologically
|
||||
usort($asMessages, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||
|
||||
//Add Display ID
|
||||
$asSortedMessages = array_values($asMessages);
|
||||
foreach($asSortedMessages as $iIndex=>&$asSortedMessage) $asSortedMessage['displayed_id'] = $iIndex + 1;
|
||||
|
||||
return $asSortedMessages;
|
||||
return $asCombinedMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,48 +373,44 @@ class Spot extends Main
|
||||
* @param String $sTimeRefField Field to calculate relative times: 'taken_on' or 'posted_on'
|
||||
* @return Array Medias info
|
||||
*/
|
||||
private function getMedias($sTimeRefField)
|
||||
private function getMedias($sTimeRefField, $asMediaIds=array())
|
||||
{
|
||||
$asMedias = $this->oMedia->getMediasInfo();
|
||||
$asValidMedias = array();
|
||||
foreach($asMedias as $asMedia) {
|
||||
$sTimeRef = $asMedia[$sTimeRefField];
|
||||
if($sTimeRef >= $this->oProject->getActivePeriod('from') && $sTimeRef <= $this->oProject->getActivePeriod('to')) {
|
||||
$iTimeStampTakenOn = strtotime($asMedia['taken_on']);
|
||||
$iTimeStampPostedOn = strtotime($asMedia['posted_on']);
|
||||
$asMedia['taken_on_formatted'] = $this->getTimeFormat($iTimeStampTakenOn);
|
||||
$asMedia['taken_on_formatted_local'] = $this->getTimeFormat($iTimeStampTakenOn, $asMedia['timezone']);
|
||||
$asMedia['posted_on_formatted'] = $this->getTimeFormat($iTimeStampPostedOn);
|
||||
$asMedia['posted_on_formatted_local'] = $this->getTimeFormat($iTimeStampPostedOn, $asMedia['timezone']);
|
||||
|
||||
$this->addTimeStamp($asMedia, strtotime($sTimeRef), $asMedia['timezone']);
|
||||
$asValidMedias[] = $asMedia;
|
||||
}
|
||||
//Constraints
|
||||
$asConstraints = $this->getFeedConstraints(Media::MEDIA_TABLE, $sTimeRefField);
|
||||
if(!empty($asMediaIds)) {
|
||||
$asConstraints['constraint'][Db::getId(Media::MEDIA_TABLE)] = $asMediaIds;
|
||||
$asConstraints['constOpe'][Db::getId(Media::MEDIA_TABLE)] = 'IN';
|
||||
}
|
||||
|
||||
usort($asValidMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||
$asMedias = $this->oMedia->getMediasInfo($asConstraints);
|
||||
foreach($asMedias as &$asMedia) {
|
||||
$iTimeStampTakenOn = strtotime($asMedia['taken_on']);
|
||||
$iTimeStampPostedOn = strtotime($asMedia['posted_on']);
|
||||
$asMedia['taken_on_formatted'] = $this->getTimeFormat($iTimeStampTakenOn);
|
||||
$asMedia['taken_on_formatted_local'] = $this->getTimeFormat($iTimeStampTakenOn, $asMedia['timezone']);
|
||||
$asMedia['posted_on_formatted'] = $this->getTimeFormat($iTimeStampPostedOn);
|
||||
$asMedia['posted_on_formatted_local'] = $this->getTimeFormat($iTimeStampPostedOn, $asMedia['timezone']);
|
||||
$asMedia['displayed_id'] = $asMedia[Db::getId(Media::MEDIA_TABLE)];
|
||||
|
||||
$asSortedMedias = array_values($asValidMedias);
|
||||
foreach($asSortedMedias as $iIndex=>&$asSortedMedia) $asSortedMedia['displayed_id'] = $iIndex + 1;
|
||||
$this->addTimeStamp($asMedia, strtotime($asMedia[$sTimeRefField]), $asMedia['timezone']);
|
||||
}
|
||||
|
||||
return $asSortedMedias;
|
||||
return $asMedias;
|
||||
}
|
||||
|
||||
private function getPosts()
|
||||
private function getPosts($asPostIds=array())
|
||||
{
|
||||
$asInfo = array(
|
||||
'select' => array(Db::getFullColumnName(self::POST_TABLE, '*'), 'gravatar'),
|
||||
'from' => self::POST_TABLE,
|
||||
'join' => array(User::USER_TABLE => Db::getId(User::USER_TABLE)),
|
||||
'constraint'=> array(
|
||||
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
|
||||
'site_time' => $this->oProject->getActivePeriod('to')
|
||||
),
|
||||
'constOpe' => array(
|
||||
Db::getId(Project::PROJ_TABLE) => "=",
|
||||
'site_time' => "<="
|
||||
)
|
||||
'join' => array(User::USER_TABLE => Db::getId(User::USER_TABLE))
|
||||
);
|
||||
$asInfo = array_merge($asInfo, $this->getFeedConstraints(self::POST_TABLE));
|
||||
|
||||
if(!empty($asPostIds)) {
|
||||
$asInfo['constraint'][Db::getId(self::POST_TABLE)] = $asPostIds;
|
||||
$asInfo['constOpe'][Db::getId(self::POST_TABLE)] = 'IN';
|
||||
}
|
||||
$asPosts = $this->oDb->selectRows($asInfo);
|
||||
|
||||
foreach($asPosts as &$asPost) {
|
||||
@@ -415,7 +420,6 @@ class Spot extends Main
|
||||
|
||||
$this->addTimeStamp($asPost, $iUnixTimeStamp, $asPost['timezone']);
|
||||
}
|
||||
usort($asPosts, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||
|
||||
return $asPosts;
|
||||
}
|
||||
@@ -427,54 +431,145 @@ class Spot extends Main
|
||||
if($sTimeZone != '') $asData['formatted_time_local'] = $this->getTimeFormat($iTime, $sTimeZone);
|
||||
}
|
||||
|
||||
public function getNewsFeed($iChunk=0, $iRefTimePoint=0, $bInternal=false)
|
||||
{
|
||||
$bHistoMode = ($this->oProject->getMode() == Project::MODE_HISTO);
|
||||
$asFeeds = array();
|
||||
$asFeedTypes = array(
|
||||
'message' => array(
|
||||
'table' => Feed::MSG_TABLE,
|
||||
'feed' => $this->getSpotMessages(),
|
||||
'priority' => 0
|
||||
),
|
||||
'media' => array(
|
||||
'table' => Media::MEDIA_TABLE,
|
||||
'feed' => $this->getMedias('posted_on'),
|
||||
'priority' => 1
|
||||
),
|
||||
'post' => array(
|
||||
'table' => self::POST_TABLE,
|
||||
'feed' => $this->getPosts(),
|
||||
'priority' => 2
|
||||
)
|
||||
private function getFeedConstraints($sType, $sTimeField='site_time', $sReturnFormat='array') {
|
||||
$asConsArray = array();
|
||||
$sConsSql = "";
|
||||
$asActPeriod = $this->oProject->getActivePeriod();
|
||||
|
||||
//Filter on Project ID
|
||||
$sConsSql = "WHERE ".Db::getId(Project::PROJ_TABLE)." = ".$this->oProject->getProjectId();
|
||||
$asConsArray = array(
|
||||
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId()),
|
||||
'constOpe' => array(Db::getId(Project::PROJ_TABLE) => "=")
|
||||
);
|
||||
foreach($asFeedTypes as $sFeedType=>$asFeedTypeInfo) {
|
||||
foreach($asFeedTypeInfo['feed'] as $asFeed) {
|
||||
$iTableId = $asFeed[Db::getId($asFeedTypeInfo['table'])];
|
||||
|
||||
//Build unique sorting ID
|
||||
$iSort = $asFeed['unix_time'].'.'.$asFeedTypeInfo['priority'].$iTableId;
|
||||
|
||||
//Build feed (not including new feeds added in between chunk by concurrent access)
|
||||
if($iChunk == 0 || $iSort <= $iRefTimePoint) {
|
||||
$asFeeds[$iSort] = $asFeed;
|
||||
$asFeeds[$iSort]['type'] = $sFeedType;
|
||||
$asFeeds[$iSort]['id'] = $iTableId;
|
||||
}
|
||||
|
||||
//Build Reference Time Point (latest item extracted by first chunk)
|
||||
if($iChunk == 0 && $iSort > $iRefTimePoint) $iRefTimePoint = $iSort;
|
||||
}
|
||||
//Time Filter
|
||||
switch($sType) {
|
||||
case Feed::MSG_TABLE:
|
||||
$asConsArray['constraint'][$sTimeField] = $asActPeriod;
|
||||
$asConsArray['constOpe'][$sTimeField] = "BETWEEN";
|
||||
$sConsSql .= " AND ".$sTimeField." BETWEEN '".$asActPeriod['from']."' AND '".$asActPeriod['to']."'";
|
||||
break;
|
||||
case Media::MEDIA_TABLE:
|
||||
$asConsArray['constraint'][$sTimeField] = $asActPeriod['to'];
|
||||
$asConsArray['constOpe'][$sTimeField] = "<=";
|
||||
$sConsSql .= " AND ".$sTimeField." <= '".$asActPeriod['to']."'";
|
||||
break;
|
||||
case self::POST_TABLE:
|
||||
$asConsArray['constraint'][$sTimeField] = $asActPeriod['to'];
|
||||
$asConsArray['constOpe'][$sTimeField] = "<=";
|
||||
$sConsSql .= " AND ".$sTimeField." <= '".$asActPeriod['to']."'";
|
||||
break;
|
||||
}
|
||||
|
||||
//Sort by key
|
||||
if($bHistoMode) ksort($asFeeds); //Old first
|
||||
else krsort($asFeeds); //New first
|
||||
return ($sReturnFormat=='array')?$asConsArray:$sConsSql;
|
||||
}
|
||||
|
||||
//Split chunks
|
||||
$asFeeds = array_slice($asFeeds, $iChunk * self::FEED_CHUNK_SIZE, self::FEED_CHUNK_SIZE);
|
||||
public function getNewFeed($iRefIdFirst) {
|
||||
$asResult = array();
|
||||
|
||||
return $bInternal?$asFeeds:self::getJsonResult(true, '', array('ref_id'=>$iRefTimePoint, 'feed' => $asFeeds));
|
||||
if($this->oProject->getMode() != Project::MODE_HISTO) {
|
||||
$asMessageIds = $asMediaIds = array();
|
||||
|
||||
//New Feed Items
|
||||
$asResult = $this->getFeed($iRefIdFirst, ">", "DESC");
|
||||
foreach($asResult['feed'] as $asItem) {
|
||||
switch($asItem['type']) {
|
||||
case 'message':
|
||||
$asMessageIds[] = $asItem['id'];
|
||||
break;
|
||||
case 'media':
|
||||
$asMediaIds[] = $asItem['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//New Markers
|
||||
$asMarkers = $this->getMarkers(
|
||||
empty($asMessageIds)?array(0):$asMessageIds,
|
||||
empty($asMediaIds)?array(0):$asMediaIds,
|
||||
true
|
||||
);
|
||||
|
||||
$asResult = array_merge($asResult, $asMarkers);
|
||||
}
|
||||
|
||||
return self::getJsonResult(true, '', $asResult);
|
||||
}
|
||||
|
||||
public function getNextFeed($iRefIdLast=0, $bInternal=false) {
|
||||
if($this->oProject->getMode() == Project::MODE_HISTO) {
|
||||
$sDirection = ">";
|
||||
$sSort = "ASC";
|
||||
}
|
||||
else {
|
||||
$sDirection = "<";
|
||||
$sSort = "DESC";
|
||||
}
|
||||
$asResult = $this->getFeed($iRefIdLast, $sDirection, $sSort);
|
||||
return $bInternal?$asResult['feed']:self::getJsonResult(true, '', $asResult);
|
||||
}
|
||||
|
||||
public function getFeed($iRefId=0, $sDirection, $sSort) {
|
||||
$this->oDb->cleanSql($iRefId);
|
||||
$this->oDb->cleanSql($sDirection);
|
||||
$this->oDb->cleanSql($sSort);
|
||||
|
||||
$sMediaRefField = 'posted_on';
|
||||
$sQuery = implode(" ", array(
|
||||
"SELECT type, id, ref",
|
||||
"FROM (",
|
||||
"SELECT id_project, id_message AS id, 'message' AS type, CONCAT(UNIX_TIMESTAMP(site_time), '.0', id_message) AS ref",
|
||||
"FROM ".Feed::MSG_TABLE,
|
||||
"INNER JOIN feeds USING(id_feed)",
|
||||
$this->getFeedConstraints(Feed::MSG_TABLE, 'site_time', 'sql'),
|
||||
"UNION",
|
||||
"SELECT id_project, id_media AS id, 'media' AS type, CONCAT(UNIX_TIMESTAMP(".$sMediaRefField."), '.1', id_media) AS ref",
|
||||
"FROM ".Media::MEDIA_TABLE,
|
||||
$this->getFeedConstraints(Media::MEDIA_TABLE, $sMediaRefField, 'sql'),
|
||||
"UNION",
|
||||
"SELECT id_project, id_post AS id, 'post' AS type, CONCAT(UNIX_TIMESTAMP(site_time), '.2', id_post) AS ref",
|
||||
"FROM ".self::POST_TABLE,
|
||||
$this->getFeedConstraints(self::POST_TABLE, 'site_time', 'sql'),
|
||||
") AS items",
|
||||
($iRefId > 0)?("WHERE ref ".$sDirection." ".$iRefId):"",
|
||||
"ORDER BY ref ".$sSort,
|
||||
"LIMIT ".self::FEED_CHUNK_SIZE
|
||||
));
|
||||
|
||||
//Get new chunk
|
||||
$asItems = $this->oDb->getArrayQuery($sQuery, true);
|
||||
|
||||
//Update Reference Point with latest/earliest value
|
||||
$iRefIdFirst = $iRefIdLast = 0;
|
||||
if(!empty($asItems)) {
|
||||
$iRefIdLast = end($asItems)['ref'];
|
||||
$iRefIdFirst = reset($asItems)['ref'];
|
||||
}
|
||||
|
||||
//Sort Table IDs by type & Get attributes
|
||||
foreach($asItems as $asItem) {
|
||||
$asFeedIds[$asItem['type']][$asItem['id']] = $asItem;
|
||||
}
|
||||
$asFeedAttrs = array(
|
||||
'message' => $this->getSpotMessages(array_keys($asFeedIds['message'])),
|
||||
'media' => $this->getMedias($sMediaRefField, array_keys($asFeedIds['media'])),
|
||||
'post' => $this->getPosts(array_keys($asFeedIds['post']))
|
||||
);
|
||||
|
||||
//Replace Array Key with Item ID
|
||||
foreach($asFeedAttrs as $sType=>$asFeedAttr) {
|
||||
foreach($asFeedAttr as $asFeed) {
|
||||
$asFeeds[$sType][$asFeed['id_'.$sType]] = $asFeed;
|
||||
}
|
||||
}
|
||||
|
||||
//Assign
|
||||
foreach($asItems as &$asItem) {
|
||||
$asItem = array_merge($asFeeds[$asItem['type']][$asItem['id']], $asItem);
|
||||
}
|
||||
|
||||
return array('ref_id_last'=>$iRefIdLast, 'ref_id_first'=>$iRefIdFirst, 'sort'=>$sSort, 'feed'=>$asItems);
|
||||
}
|
||||
|
||||
public function syncMedias() {
|
||||
|
||||
Reference in New Issue
Block a user