コード例 #1
0
 public function search($options)
 {
     // we query the listings table which is sharded by month.
     // because it is sharded by month, we have to do a few more tricks
     // to get the data-set we want.
     // first, we try to narrow it down as much as possible by the criteria specified.
     $clauses = array();
     // are we looking for auctions that are still in progress or already finished?
     $clauses[] = $this->db->prep('closed = ?', $options->closed ? 1 : 0);
     // if we have a specific item id we are looking for, query for that.
     if (isset($options->item_id)) {
         $clauses[] = $this->db->prep('item_id IN (%i)', $options->item_id);
     }
     // do we know the seller?
     if (isset($options->seller)) {
         $clauses[] = $this->db->prep('seller IN (%i)', $options->seller);
     }
     // sometimes, rarely we are looking for an auction purchased by a specific buyer.
     // obviously these auctions are already closed. should i sanity check the closed param?
     if (isset($options->buyer)) {
         $clauses[] = $this->db->prep('buyer IN (%i)', $options->buyer);
     }
     // we can narrow by the person who is currently the leading bidder. can't search by past
     // bidders since that is more of a bid history search.
     // haven't written that yet.
     if (isset($options->bidder)) {
         $clauses[] = $this->db->prep('bidder IN (%i)', $options->bidder);
     }
     // are we looking for a bid-only auction?
     if ($options->only == 'bid') {
         $clauses[] = 'price = 0';
     }
     // how about a buy-now only auction?
     if ($options->only == 'buy') {
         $clauses[] = 'step = 0';
     }
     // look for items only above a given price range.
     if ($options->floor && ctype_digit($options->floor)) {
         $clauses[] = $this->db->prep('pricesort >= %i', $options->floor);
     }
     // look for items only below a given price range.
     if ($options->ceiling && ctype_digit($options->ceiling)) {
         $clauses[] = $this->db->prep('pricesort <= %i', $options->ceiling);
     }
     // how do we want the result set sorted?
     $sort = $options->sort;
     $order = '';
     switch ($sort) {
         case 'low_price':
             $order = 'pricesort ASC';
             break;
         case 'high_price':
             $order = 'pricesort DESC';
             break;
         case 'just_added':
             $order = 'created DESC';
             break;
         case 'expires_soon':
             $clauses[] = $this->db->prep('expires > %i', Souk\Util::now());
             $order = 'expires ASC';
             break;
         case 'expires_soon_delay':
             $clauses[] = $this->db->prep('expires > %i', Souk\Util::now() + Souk\UTIL::MIN_EXPIRE);
             $order = 'expires ASC';
             break;
         default:
             $key = $row['expires'] . '.' . $id;
             break;
     }
     $ds = Souk\Util::dateshard();
     // start with the shard a few weeks out from now, which is where the new listings are.
     $ds->setTimestamp(Souk\Util::now() + Souk\UTIL::MAX_EXPIRE);
     // if the auction is still active, we don't have to search the really old shards.
     // stop at the shard for this week.
     if (!$options->closed) {
         $ds->setCutoff(1);
     }
     // start looping throw the shards and querying.
     $ids = array();
     $where = $clauses ? 'WHERE ' . implode(' AND ', $clauses) : '';
     if ($order) {
         $order = ' ORDER BY ' . $order;
     }
     // don't return more rows than the hard search limit imposed by souk.
     // after more than about 1000 rows, more results become meaningless. who paginates through all of that?
     // need them to somehow narrow their search more.
     $limit = 'LIMIT ' . Souk\Util::SEARCH_LIMIT;
     $ds = Souk\Util::dateshard();
     foreach ($ds as $shard) {
         $table = $this->table($shard);
         if (\Gaia\Souk\Storage::isAutoSchemaEnabled()) {
             $this->create($table);
         }
         $sql = "SELECT row_id, pricesort, created, expires FROM {$table} {$where} {$order} {$limit}";
         //print "\n" . $sql;
         // run the query
         $rs = $this->execute($sql);
         //print_r( $rs );
         // pull out all the rows matched by the query.
         // we are making the key of the id list contain the
         // value of what we sort by, so we can do a keysort later, and order the
         // result in php since we have to span many shards.
         while ($row = $rs->fetch()) {
             $id = Souk\Util::composeId($shard, $row['row_id']);
             switch ($sort) {
                 case 'low_price':
                 case 'high_price':
                     $key = $row['pricesort'] . '.' . $id;
                     break;
                 case 'just_added':
                     $key = $row['created'] . '.' . $id;
                     break;
                 case 'expires_soon':
                 case 'expires_soon_delay':
                 default:
                     $key = $row['expires'] . '.' . $id;
                     break;
             }
             $ids[$key] = $id;
         }
         $rs->free();
     }
     // now that we are all done fetching the rows, sort.
     switch ($sort) {
         case 'low_price':
         case 'expires_soon':
         case 'expires_soon_delay':
             ksort($ids, SORT_NUMERIC);
             break;
         default:
             krsort($ids, SORT_NUMERIC);
             break;
     }
     // since we queried many shards we could potentially have quite a few more
     // ids than the max limit. slice off only the top most rows.
     // those are the ones we care about.
     // we only need the other values so we can sort in php across all the shards.
     // a little bit inefficient, but it is just a list of numbers, and we are gonna
     // cache it for a long time in the caching layer.
     return array_values(array_slice($ids, 0, Souk\Util::SEARCH_LIMIT));
 }