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
00099 parent::__construct();
00100
00101
00102 $this->objectType = $objectType;
00103 $this->object = $this->factory();
00104
00105
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
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
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
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
00198 $xml = parent::getPagesXml();
00199
00200
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
00228 $xml = '';
00229
00230
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
00240 $fields = $this->object->getDbFields();
00241
00242
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
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
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
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
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
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
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
00330 if((int)$this->params('num_results') > 200)
00331 $this->setParam('num_results', 200);
00332
00333
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
00340 $this->pageTitle = ucfirst($this->object->english) . " Search";
00341
00342
00343 $this->initSearchPageOutput();
00344 }
00345
00349 protected function initSearchPageOutput()
00350 {
00351
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
00412 $this->setTemplate(new XMLTemplate());
00413
00414
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
00427 $this->setTemplate(new BlankTemplate());
00428 }
00429
00433 protected function initHTMLOutput()
00434 {
00435 }
00436
00440 public function drawSearchPage()
00441 {
00442
00443 $output = $this->params('output');
00444 if (!$output)
00445 $output = 'html';
00446
00447
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
00484 $rs = $this->getSearchResult();
00485
00486
00487 if ($this->useFullTextSearch)
00488 $this->drawSearchForm();
00489
00490
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
00530 $serial = new XML_Serializer($options);
00531
00532
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
00555 $rs = $this->getSearchResult();
00556
00557
00558 echo "<ul>";
00559 foreach ($rs AS $ob)
00560 echo "\t" . $ob->getAutoCompleteRow();
00561 echo "</ul>";
00562 }
00563
00569 function initSearch($params)
00570 {
00571
00572 foreach ($params AS $key => $val)
00573 $params[$key] = dbEscape($val);
00574
00575
00576 $this->searchParams = $params;
00577
00578
00579 if ($params['num_results'])
00580 $this->numRows = (int)$params['num_results'];
00581
00582
00583 $this->query = $this->getSearchQuery($params);
00584 }
00585
00593 public function getSearchQuery($params)
00594 {
00595
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
00604 $countSql = $countSel . $from . $where;
00605
00606
00607 if (self::$cacheSearchCount)
00608 $countAr = CacheBot::get('BaseJumper:count:' . sha1($countSql), self::$searchCacheLife);
00609
00610
00611 if (!$countAr)
00612 {
00613 $countAr = dbFetchAssoc(dbQuery($countSql));
00614
00615
00616 if (self::$cacheSearchCount)
00617 CacheBot::set('BaseJumper:count:' . sha1($countSql), $countAr, self::$searchCacheLife);
00618 }
00619
00620
00621 $this->numResults = $countAr['count'];
00622
00623
00624 $this->resultPage = abs((int)$params['result_page']);
00625
00626
00627 if ($this->resultPage * $this->numRows > $this->numResults)
00628 throw new PageError('We do not have that many ' . $this->english . "s.");
00629
00630
00631 $limit = " LIMIT " . $this->resultPage * $this->numRows . ", $this->numRows";
00632
00633
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
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
00687 $xml = $this->parseModuleXml();
00688 $rs = $xml->xpath("//page[@name='search']");
00689
00690
00691 if (is_object($rs[0]->param[0]))
00692 {
00693
00694 foreach ($rs[0]->param AS $param)
00695 {
00696
00697 $pName = (string)$param['name'];
00698 $pVal = $params[$pName];
00699
00700
00701 if ($pVal)
00702 {
00703
00704 if ($pName == 'ids')
00705 $where .= " AND o.id IN ($pVal) ";
00706
00707
00708 if ($pName == 'user_id')
00709 $where .= " AND o.user_id = '$pVal' ";
00710
00711
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
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
00732 else if ($pVal && (string)$param['is_searchable'] == 'true')
00733 $where .= " AND o.$pName = '$pVal'";
00734 }
00735 }
00736 }
00737
00738
00739 $where .= $this->getPrivacyWhere($params);
00740
00741
00742 if ($this->useFullTextSearch && $params['query'] && count($this->object->fullTextFields))
00743 $where .= " AND " . $this->getFullTextSearch($params['query']);
00744
00745
00746 $where .= $this->getLikeSearch($params['like']);
00747
00748 return $where;
00749 }
00750
00758 protected function getFullTextSearch($query)
00759 {
00760
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
00814 $sortVar = $params['sort'];
00815 $order = $params['order'];
00816
00817
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
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
00871 if ($this->hasPage($this->resultPage-1) || $this->hasPage($this->resultPage+1))
00872 {
00873 $s = "Page: ";
00874
00875
00876 if ($this->resultPage >= 1)
00877 {
00878 $s .= $this->getPaginationFirst();
00879 $s .= " ";
00880 $s .= $this->getPaginationPrev();
00881 }
00882
00883
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
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
00914 $params = $this->searchParams;
00915 $params['page'] = 'search';
00916 $params['result_page'] = $page;
00917
00918
00919 return $this->getUrl($params);
00920 }
00921
00930 function getPaginationLink($page, $link = null)
00931 {
00932 $url = $this->getPaginationUrl($page);
00933
00934
00935 if ($link === null)
00936 $link = $page + 1;
00937
00938
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
00994 if ($page < 0)
00995 return false;
00996
00997
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
01026 $data = $this->doObjectSearch();
01027
01028
01029 $ret = $this->loadObjects($data);
01030
01031
01032 $this->calculatePagination();
01033
01034 return $ret;
01035 }
01036
01045 protected function doObjectSearch()
01046 {
01047
01048 if (self::$cacheSearchQuery)
01049 $data = CacheBot::get('BaseJumper:search:' . sha1($this->query), self::$searchCacheLife);
01050
01051
01052 if (!is_array($data))
01053 {
01054
01055 $data = array();
01056
01057
01058 $rs = dbQuery($this->query);
01059 while ($ar = dbFetchAssoc($rs))
01060 $data[] = $ar;
01061
01062
01063 if (self::$cacheSearchQuery)
01064 CacheBot::set('BaseJumper:search:' . sha1($this->query), $data, self::$searchCacheLife);
01065 }
01066
01067
01068 return $data;
01069 }
01070
01079 protected function loadObjects($data)
01080 {
01081 $objs = array();
01082
01083
01084 if (count($data))
01085 {
01086
01087 $keys = array();
01088 foreach ($data AS $row)
01089 $keys[] = $this->object->getCacheKey($row['id']);
01090
01091 $data = CacheBot::get($keys, BaseObject::$objectCacheLife);
01092 foreach ($data AS $key => $val)
01093 {
01094 $info = explode(":", $key);
01095 $id = $info[3];
01096
01097
01098 if ($val)
01099 $objs[$id] = $this->factory($val);
01100
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
01134 if ($params === null)
01135 $params = $this->params();
01136
01137
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
01200 $flag = true;
01201
01202
01203 if ($class === null)
01204 $class = "contentRow " . strtolower($this->objectType);
01205
01206
01207 if (count($rs))
01208 {
01209
01210 $this->object->drawHeaderRow();
01211 foreach ($rs AS $ar)
01212 {
01213
01214 $this->object = $ar;
01215 if ($this->object->canView())
01216 {
01217
01218 if ($flag)
01219 $classRow = "onRow";
01220 else
01221 $classRow = "offRow";
01222
01223
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
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
01294 if ($limit == -1)
01295 $limit = 99999999;
01296
01297
01298 if ($limit !== null)
01299 $params['num_results'] = $limit;
01300
01301
01302 $this->initSearch($params);
01303
01304
01305 return $this->getSearchResult();
01306 }
01307
01318 public function searchCount($params = array(), $cache = true)
01319 {
01320
01321 $oldCache = self::$cacheSearchCount;
01322
01323
01324 self::$cacheSearchCount = $cache;
01325
01326
01327 $this->initSearch($params);
01328
01329
01330 self::$cacheSearchCount = $oldCache;
01331
01332
01333 return $this->numResults;
01334 }
01335
01344 function generateRss($params = array(), $useCached = true)
01345 {
01346 require_once("lib/feedcreator.class.php");
01347
01348
01349 $rss = new UniversalFeedCreator();
01350
01351
01352 if ($useCached)
01353 $rss->useCached();
01354
01355 $rss->title = $this->pageTitle . " - " . Config::get('site_name');
01356 $rss->description = $this->object->english . " feed";
01357 $item->descriptionHtmlSyndicated = true;
01358
01359
01360 $rss->link = "http://" . Config::get('site_hostname');
01361 $rss->syndicationURL = "http://" . Config::get('site_hostname') . $_SERVER["PHP_SELF"];
01362
01363
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
01387 $results = array();
01388 $rs = $this->search($params);
01389 if (count($rs))
01390 foreach ($rs AS $ob)
01391 $results[] = $ob->getPublicData();
01392
01393
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
01438 if ($query === null)
01439 $query = $this->params('query');
01440
01441
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 }