Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

object-manager.inc.php

Go to the documentation of this file.
00001 <?php
00013 abstract class ObjectManager extends MyModule
00014 {
00018     protected $table;
00019 
00023     public $objectType;
00024     
00028     public $object;
00029     
00033     public $useRss = true;
00034 
00038     public $numResults;
00039 
00043     public $numRows;
00044     
00048     protected $query;
00049 
00053     private $resultPage = 0;
00054 
00058     private $startRow = 0;
00059 
00063     private $endRow = 0;
00064 
00068     private $searchParams = array();
00069 
00073     public static $cacheSearchCount = true;
00074 
00078     public static $cacheSearchQuery = false;
00079 
00083     public static $searchCacheLife = 300;
00084     
00088     public $useFullTextSearch = true;
00089     
00096     function __construct($objectType, $table = null, $numRows = 15)
00097     {
00098         //give it to me, daddy.
00099         parent::__construct();
00100 
00101         //set and create our object.
00102         $this->objectType = $objectType;
00103         $this->object = $this->factory();
00104         
00105         //if we didnt get a table, get it from the object class
00106         if ($table === null)
00107         {
00108             $this->table = $object->tableName;
00109             $this->english = $this->object->english;
00110         }
00111         else
00112             $this->table = $table;
00113 
00114         //set our numrows.
00115         $this->numRows = $numRows;
00116     }
00117 
00124     function factory($data = null)
00125     {
00126         return new $this->objectType($data);
00127     }
00128 
00134     function getSortOptionXml()
00135     {
00136         $rval = "";
00137 
00138         //get our array and make the xml;
00139         $sort = $this->getSortFieldsArray();
00140         foreach ($sort AS $key => $val)
00141             $rval .= "<option value=\"$key\" desc=\"$val\"/>\n";
00142 
00143         return $rval;
00144     }
00145 
00152     protected function getSortFieldsArray()
00153     {
00154         $sort = array();
00155         
00156         if ($this->object->hasField('add_date'))
00157             $sort['add_date'] = 'sort by date added';
00158             
00159         if ($this->object->hasField('edit_date'))
00160             $sort['edit_date'] = 'sort by date last edited/modified';
00161         
00162         if ($this->object->hasField('comment_count'))
00163             $sort['comment_count'] = 'sort by number of comments';
00164         
00165         if ($this->object->hasField('user_id'))
00166             $sort['user_id'] = 'sort by user id';
00167         
00168         $sort['id'] = 'sort the results by id';
00169         $sort['random'] = 'sort the results randomly';
00170 
00171         //do we want to sort by fulltext?
00172         if ($this->useFullTextSearch)
00173             $sort['relevancy'] = 'sort by fulltext relevancy';
00174     
00175         return $sort;
00176     }
00177 
00183     public function delete($rs)
00184     {
00185         if (count($rs))
00186             foreach ($rs AS $ob)
00187                 $ob->delete();
00188     }
00189 
00195     public function getPagesXml()
00196     {
00197         //obviously we want the base xml.
00198         $xml = parent::getPagesXml();
00199 
00200         //main pages are rss and search.
00201         $xml .= $this->getSearchPageXml();
00202         
00203         return $xml;
00204     }
00205     
00211     public function getSearchPageXml()
00212     {
00213         $xml = "\t<page name=\"search\" desc=\"search for {$this->english}s from the manager.\">\n";
00214         $xml .= $this->getSearchParamXml();
00215         $xml .= "\t</page>\n";
00216 
00217         return $xml;
00218     }
00219     
00225     public function getSearchParamXml()
00226     {
00227         //init
00228         $xml = '';
00229         
00230         //just get a set of objects
00231         $xml .= "\t\t<param name=\"ids\" desc=\"a comma separated list of ids you want.\" />\n";
00232 
00233         if ($this->useFullTextSearch)
00234             $xml .= "\t\t<param name=\"query\" desc=\"a string to query the database against.\" />\n";
00235         
00236         if (count($this->object->likeFields))
00237             $xml .= "\t\t<param name=\"like\" desc=\"a string to match against with LIKE '%param%' format.\" />\n";
00238         
00239         //any field specific stuff...
00240         $fields = $this->object->getDbFields();
00241         
00242         //allow to search for things with this parent.
00243         if (is_array($fields['parent_id']))
00244             $xml .= "\t\t<param name=\"parent_id\" desc=\"the id of the parent.\" is_searchable=\"true\" type=\"int\"/>\n";
00245         
00246         //or search on a user.
00247         if (isset($fields['user_id']))
00248             $xml .= "\t\t<param name=\"user_id\" desc=\"the id of the user who created the {$this->object->english}\" is_searchable=\"true\" type=\"int\"/>\n";
00249         
00250         //do we give them lat/lon access?
00251         if (isset($this->object->useLatLng))
00252         {
00253             if (isset($fields['lat']))
00254             {
00255                 $xml .= "\t\t<param name=\"northlat\" type=\"float\" is_searchable=\"true\"/>\n";
00256                 $xml .= "\t\t<param name=\"southlat\" type=\"float\" is_searchable=\"true\"/>\n";
00257             }
00258 
00259             if (isset($fields['lon']))
00260             {
00261                 $xml .= "\t\t<param name=\"eastlon\" type=\"float\" is_searchable=\"true\"/>\n";
00262                 $xml .= "\t\t<param name=\"westlon\" type=\"float\" is_searchable=\"true\"/>\n";
00263             }
00264         }
00265 
00266         //add date is good.
00267         if (isset($fields['add_date']))
00268         {
00269             $xml .= "\t\t<param name=\"add_date_start\" desc=\"start date for your query, eg 10-22-1983. it will get all the {$this->object->english}s added on or after it\" regex=\"/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}(isset([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}))?$/\"/>\n";
00270             $xml .= "\t\t<param name=\"add_date_stop\" desc=\"end date for your query. it will get all the {$this->object->english}s added on or before it.  used with start date you can specify a range.\"  regex=\"/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}(isset([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}))?$/\"/>\n";
00271         }
00272 
00273         //as is edit date
00274         if (isset($fields['edit_date']))
00275         {
00276             $xml .= "\t\t<param name=\"edit_date_start\" desc=\"start date for your query, eg 10-22-1983. it will get all the {$this->object->english}s edited on or after it.\" regex=\"/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}(isset([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}))?$/\"/>\n";
00277             $xml .= "\t\t<param name=\"edit_date_stop\" desc=\"end date for your query. it will get all the {$this->object->english} edited on or before it.  used with start date you can specify a range\" regex=\"/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}(isset([0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}))?$/\"/>\n";
00278         }
00279         
00280         //heres our sorting type stuff
00281         $xml .= "\t\t<param name=\"result_page\" desc=\"the page number you want. defaults to 0\" type=\"int\"/>\n";
00282         $xml .= "\t\t<param name=\"num_results\" desc=\"the number of results per page\" type=\"int\"/>\n";
00283         $xml .= "\t\t<param name=\"sort\" desc=\"the parameter you want to sort by.\">\n";
00284         $xml .= $this->getSortOptionXml();
00285         $xml .= "\t\t</param>\n";
00286         $xml .= "\t\t<param name=\"order\" desc=\"how you want to order the objects\">\n";
00287         $xml .= "\t\t\t<option value=\"asc\" desc=\"descending order... highest to lowest\" />\n";
00288         $xml .= "\t\t\t<option value=\"desc\" desc=\"ascending order... lowest to highest\" />\n";
00289         $xml .= "\t\t</param>\n";
00290 
00291         //what type of output do we want?
00292         $xml .= $this->getSearchOutputXml();
00293 
00294         return $xml;
00295     }
00296 
00302     protected function getSearchOutputXml()
00303     {
00304         return <<<XML
00305             <param name="output">
00306                 <option value="html" description="plain HTML output"/>
00307                 <option value="xml" description="data as structured xml"/>
00308                 <option value="rss" description="data as an rss feed"/>
00309                 <option value="json" description="data in JSON format"/>
00310                 <option value="php" description="data in PHP serialized() format"/>
00311                 <option value="autocomplete" description="html compatible with del.icio.us Ajax.Autocompleter"/>
00312             </param>
00313 XML;
00314     }
00315         
00319     function initMainPage()
00320     {
00321         Util::redirect($this->getUrl(".search"));
00322     }
00323 
00327     function initSearchPage()
00328     {
00329         //set our max results param
00330         if((int)$this->params('num_results') > 200)
00331             $this->setParam('num_results', 200);
00332 
00333         //make sure we can do fulltext search...
00334         if ($this->params('query') && !count($this->object->fullTextFields))
00335             throw new PageError('Oops, there are no fulltext fields to search in ' . get_class($this->object));
00336     
00337         $this->initSearch($this->params());
00338 
00339         //titles are nice =)
00340         $this->pageTitle = ucfirst($this->object->english) . " Search";
00341     
00342         //what output do we want?
00343         $this->initSearchPageOutput();
00344     }
00345 
00349     protected function initSearchPageOutput()
00350     {
00351         //how do you want it?  how does it feel?
00352         $output = $this->params('output');
00353         switch ($output)
00354         {
00355             case 'rss':
00356                 $this->initRSSOutput();
00357                 break;
00358                 
00359             case 'json':
00360                 $this->initJSONOutput();
00361                 break;
00362                 
00363             case 'php':
00364                 $this->initPHPOutput();
00365                 break;
00366 
00367             case 'xml':
00368                 $this->initXMLOutput();
00369                 break;
00370 
00371             case 'autocomplete':
00372                 $this->initAutocompleteOutput();
00373                 break;
00374 
00375             case 'html':
00376             default:
00377                 $this->initHTMLOutput();
00378                 break;
00379         }
00380     }
00381     
00385     protected function initPHPOutput()
00386     {
00387         $this->setTemplate(new BlankTemplate());
00388     }
00389     
00393     protected function initJSONOutput()
00394     {
00395         $this->setTemplate(new BlankTemplate());
00396     }
00397     
00401     protected function initRSSOutput()
00402     {
00403         $this->setTemplate(new BlankTemplate());
00404     }
00405 
00409     protected function initXMLOutput()
00410     {
00411         //we want the xml template
00412         $this->setTemplate(new XMLTemplate());
00413     
00414         //make sure we have the serializer class
00415         if (!class_exists('XML_Serializer'))
00416             throw new PageError('BaseJumper xml data export depends on Pear::XML_Serializer to function.');
00417     }
00418 
00424     protected function initAutocompleteOutput()
00425     {
00426         //we want the xml template
00427         $this->setTemplate(new BlankTemplate());
00428     }
00429 
00433     protected function initHTMLOutput()
00434     {
00435     }
00436 
00440     public function drawSearchPage()
00441     {
00442         //what is our output type?
00443         $output = $this->params('output');
00444         if (!$output)
00445             $output = 'html';
00446 
00447         //now, how do we draw it.
00448         switch ($output)
00449         {
00450             case 'rss':
00451                 $this->drawRSSOutput(); 
00452                 break;
00453 
00454             case 'json':
00455                 $this->drawJSONOutput();    
00456 
00457                 break;
00458 
00459             case 'php':
00460                 $this->drawPHPOutput(); 
00461                 break;
00462 
00463             case 'xml':
00464                 $this->drawXMLOutput(); 
00465                 break;
00466 
00467             case 'autocomplete':
00468                 $this->drawAutocompleteOutput();    
00469                 break;
00470 
00471             case 'html':
00472             default:
00473                 $this->drawHTMLOutput();    
00474                 break;
00475         }
00476     }
00477 
00481     protected function drawHTMLOutput()
00482     {
00483         //get our results
00484         $rs = $this->getSearchResult();
00485         
00486         //draw our search form.
00487         if ($this->useFullTextSearch)
00488             $this->drawSearchForm();
00489 
00490         //now draw them.
00491         if (count($rs))
00492             $this->drawResults($rs);
00493         else
00494             $this->drawNoResults();
00495     }
00496     
00500     protected function drawRssOutput()
00501     {
00502         $feed = $this->generateRss($this->params());
00503         $feed->saveFeed('RSS2.0', '', true);
00504     }
00505 
00509     protected function drawJSONOutput()
00510     {
00511         $data = $this->getPublicData($this->params());
00512 
00513         echo JSON::encode($data);
00514     }
00515     
00519     protected function drawXMLOutput()
00520     {
00521         $options = array(
00522             "indent"         => "\t",
00523             "linebreak"      => "\n",
00524             "typeHints"      => false,
00525             "addDecl"        => false,
00526             "defaultTagName" => get_class($this->object),
00527             "rootName" => "BaseJumper"
00528         );
00529         //setup our serializer
00530         $serial = new XML_Serializer($options);
00531         
00532         //serialize our data.
00533         $data = $this->getPublicData($this->params());
00534         if ($serial->serialize($data))
00535             echo $serial->getSerializedData();
00536     }
00537     
00541     protected function drawPHPOutput()
00542     {
00543         echo serialize($this->getPublicData($this->params()));
00544     }
00545 
00552     protected function drawAutocompleteOutput()
00553     {
00554         //get our results
00555         $rs = $this->getSearchResult();
00556 
00557         //draw them!
00558         echo "<ul>";
00559         foreach ($rs AS $ob)
00560             echo "\t" . $ob->getAutoCompleteRow();
00561         echo "</ul>";
00562     }
00563     
00569     function initSearch($params)
00570     {
00571         //fix slashies!
00572         foreach ($params AS $key => $val)
00573             $params[$key] = dbEscape($val);
00574         
00575         //save our parameters.
00576         $this->searchParams = $params;
00577         
00578         //did we have a parameter for number of results.
00579         if ($params['num_results'])
00580             $this->numRows = (int)$params['num_results'];
00581         
00582         //finally set the query.
00583         $this->query = $this->getSearchQuery($params);
00584     }
00585 
00593     public function getSearchQuery($params)
00594     {
00595         //our basic search
00596         $select = $this->getSearchSelect($params);
00597         $countSel = $this->getSearchCountSelect($params);
00598         $from = $this->getSearchFrom($params);
00599         $where = $this->getSearchWhere($params);
00600         $group = $this->getSearchGroupBy($params);
00601         $order = $this->getSearchOrder($params);
00602 
00603         //find out how many results we got.
00604         $countSql = $countSel . $from . $where;
00605         
00606         //do we look it up?
00607         if (self::$cacheSearchCount)
00608             $countAr = CacheBot::get('BaseJumper:count:' . sha1($countSql), self::$searchCacheLife);
00609 
00610         //no cache?  no problem.
00611         if (!$countAr)
00612         {
00613             $countAr = dbFetchAssoc(dbQuery($countSql));
00614 
00615             //do we cache it?
00616             if (self::$cacheSearchCount)
00617                 CacheBot::set('BaseJumper:count:' . sha1($countSql), $countAr, self::$searchCacheLife);
00618         }
00619         
00620         //get the count.
00621         $this->numResults = $countAr['count'];
00622 
00623         //get our limit stuff...
00624         $this->resultPage = abs((int)$params['result_page']);
00625 
00626         //do a bit of error checking on the bounds of the result.
00627         if ($this->resultPage * $this->numRows > $this->numResults)
00628             throw new PageError('We do not have that many ' . $this->english . "s.");
00629     
00630         //add our limit in here...
00631         $limit = " LIMIT " . $this->resultPage * $this->numRows . ", $this->numRows";
00632 
00633         //give it back to the man.
00634         return $select . $from . $where . $group . $order . $limit;
00635     }
00636     
00642     protected function getSearchSelect($params = array())
00643     {
00644         $sql = "SELECT o.id\n";
00645 
00646         //add our fulltext relevancy in.
00647         if ($this->useFullTextSearch && $params['query'])
00648             $sql .= ", " . $this->getFullTextSearch($params['query']) . " AS relevancy\n";
00649 
00650         return $sql;
00651     }
00652     
00658     protected function getSearchCountSelect($params = array())
00659     {
00660         return "SELECT count(distinct(o.id)) AS count\n";
00661     }
00662 
00668     protected function getSearchFrom($params = array())
00669     {
00670         $from = "FROM {$this->object->tableName} o \n";
00671 
00672         return $from; 
00673     }
00674 
00680     protected function getSearchWhere($params = array())
00681     {
00682         global $me;
00683 
00684         $where = "WHERE 1 ";
00685 
00686         //our xml configuration.
00687         $xml = $this->parseModuleXml();
00688         $rs = $xml->xpath("//page[@name='search']");
00689 
00690         //get our where stuff...
00691         if (is_object($rs[0]->param[0]))
00692         {
00693             //loop thru all our params in our object.
00694             foreach ($rs[0]->param AS $param)
00695             {
00696                 //get that param.
00697                 $pName = (string)$param['name'];
00698                 $pVal = $params[$pName];
00699 
00700                 //did we get one?
00701                 if ($pVal)
00702                 {
00703                     //listing of ids?
00704                     if ($pName == 'ids')
00705                         $where .= " AND o.id IN ($pVal) ";
00706 
00707                     //by user id.
00708                     if ($pName == 'user_id')
00709                         $where .= " AND o.user_id = '$pVal' ";
00710                     
00711                     //heres our date stuff...
00712                     else if ($pName == 'add_date_start')
00713                         $where .= " AND o.add_date >= '$pVal' ";
00714                     else if ($pName == 'add_date_stop')
00715                         $where .= " AND o.add_date <= '$pVal' ";
00716                     else if ($pName == 'edit_date_start')
00717                         $where .= " AND o.edit_date >= '$pVal' ";
00718                     else if ($pName == 'edit_date_stop')
00719                         $where .= " AND o.edit_date <= '$pVal' ";
00720                     
00721                     //how about location?
00722                     else if ($pName == 'northlat')
00723                         $where .= " AND o.lat <= '$pVal' AND o.lat != 0";
00724                     else if ($pName == 'southlat')
00725                         $where .= " AND o.lat >= '$pVal'";
00726                     else if ($pName == 'eastlon')
00727                         $where .= " AND o.lon <= '$pVal' AND o.lon != 0";
00728                     else if ($pName == 'westlon')
00729                         $where .= " AND o.lon >= '$pVal'";
00730                     
00731                     //if it was passed and is searchable... try it.
00732                     else if ($pVal && (string)$param['is_searchable'] == 'true')
00733                         $where .= " AND o.$pName = '$pVal'";
00734                 }
00735             }
00736         }
00737 
00738         //add our privacy where.
00739         $where .= $this->getPrivacyWhere($params);
00740         
00741         //what about our fulltext search
00742         if ($this->useFullTextSearch && $params['query'] && count($this->object->fullTextFields))
00743             $where .= " AND " . $this->getFullTextSearch($params['query']);
00744 
00745         //add our like search in...
00746         $where .= $this->getLikeSearch($params['like']);
00747         
00748         return $where;
00749     }
00750 
00758     protected function getFullTextSearch($query)
00759     {
00760         //if we can use it, do it.
00761         if ($this->useFullTextSearch && count($this->object->fullTextFields))
00762             return "MATCH (" . implode(',', $this->object->fullTextFields) . ") AGAINST ('$query')";
00763     
00764         return '';
00765     }
00766 
00776     protected function getLikeSearch($query)
00777     {
00778         if (count($this->object->likeFields) && $query)
00779         {
00780             foreach ($this->object->likeFields AS $field)
00781                 $likes[] = "o.$field LIKE '%$query%'";
00782             
00783             return " AND (" . implode(" OR ", $likes) . ") ";
00784         }
00785     }
00786 
00792     protected function getSearchGroupBy($params = array())
00793     {
00794             return '';
00795     }
00796 
00802     protected function getPrivacyWhere($params = array())
00803     {
00804     }
00805 
00811     protected function getSearchOrder($params = array())
00812     {
00813         //get our sort...
00814         $sortVar = $params['sort'];
00815         $order = $params['order'];
00816 
00817         //if we dont have order and sort... add date desc!
00818         if (!$order && !$sortVar)
00819             $order = 'DESC';
00820         
00821         if ($sortVar == 'random')
00822             $sort = " ORDER BY rand() ";
00823         else if ($sortVar)
00824         {
00825             if ($this->object->hasField($sortVar))
00826                 $sort = " ORDER BY o.$sortVar $order";
00827             else
00828                 $sort = " ORDER BY $sortVar $order";
00829         }
00830         //add our fulltext order if we can
00831         else if ($this->useFullTextSearch && $params['query'])
00832             $sort = " ORDER BY relevancy $order";
00833         else if ($this->object->hasField('add_date'))
00834             $sort = " ORDER BY o.add_date $order";
00835         else
00836             $sort = '';
00837 
00838         return $sort;
00839     }
00840 
00844     function drawPagination()
00845     {
00846         echo "<div id=\"pagination\">\n";
00847         echo $this->getPaginationStats();
00848         echo $this->getPaginationNav();
00849         echo "</div>\n";
00850     }
00851 
00857     function getPaginationStats()
00858     {
00859         return "Showing $this->startRow - $this->endRow of $this->numResults {$this->english}s. ";
00860     } 
00861     
00867     function getPaginationNav()
00868     {
00869         $s = '';
00870         //do we have any pages to show?
00871         if ($this->hasPage($this->resultPage-1) || $this->hasPage($this->resultPage+1))
00872         {
00873             $s = "Page: ";
00874         
00875             //get our previous
00876             if ($this->resultPage >= 1)
00877             {
00878                 $s .= $this->getPaginationFirst();
00879                 $s .= " ";
00880                 $s .= $this->getPaginationPrev();
00881             }
00882 
00883             //show the nearest 5 pages.
00884             for ($i = $this->resultPage - 5; $i <= $this->resultPage + 5; $i++)
00885             {
00886                 if ($i == $this->resultPage)
00887                     $s .= " <b>" . ($this->resultPage + 1) . "</b> ";
00888                 else if ($this->hasPage($i))
00889                     $s .= " " . $this->getPaginationLink($i) . " ";
00890             }
00891             
00892             //show our next link
00893             if ($this->endRow < $this->numResults)
00894             {
00895                 $s .= $this->getPaginationNext();
00896                 $s .= " ";
00897                 $s .= $this->getPaginationLast();
00898             }
00899         }
00900 
00901         return $s;
00902     }
00903 
00911     function getPaginationUrl($page)
00912     {
00913         //update our parameters
00914         $params = $this->searchParams;
00915         $params['page'] = 'search';
00916         $params['result_page'] = $page;
00917         
00918         //get the link.
00919         return $this->getUrl($params);
00920     }
00921 
00930     function getPaginationLink($page, $link = null)
00931     {
00932         $url = $this->getPaginationUrl($page);
00933 
00934         //link to our page if none.
00935         if ($link === null)
00936             $link = $page + 1;
00937         
00938         //get our link
00939         return "<a href=\"$url\">$link</a>";
00940     }
00941 
00947     function getPaginationFirst()
00948     {
00949         return $this->getPaginationLink(0, '<< first');
00950     }
00951     
00957     function getPaginationPrev()
00958     {
00959         return $this->getPaginationLink($this->resultPage - 1, '< prev');
00960     }
00961 
00967     function getPaginationNext()
00968     { 
00969         return $this->getPaginationLink($this->resultPage + 1, 'next >');
00970     }
00971     
00977     function getPaginationLast()
00978     { 
00979         $page = floor($this->numResults / $this->numRows); 
00980 
00981         return $this->getPaginationLink($page, 'last >>');
00982     }
00983     
00991     function hasPage($page)
00992     {
00993         //negative pages == barf
00994         if ($page < 0)
00995             return false;
00996         
00997         //if we show are page, are there still results?
00998         return (($this->numResults - ($page * $this->numRows)) > 0);
00999     }
01000     
01004     function calculatePagination()
01005     {
01006         $this->startRow = ($this->resultPage * $this->numRows) + 1;
01007         $this->endRow = ($this->resultPage + 1) * $this->numRows;
01008 
01009         if ($this->endRow > $this->numResults)
01010             $this->endRow = $this->numResults;
01011 
01012         if ($this->endRow == 0)
01013             $this->startRow = 0;
01014     }
01015 
01023     function getSearchResult()
01024     {
01025         //do our search.
01026         $data = $this->doObjectSearch();
01027         
01028         //load up our objects
01029         $ret = $this->loadObjects($data);
01030 
01031         //set our pagination
01032         $this->calculatePagination();
01033         
01034         return $ret;
01035     }
01036 
01045     protected function doObjectSearch()
01046     {
01047         //get our objects
01048         if (self::$cacheSearchQuery)
01049             $data = CacheBot::get('BaseJumper:search:' . sha1($this->query), self::$searchCacheLife);
01050 
01051         //no cache?  no problem.
01052         if (!is_array($data))
01053         {
01054             //init so the cache save works
01055             $data = array();
01056             
01057             //do our query.
01058             $rs = dbQuery($this->query);
01059             while ($ar = dbFetchAssoc($rs))
01060                 $data[] = $ar;
01061 
01062             //save it.
01063             if (self::$cacheSearchQuery)
01064                 CacheBot::set('BaseJumper:search:' . sha1($this->query), $data, self::$searchCacheLife);
01065         }
01066 
01067         //send it back
01068         return $data;
01069     }
01070 
01079     protected function loadObjects($data)
01080     {
01081         $objs = array();
01082         
01083         //did we get any ids?
01084         if (count($data))
01085         {
01086             //get all our cache keys
01087             $keys = array();
01088             foreach ($data AS $row)
01089                 $keys[] = $this->object->getCacheKey($row['id']);
01090             //get our data back.
01091             $data = CacheBot::get($keys, BaseObject::$objectCacheLife);
01092             foreach ($data AS $key => $val)
01093             {
01094                 $info = explode(":", $key);
01095                 $id = $info[3];
01096 
01097                 //was the cache lookup successful?
01098                 if ($val)
01099                     $objs[$id] = $this->factory($val);
01100                 //nope, have it load itself
01101                 else
01102                     $objs[$id] = $this->factory($id);
01103             }
01104         }
01105 
01106         return $objs;
01107     }
01108 
01114     function drawResults($rs)
01115     {
01116         $this->drawPagination();
01117         $this->drawRows($rs);
01118         $this->drawPagination();
01119 
01120         if ($this->useRss)
01121             $this->drawRssLink();
01122     }
01123 
01129     function drawRssLink($params = null)
01130     {
01131         $link = ".search?output=rss";
01132         
01133         //get some params
01134         if ($params === null)
01135             $params = $this->params();
01136         
01137         //add them in.
01138         $get = array();
01139         foreach ($params AS $key => $param)
01140         {
01141             if ($key != 'result_page')
01142                 $get[] = "$key=$param";
01143         }
01144         if (count($get))
01145             $link .= "&" . implode("&", $get);
01146 
01147         echo $this->getRssLink($link, "Subscribe to this {$this->object->english} feed.");
01148     }
01149 
01157     public function getRssLink($link, $text, $addFeed = true)
01158     {
01159         $txt = "<div id=\"commentRss\"><img src=\"lib/img/rss-16x16.png\"/><span>" . $this->getPlainRssLink($link, $text, $addFeed) . "</span>";
01160         $txt .= '<a href="http://news.bbc.co.uk/2/hi/help/3223484.stm"><img src="lib/img/question.gif" width="17" height="17"/></a></div>';
01161 
01162         return $txt;
01163     }
01164 
01173     public function getPlainRssLink($link, $text, $addFeed = true)
01174     {
01175         if ($addFeed)
01176             $this->addFeed($this->getUrl($link), $text);
01177 
01178         return $this->getLink($link, $text);
01179     }
01180 
01184     function drawNoResults()
01185     {
01186         echo "<p>No {$this->english}s found.</p>\n";
01187     }
01188 
01197     function drawRows($rs, $class = null)
01198     {
01199         //init our flag
01200         $flag = true;
01201         
01202         //what class is it?
01203         if ($class === null)
01204             $class = "contentRow " . strtolower($this->objectType);
01205 
01206         //did we get anything?
01207         if (count($rs))
01208         {
01209             //draw out header and loop
01210             $this->object->drawHeaderRow();
01211             foreach ($rs AS $ar)
01212             {
01213                 //can we view it?
01214                 $this->object = $ar;
01215                 if ($this->object->canView())
01216                 {
01217                     //our row flags
01218                     if ($flag)
01219                         $classRow = "onRow";
01220                     else
01221                         $classRow = "offRow";
01222                 
01223                     //draw our object
01224                     echo "\n<div class=\"$class\">\n";
01225                     echo "\n<div class=\"$classRow\">\n";
01226                     $this->object->drawRow();
01227                     echo "</div>\n";
01228                     echo "</div>\n";
01229 
01230                     //change our flag
01231                     $flag = !$flag;
01232                 }
01233             }
01234         }
01235     }
01236     
01243     function drawLines($rs, $class = null)
01244     {
01245         if ($class === null)
01246             $class = strtolower($this->objectType) . "Line";
01247         
01248 
01249         if (count($rs))
01250         {
01251             echo "<div class=\"ObjectLines\">";
01252             $this->object->drawHeaderLine();
01253             foreach ($rs AS $ar)
01254             {
01255                 $id = strtolower($this->objectType) . "Line-$ar->id";
01256                 $this->object = $ar;
01257                 if ($this->object->canView())
01258                 {
01259                     echo "\n<div id=\"$id\" class='$class'>\n";
01260                     $this->object->drawLine();
01261                     echo "</div>\n";
01262                 }
01263             }
01264             echo "</div>";
01265         }
01266     }
01267 
01276     function userSearch($userId, $limit = null)
01277     {
01278         return $this->search(array(
01279             'user_id' => $userId
01280         ), $limit);
01281     }
01282 
01291     public function search($params = array(), $limit = null)
01292     {
01293         //know your limit!
01294         if ($limit == -1)
01295             $limit = 99999999;
01296 
01297         //set it!
01298         if ($limit !== null)
01299             $params['num_results'] = $limit;
01300 
01301         //prep it!
01302         $this->initSearch($params);
01303 
01304         //now actually search
01305         return $this->getSearchResult();
01306     } 
01307     
01318     public function searchCount($params = array(), $cache = true)
01319     {
01320         //save our old cache setting.
01321         $oldCache = self::$cacheSearchCount;
01322 
01323         //set our new one.
01324         self::$cacheSearchCount = $cache;
01325         
01326         //prep it!
01327         $this->initSearch($params);
01328 
01329         //save it back in now
01330         self::$cacheSearchCount = $oldCache;
01331 
01332         //now actually search
01333         return $this->numResults;
01334     } 
01335     
01344     function generateRss($params = array(), $useCached = true)
01345     {
01346         require_once("lib/feedcreator.class.php");
01347 
01348         //create the object
01349         $rss = new UniversalFeedCreator();
01350 
01351         //do we use cached?
01352         if ($useCached)
01353             $rss->useCached(); // use cached version if age<1 hour
01354         
01355         $rss->title = $this->pageTitle . " - " . Config::get('site_name');
01356         $rss->description = $this->object->english . " feed"; 
01357         $item->descriptionHtmlSyndicated = true;
01358         
01359         //get our links...
01360         $rss->link = "http://" . Config::get('site_hostname');
01361         $rss->syndicationURL = "http://" . Config::get('site_hostname') . $_SERVER["PHP_SELF"];
01362 
01363         //do our search
01364         $rs = $this->search($params);
01365         if (count($rs))
01366         {
01367             foreach ($rs AS $ob)
01368             {
01369                 $item = $ob->getRssItem();
01370                 $rss->addItem($item);
01371             }
01372         }
01373 
01374         return $rss;
01375     }
01376 
01384     function getPublicData($params)
01385     {
01386         //get our search results.
01387         $results = array();
01388         $rs = $this->search($params);
01389         if (count($rs))
01390             foreach ($rs AS $ob)
01391                 $results[] = $ob->getPublicData();
01392     
01393         //format our data.
01394         $data = array(
01395             'runtime' => '%%BJ_RUNTIME%%',
01396             'queries' => '%%BJ_QUERIES%%',
01397             'cachehits' => '%%BJ_CACHE_HITS%%',
01398             'page' => $this->resultPage,
01399             'startrow' => $this->startRow,
01400             'endrow' => $this->endRow,
01401             'totalresults' => $this->numResults,
01402             'resultsperpage' => $this->numRows 
01403         );
01404         $data['Results'] = $results;
01405 
01406         return $data;
01407     }
01408 
01413     public function isAdmin()
01414     {
01415         return (bool)$this->object->isAdmin();
01416     }
01417     
01423     public function createSearchForm($query = null)
01424     {
01425         $form = new Form(new OneLineLayout());
01426         $form->action = $this->getUrl(".search");
01427         $form->onSubmit = "return objectManagerSearch('$form->name')";
01428 
01429         $form->add('TextField', 'query', array(
01430             'title' => '',
01431             'width' => '50%',
01432             'required' => true
01433         ));
01434         
01435         $form->addSubmit('Search ' . ucfirst(get_class($this)));
01436 
01437         //if null.. default to our param
01438         if ($query === null)
01439             $query = $this->params('query');
01440 
01441         //set our data.
01442         if ($query)
01443             $form->setData(array(
01444                 'query' => $query
01445             ));
01446 
01447         return $form;
01448     }
01449 
01453     public function drawSearchForm()
01454     {
01455         $this->needsJs('lib/js/basejumper.js');
01456 
01457         echo "<div class=\"ObjectSearch\" id=\"" . get_class($this->object) . "Search\">\n";
01458         $form = $this->createSearchForm();
01459         $form->draw();
01460         echo "</div>";
01461     }
01462 }

Generated on Fri Oct 27 12:26:40 2006 for BaseJumper by doxygen 1.3.9.1