/** * Search for routes going from from to to * @return array * @param string $from * @param string $to * @param mixed $time */ public function search($from, $to, $time = false, $weekday = false, $limit = 5, $offset = 0, $timer = false) { if ($timer) { $timer->tick("search", "Entering RouteSearch::search"); } if (!$weekday) { $weekday = (int) date("w"); } if ($weekday == 0) { // sunday, fix it $weekday = 7; } $cacheKey = $from . $to . $time . $weekday; $memcache = new Memcache(); $memcache->connect('localhost', 11211); $hits = $memcache->get($cacheKey); if ($timer) { $timer->tick("search", "Fetched from memcache"); } if ($hits) { $hits = unserialize($hits); } if (!is_array($hits) || count($hits) == 0) { $hits = array(); /** * First find all buses having both stops in their path, kinda nice */ if ($timer) { $timer->tick("search", "No cache"); } $db = Config::getDb(); $start = toLower($from); $end = toLower($to); if ($timer) { $timer->tick("search", "Lowercased input"); } $buses = $db->routes->find(array('search' => array('$all' => array($start, $end)))); if ($timer) { $timer->tick("search", "Search routes"); } // Find some necessary data if (!$time) { $time = date("Hi"); } //"0700"; $minutes = (int) substr($time, -2); $hours = (int) substr($time, 0, -2); $searchFilters = array(); $hitCount = 0; $timeSort = array(); while ($route = $buses->getNext()) { // Iterate over stops and find the $startStop = null; $endStop = null; foreach ($route['stops'] as $stop) { if (!$startStop && toLower($stop['name']) == $start) { $startStop = $stop; } elseif ($startStop && !$endStop && toLower($stop['name']) == $end) { $endStop = $stop; } } if ($startStop && $endStop) { /** * By now we have tested that we have both stops * and in the correct order for this route * Its time to generate the query to find departures */ $minuteMark = $minutes - (int) $startStop['timeOffset']; $latestStartTime = date("Hi", mktime($hours, $minuteMark)); $startOffset = (int) $startStop['timeOffset']; $endOffset = (int) $endStop['timeOffset']; $runningTime = $endOffset - $startOffset; $filters = array('route' => $route['_id'], 'time' => array('$gte' => (int) $latestStartTime), 'days' => $weekday); $departuresForRoute = $db->departures->find($filters)->sort(array('time' => 1))->limit(15); /** * Loop over each departure and calculate some times */ while ($dep = $departuresForRoute->getNext()) { $arrivalTime = (int) $dep['time']; $startTime = Config::timeAdd($arrivalTime, $startOffset); $startM = substr($startTime, -2); $startH = substr($startTime, 0, -2); $waitTime = ($startH - $hours) * 60 + ($startM - $minutes); $arrivalTime = Config::timeAdd(str_replace(":", "", $startTime), $runningTime, "H:i"); while ($waitTime < 0) { $waitTime += 1440; } $timeSort[] = $waitTime; // Wait time should be arrival time minus specified search time $hits[] = array('id' => $route['num'], 'name' => $route['dest'], 'runningTime' => $runningTime, 'startTime' => $startTime, 'wait' => $waitTime, 'arrivalTime' => $arrivalTime, 'arrivalSpan' => $runningTime + $waitTime); } } } if ($timer) { $timer->tick("search", "Searched departures"); } array_multisort($timeSort, SORT_ASC, $hits); $memcache->set($cacheKey, serialize($hits), false, 120); } $this->count = count($hits); return array_slice($hits, $offset, $limit); }