├── SolrPhpClient ├── Apache │ └── Solr │ │ ├── Document.php │ │ ├── Exception.php │ │ ├── HttpTransport │ │ ├── Abstract.php │ │ ├── Curl.php │ │ ├── CurlNoReuse.php │ │ ├── FileGetContents.php │ │ ├── Interface.php │ │ └── Response.php │ │ ├── HttpTransportException.php │ │ ├── InvalidArgumentException.php │ │ ├── NoServiceAvailableException.php │ │ ├── ParserException.php │ │ ├── Response.php │ │ ├── Service.php │ │ └── Service │ │ └── Balancer.php ├── COPYING └── tests │ ├── Apache │ └── Solr │ │ ├── DocumentTest.php │ │ ├── HttpTransport │ │ ├── AbstractTest.php │ │ ├── CurlNoReuseTest.php │ │ ├── CurlTest.php │ │ ├── FileGetContentsTest.php │ │ └── ResponseTest.php │ │ ├── HttpTransportExceptionTest.php │ │ ├── ResponseTest.php │ │ ├── Service │ │ └── BalancerTest.php │ │ ├── ServiceAbstractTest.php │ │ └── ServiceTest.php │ ├── README │ ├── phpunit.bootstrap.inc │ ├── phpunit.xml │ └── run.php ├── readme.txt ├── schema.xml ├── screenshot-1.png ├── screenshot-2.png ├── solr-for-wordpress.php ├── solr-for-wordpress.pot ├── solr-options-page.php └── template ├── autocomplete.css ├── s4w_search.php └── search.css /SolrPhpClient/Apache/Solr/Document.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | 39 | /** 40 | * Holds Key / Value pairs that represent a Solr Document along with any associated boost 41 | * values. Field values can be accessed by direct dereferencing such as: 42 | * 43 | * ... 44 | * $document->title = 'Something'; 45 | * echo $document->title; 46 | * ... 47 | * 48 | * 49 | * Additionally, the field values can be iterated with foreach 50 | * 51 | * 52 | * foreach ($document as $fieldName => $fieldValue) 53 | * { 54 | * ... 55 | * } 56 | * 57 | */ 58 | class Apache_Solr_Document implements IteratorAggregate 59 | { 60 | /** 61 | * SVN Revision meta data for this class 62 | */ 63 | const SVN_REVISION = '$Revision: 54 $'; 64 | 65 | /** 66 | * SVN ID meta data for this class 67 | */ 68 | const SVN_ID = '$Id: Document.php 54 2011-02-04 16:29:18Z donovan.jimenez $'; 69 | 70 | /** 71 | * Document boost value 72 | * 73 | * @var float 74 | */ 75 | protected $_documentBoost = false; 76 | 77 | /** 78 | * Document field values, indexed by name 79 | * 80 | * @var array 81 | */ 82 | protected $_fields = array(); 83 | 84 | /** 85 | * Document field boost values, indexed by name 86 | * 87 | * @var array array of floats 88 | */ 89 | protected $_fieldBoosts = array(); 90 | 91 | /** 92 | * Clear all boosts and fields from this document 93 | */ 94 | public function clear() 95 | { 96 | $this->_documentBoost = false; 97 | 98 | $this->_fields = array(); 99 | $this->_fieldBoosts = array(); 100 | } 101 | 102 | /** 103 | * Get current document boost 104 | * 105 | * @return mixed will be false for default, or else a float 106 | */ 107 | public function getBoost() 108 | { 109 | return $this->_documentBoost; 110 | } 111 | 112 | /** 113 | * Set document boost factor 114 | * 115 | * @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false 116 | */ 117 | public function setBoost($boost) 118 | { 119 | $boost = (float) $boost; 120 | 121 | if ($boost > 0.0) 122 | { 123 | $this->_documentBoost = $boost; 124 | } 125 | else 126 | { 127 | $this->_documentBoost = false; 128 | } 129 | } 130 | 131 | /** 132 | * Add a value to a multi-valued field 133 | * 134 | * NOTE: the solr XML format allows you to specify boosts 135 | * PER value even though the underlying Lucene implementation 136 | * only allows a boost per field. To remedy this, the final 137 | * field boost value will be the product of all specified boosts 138 | * on field values - this is similar to SolrJ's functionality. 139 | * 140 | * 141 | * $doc = new Apache_Solr_Document(); 142 | * 143 | * $doc->addField('foo', 'bar', 2.0); 144 | * $doc->addField('foo', 'baz', 3.0); 145 | * 146 | * // resultant field boost will be 6! 147 | * echo $doc->getFieldBoost('foo'); 148 | * 149 | * 150 | * @param string $key 151 | * @param mixed $value 152 | * @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false 153 | */ 154 | public function addField($key, $value, $boost = false) 155 | { 156 | if (!isset($this->_fields[$key])) 157 | { 158 | // create holding array if this is the first value 159 | $this->_fields[$key] = array(); 160 | } 161 | else if (!is_array($this->_fields[$key])) 162 | { 163 | // move existing value into array if it is not already an array 164 | $this->_fields[$key] = array($this->_fields[$key]); 165 | } 166 | 167 | if ($this->getFieldBoost($key) === false) 168 | { 169 | // boost not already set, set it now 170 | $this->setFieldBoost($key, $boost); 171 | } 172 | else if ((float) $boost > 0.0) 173 | { 174 | // multiply passed boost with current field boost - similar to SolrJ implementation 175 | $this->_fieldBoosts[$key] *= (float) $boost; 176 | } 177 | 178 | // add value to array 179 | $this->_fields[$key][] = $value; 180 | } 181 | 182 | /** 183 | * Handle the array manipulation for a multi-valued field 184 | * 185 | * @param string $key 186 | * @param string $value 187 | * @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false 188 | * 189 | * @deprecated Use addField(...) instead 190 | */ 191 | public function setMultiValue($key, $value, $boost = false) 192 | { 193 | $this->addField($key, $value, $boost); 194 | } 195 | 196 | /** 197 | * Get field information 198 | * 199 | * @param string $key 200 | * @return mixed associative array of info if field exists, false otherwise 201 | */ 202 | public function getField($key) 203 | { 204 | if (isset($this->_fields[$key])) 205 | { 206 | return array( 207 | 'name' => $key, 208 | 'value' => $this->_fields[$key], 209 | 'boost' => $this->getFieldBoost($key) 210 | ); 211 | } 212 | 213 | return false; 214 | } 215 | 216 | /** 217 | * Set a field value. Multi-valued fields should be set as arrays 218 | * or instead use the addField(...) function which will automatically 219 | * make sure the field is an array. 220 | * 221 | * @param string $key 222 | * @param mixed $value 223 | * @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false 224 | */ 225 | public function setField($key, $value, $boost = false) 226 | { 227 | $this->_fields[$key] = $value; 228 | $this->setFieldBoost($key, $boost); 229 | } 230 | 231 | /** 232 | * Get the currently set field boost for a document field 233 | * 234 | * @param string $key 235 | * @return float currently set field boost, false if one is not set 236 | */ 237 | public function getFieldBoost($key) 238 | { 239 | return isset($this->_fieldBoosts[$key]) ? $this->_fieldBoosts[$key] : false; 240 | } 241 | 242 | /** 243 | * Set the field boost for a document field 244 | * 245 | * @param string $key field name for the boost 246 | * @param mixed $boost Use false for default boost, else cast to float that should be > 0 or will be treated as false 247 | */ 248 | public function setFieldBoost($key, $boost) 249 | { 250 | $boost = (float) $boost; 251 | 252 | if ($boost > 0.0) 253 | { 254 | $this->_fieldBoosts[$key] = $boost; 255 | } 256 | else 257 | { 258 | $this->_fieldBoosts[$key] = false; 259 | } 260 | } 261 | 262 | /** 263 | * Return current field boosts, indexed by field name 264 | * 265 | * @return array 266 | */ 267 | public function getFieldBoosts() 268 | { 269 | return $this->_fieldBoosts; 270 | } 271 | 272 | /** 273 | * Get the names of all fields in this document 274 | * 275 | * @return array 276 | */ 277 | public function getFieldNames() 278 | { 279 | return array_keys($this->_fields); 280 | } 281 | 282 | /** 283 | * Get the values of all fields in this document 284 | * 285 | * @return array 286 | */ 287 | public function getFieldValues() 288 | { 289 | return array_values($this->_fields); 290 | } 291 | 292 | /** 293 | * IteratorAggregate implementation function. Allows usage: 294 | * 295 | * 296 | * foreach ($document as $key => $value) 297 | * { 298 | * ... 299 | * } 300 | * 301 | */ 302 | public function getIterator() 303 | { 304 | $arrayObject = new ArrayObject($this->_fields); 305 | 306 | return $arrayObject->getIterator(); 307 | } 308 | 309 | /** 310 | * Magic get for field values 311 | * 312 | * @param string $key 313 | * @return mixed 314 | */ 315 | public function __get($key) 316 | { 317 | if (isset($this->_fields[$key])) 318 | { 319 | return $this->_fields[$key]; 320 | } 321 | 322 | return null; 323 | } 324 | 325 | /** 326 | * Magic set for field values. Multi-valued fields should be set as arrays 327 | * or instead use the addField(...) function which will automatically 328 | * make sure the field is an array. 329 | * 330 | * @param string $key 331 | * @param mixed $value 332 | */ 333 | public function __set($key, $value) 334 | { 335 | $this->setField($key, $value); 336 | } 337 | 338 | /** 339 | * Magic isset for fields values. Do not call directly. Allows usage: 340 | * 341 | * 342 | * isset($document->some_field); 343 | * 344 | * 345 | * @param string $key 346 | * @return boolean 347 | */ 348 | public function __isset($key) 349 | { 350 | return isset($this->_fields[$key]); 351 | } 352 | 353 | /** 354 | * Magic unset for field values. Do not call directly. Allows usage: 355 | * 356 | * 357 | * unset($document->some_field); 358 | * 359 | * 360 | * @param string $key 361 | */ 362 | public function __unset($key) 363 | { 364 | unset($this->_fields[$key]); 365 | unset($this->_fieldBoosts[$key]); 366 | } 367 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/Exception.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | 39 | class Apache_Solr_Exception extends Exception 40 | { 41 | /** 42 | * SVN Revision meta data for this class 43 | */ 44 | const SVN_REVISION = '$Revision: 54 $'; 45 | 46 | /** 47 | * SVN ID meta data for this class 48 | */ 49 | const SVN_ID = '$Id: Exception.php 54 2011-02-04 16:29:18Z donovan.jimenez $'; 50 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/HttpTransport/Abstract.php: -------------------------------------------------------------------------------- 1 | , Donovan Jimenez 37 | */ 38 | 39 | /** 40 | * Convenience class that implements the transport implementation. Can be extended by 41 | * real implementations to do some of the common book keeping 42 | */ 43 | abstract class Apache_Solr_HttpTransport_Abstract implements Apache_Solr_HttpTransport_Interface 44 | { 45 | /** 46 | * Our default timeout value for requests that don't specify a timeout 47 | * 48 | * @var float 49 | */ 50 | private $_defaultTimeout = false; 51 | 52 | /** 53 | * Get the current default timeout setting (initially the default_socket_timeout ini setting) 54 | * in seconds 55 | * 56 | * @return float 57 | */ 58 | public function getDefaultTimeout() 59 | { 60 | // lazy load the default timeout from the ini settings 61 | if ($this->_defaultTimeout === false) 62 | { 63 | $this->_defaultTimeout = (int) ini_get('default_socket_timeout'); 64 | 65 | // double check we didn't get 0 for a timeout 66 | if ($this->_defaultTimeout <= 0) 67 | { 68 | $this->_defaultTimeout = 60; 69 | } 70 | } 71 | 72 | return $this->_defaultTimeout; 73 | } 74 | 75 | /** 76 | * Set the current default timeout for all HTTP requests 77 | * 78 | * @param float $timeout 79 | */ 80 | public function setDefaultTimeout($timeout) 81 | { 82 | $timeout = (float) $timeout; 83 | 84 | if ($timeout >= 0) 85 | { 86 | $this->_defaultTimeout = $timeout; 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/HttpTransport/Curl.php: -------------------------------------------------------------------------------- 1 | , Donovan Jimenez 37 | */ 38 | 39 | // Require Apache_Solr_HttpTransport_Abstract 40 | require_once(dirname(__FILE__) . '/Abstract.php'); 41 | 42 | /** 43 | * A Curl based HTTP transport. Uses a single curl session for all requests. 44 | */ 45 | class Apache_Solr_HttpTransport_Curl extends Apache_Solr_HttpTransport_Abstract 46 | { 47 | /** 48 | * SVN Revision meta data for this class 49 | */ 50 | const SVN_REVISION = '$Revision:$'; 51 | 52 | /** 53 | * SVN ID meta data for this class 54 | */ 55 | const SVN_ID = '$Id:$'; 56 | 57 | /** 58 | * Curl Session Handle 59 | * 60 | * @var resource 61 | */ 62 | private $_curl; 63 | 64 | /** 65 | * Initializes a curl session 66 | */ 67 | public function __construct() 68 | { 69 | // initialize a CURL session 70 | $this->_curl = curl_init(); 71 | 72 | // set common options that will not be changed during the session 73 | curl_setopt_array($this->_curl, array( 74 | // return the response body from curl_exec 75 | CURLOPT_RETURNTRANSFER => true, 76 | 77 | // get the output as binary data 78 | CURLOPT_BINARYTRANSFER => true, 79 | 80 | // we do not need the headers in the output, we get everything we need from curl_getinfo 81 | CURLOPT_HEADER => false 82 | )); 83 | } 84 | 85 | /** 86 | * Closes a curl session 87 | */ 88 | function __destruct() 89 | { 90 | // close our curl session 91 | curl_close($this->_curl); 92 | } 93 | 94 | public function performGetRequest($url, $timeout = false) 95 | { 96 | // check the timeout value 97 | if ($timeout === false || $timeout <= 0.0) 98 | { 99 | // use the default timeout 100 | $timeout = $this->getDefaultTimeout(); 101 | } 102 | 103 | // set curl GET options 104 | curl_setopt_array($this->_curl, array( 105 | // make sure we're returning the body 106 | CURLOPT_NOBODY => false, 107 | 108 | // make sure we're GET 109 | CURLOPT_HTTPGET => true, 110 | 111 | // set the URL 112 | CURLOPT_URL => $url, 113 | 114 | // set the timeout 115 | CURLOPT_TIMEOUT => $timeout 116 | )); 117 | 118 | // make the request 119 | $responseBody = curl_exec($this->_curl); 120 | 121 | // get info from the transfer 122 | $statusCode = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE); 123 | $contentType = curl_getinfo($this->_curl, CURLINFO_CONTENT_TYPE); 124 | 125 | return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody); 126 | } 127 | 128 | public function performHeadRequest($url, $timeout = false) 129 | { 130 | // check the timeout value 131 | if ($timeout === false || $timeout <= 0.0) 132 | { 133 | // use the default timeout 134 | $timeout = $this->getDefaultTimeout(); 135 | } 136 | 137 | // set curl HEAD options 138 | curl_setopt_array($this->_curl, array( 139 | // this both sets the method to HEAD and says not to return a body 140 | CURLOPT_NOBODY => true, 141 | 142 | // set the URL 143 | CURLOPT_URL => $url, 144 | 145 | // set the timeout 146 | CURLOPT_TIMEOUT => $timeout 147 | )); 148 | 149 | // make the request 150 | $responseBody = curl_exec($this->_curl); 151 | 152 | // get info from the transfer 153 | $statusCode = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE); 154 | $contentType = curl_getinfo($this->_curl, CURLINFO_CONTENT_TYPE); 155 | 156 | return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody); 157 | } 158 | 159 | public function performPostRequest($url, $postData, $contentType, $timeout = false) 160 | { 161 | // check the timeout value 162 | if ($timeout === false || $timeout <= 0.0) 163 | { 164 | // use the default timeout 165 | $timeout = $this->getDefaultTimeout(); 166 | } 167 | 168 | // set curl POST options 169 | curl_setopt_array($this->_curl, array( 170 | // make sure we're returning the body 171 | CURLOPT_NOBODY => false, 172 | 173 | // make sure we're POST 174 | CURLOPT_POST => true, 175 | 176 | // set the URL 177 | CURLOPT_URL => $url, 178 | 179 | // set the post data 180 | CURLOPT_POSTFIELDS => $postData, 181 | 182 | // set the content type 183 | CURLOPT_HTTPHEADER => array("Content-Type: {$contentType}"), 184 | 185 | // set the timeout 186 | CURLOPT_TIMEOUT => $timeout 187 | )); 188 | 189 | // make the request 190 | $responseBody = curl_exec($this->_curl); 191 | 192 | // get info from the transfer 193 | $statusCode = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE); 194 | $contentType = curl_getinfo($this->_curl, CURLINFO_CONTENT_TYPE); 195 | 196 | return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody); 197 | } 198 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/HttpTransport/CurlNoReuse.php: -------------------------------------------------------------------------------- 1 | , Donovan Jimenez 37 | */ 38 | 39 | // Require Apache_Solr_HttpTransport_Abstract 40 | require_once(dirname(__FILE__) . '/Abstract.php'); 41 | 42 | /** 43 | * An alternative Curl HTTP transport that opens and closes a curl session for 44 | * every request. This isn't the recommended way to use curl, but some version of 45 | * PHP have memory issues. 46 | */ 47 | class Apache_Solr_HttpTransport_CurlNoReuse extends Apache_Solr_HttpTransport_Abstract 48 | { 49 | /** 50 | * SVN Revision meta data for this class 51 | */ 52 | const SVN_REVISION = '$Revision:$'; 53 | 54 | /** 55 | * SVN ID meta data for this class 56 | */ 57 | const SVN_ID = '$Id:$'; 58 | 59 | public function performGetRequest($url, $timeout = false) 60 | { 61 | // check the timeout value 62 | if ($timeout === false || $timeout <= 0.0) 63 | { 64 | // use the default timeout 65 | $timeout = $this->getDefaultTimeout(); 66 | } 67 | 68 | $curl = curl_init(); 69 | 70 | // set curl GET options 71 | curl_setopt_array($curl, array( 72 | // return the response body from curl_exec 73 | CURLOPT_RETURNTRANSFER => true, 74 | 75 | // get the output as binary data 76 | CURLOPT_BINARYTRANSFER => true, 77 | 78 | // we do not need the headers in the output, we get everything we need from curl_getinfo 79 | CURLOPT_HEADER => false, 80 | 81 | // set the URL 82 | CURLOPT_URL => $url, 83 | 84 | // set the timeout 85 | CURLOPT_TIMEOUT => $timeout 86 | )); 87 | 88 | // make the request 89 | $responseBody = curl_exec($curl); 90 | 91 | // get info from the transfer 92 | $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); 93 | $contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE); 94 | 95 | // close our curl session - we're done with it 96 | curl_close($curl); 97 | 98 | return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody); 99 | } 100 | 101 | public function performHeadRequest($url, $timeout = false) 102 | { 103 | // check the timeout value 104 | if ($timeout === false || $timeout <= 0.0) 105 | { 106 | // use the default timeout 107 | $timeout = $this->getDefaultTimeout(); 108 | } 109 | 110 | $curl = curl_init(); 111 | 112 | // set curl HEAD options 113 | curl_setopt_array($curl, array( 114 | // return the response body from curl_exec 115 | CURLOPT_RETURNTRANSFER => true, 116 | 117 | // get the output as binary data 118 | CURLOPT_BINARYTRANSFER => true, 119 | 120 | // we do not need the headers in the output, we get everything we need from curl_getinfo 121 | CURLOPT_HEADER => false, 122 | 123 | // this both sets the method to HEAD and says not to return a body 124 | CURLOPT_NOBODY => true, 125 | 126 | // set the URL 127 | CURLOPT_URL => $url, 128 | 129 | // set the timeout 130 | CURLOPT_TIMEOUT => $timeout 131 | )); 132 | 133 | // make the request 134 | $responseBody = curl_exec($curl); 135 | 136 | // get info from the transfer 137 | $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); 138 | $contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE); 139 | 140 | // close our curl session - we're done with it 141 | curl_close($curl); 142 | 143 | return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody); 144 | } 145 | 146 | public function performPostRequest($url, $postData, $contentType, $timeout = false) 147 | { 148 | // check the timeout value 149 | if ($timeout === false || $timeout <= 0.0) 150 | { 151 | // use the default timeout 152 | $timeout = $this->getDefaultTimeout(); 153 | } 154 | 155 | $curl = curl_init(); 156 | 157 | // set curl POST options 158 | curl_setopt_array($curl, array( 159 | // return the response body from curl_exec 160 | CURLOPT_RETURNTRANSFER => true, 161 | 162 | // get the output as binary data 163 | CURLOPT_BINARYTRANSFER => true, 164 | 165 | // we do not need the headers in the output, we get everything we need from curl_getinfo 166 | CURLOPT_HEADER => false, 167 | 168 | // make sure we're POST 169 | CURLOPT_POST => true, 170 | 171 | // set the URL 172 | CURLOPT_URL => $url, 173 | 174 | // set the post data 175 | CURLOPT_POSTFIELDS => $postData, 176 | 177 | // set the content type 178 | CURLOPT_HTTPHEADER => array("Content-Type: {$contentType}"), 179 | 180 | // set the timeout 181 | CURLOPT_TIMEOUT => $timeout 182 | )); 183 | 184 | // make the request 185 | $responseBody = curl_exec($curl); 186 | 187 | // get info from the transfer 188 | $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); 189 | $contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE); 190 | 191 | // close our curl session - we're done with it 192 | curl_close($curl); 193 | 194 | return new Apache_Solr_HttpTransport_Response($statusCode, $contentType, $responseBody); 195 | } 196 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/HttpTransport/FileGetContents.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | 39 | // Require Apache_Solr_HttpTransport_Abstract 40 | require_once(dirname(__FILE__) . '/Abstract.php'); 41 | 42 | /** 43 | * HTTP Transport implemenation that uses the builtin http URL wrappers and file_get_contents 44 | */ 45 | class Apache_Solr_HttpTransport_FileGetContents extends Apache_Solr_HttpTransport_Abstract 46 | { 47 | /** 48 | * SVN Revision meta data for this class 49 | */ 50 | const SVN_REVISION = '$Revision: $'; 51 | 52 | /** 53 | * SVN ID meta data for this class 54 | */ 55 | const SVN_ID = '$Id: $'; 56 | 57 | /** 58 | * Reusable stream context resources for GET and POST operations 59 | * 60 | * @var resource 61 | */ 62 | private $_getContext, $_headContext, $_postContext; 63 | 64 | /** 65 | * Initializes our reuseable get and post stream contexts 66 | */ 67 | public function __construct() 68 | { 69 | $this->_getContext = stream_context_create(); 70 | $this->_headContext = stream_context_create(); 71 | $this->_postContext = stream_context_create(); 72 | } 73 | 74 | public function performGetRequest($url, $timeout = false) 75 | { 76 | // set the timeout if specified 77 | if ($timeout !== FALSE && $timeout > 0.0) 78 | { 79 | // timeouts with file_get_contents seem to need 80 | // to be halved to work as expected 81 | $timeout = (float) $timeout / 2; 82 | 83 | stream_context_set_option($this->_getContext, 'http', 'timeout', $timeout); 84 | } 85 | else 86 | { 87 | // use the default timeout pulled from default_socket_timeout otherwise 88 | stream_context_set_option($this->_getContext, 'http', 'timeout', $this->getDefaultTimeout()); 89 | } 90 | 91 | // $http_response_headers will be updated by the call to file_get_contents later 92 | // see http://us.php.net/manual/en/wrappers.http.php for documentation 93 | // Unfortunately, it will still create a notice in analyzers if we don't set it here 94 | $http_response_header = null; 95 | $responseBody = @file_get_contents($url, false, $this->_getContext); 96 | 97 | return $this->_getResponseFromParts($responseBody, $http_response_header); 98 | } 99 | 100 | public function performHeadRequest($url, $timeout = false) 101 | { 102 | stream_context_set_option($this->_headContext, array( 103 | 'http' => array( 104 | // set HTTP method 105 | 'method' => 'HEAD', 106 | 107 | // default timeout 108 | 'timeout' => $this->getDefaultTimeout() 109 | ) 110 | ) 111 | ); 112 | 113 | // set the timeout if specified 114 | if ($timeout !== FALSE && $timeout > 0.0) 115 | { 116 | // timeouts with file_get_contents seem to need 117 | // to be halved to work as expected 118 | $timeout = (float) $timeout / 2; 119 | 120 | stream_context_set_option($this->_headContext, 'http', 'timeout', $timeout); 121 | } 122 | 123 | // $http_response_headers will be updated by the call to file_get_contents later 124 | // see http://us.php.net/manual/en/wrappers.http.php for documentation 125 | // Unfortunately, it will still create a notice in analyzers if we don't set it here 126 | $http_response_header = null; 127 | $responseBody = @file_get_contents($url, false, $this->_headContext); 128 | 129 | return $this->_getResponseFromParts($responseBody, $http_response_header); 130 | } 131 | 132 | public function performPostRequest($url, $rawPost, $contentType, $timeout = false) 133 | { 134 | stream_context_set_option($this->_postContext, array( 135 | 'http' => array( 136 | // set HTTP method 137 | 'method' => 'POST', 138 | 139 | // Add our posted content type 140 | 'header' => "Content-Type: $contentType", 141 | 142 | // the posted content 143 | 'content' => $rawPost, 144 | 145 | // default timeout 146 | 'timeout' => $this->getDefaultTimeout() 147 | ) 148 | ) 149 | ); 150 | 151 | // set the timeout if specified 152 | if ($timeout !== FALSE && $timeout > 0.0) 153 | { 154 | // timeouts with file_get_contents seem to need 155 | // to be halved to work as expected 156 | $timeout = (float) $timeout / 2; 157 | 158 | stream_context_set_option($this->_postContext, 'http', 'timeout', $timeout); 159 | } 160 | 161 | // $http_response_header will be updated by the call to file_get_contents later 162 | // see http://us.php.net/manual/en/wrappers.http.php for documentation 163 | // Unfortunately, it will still create a notice in analyzers if we don't set it here 164 | $http_response_header = null; 165 | $responseBody = @file_get_contents($url, false, $this->_postContext); 166 | 167 | // reset content of post context to reclaim memory 168 | stream_context_set_option($this->_postContext, 'http', 'content', ''); 169 | 170 | return $this->_getResponseFromParts($responseBody, $http_response_header); 171 | } 172 | 173 | private function _getResponseFromParts($rawResponse, $httpHeaders) 174 | { 175 | //Assume 0, false as defaults 176 | $status = 0; 177 | $contentType = false; 178 | 179 | //iterate through headers for real status, type, and encoding 180 | if (is_array($httpHeaders) && count($httpHeaders) > 0) 181 | { 182 | //look at the first headers for the HTTP status code 183 | //and message (errors are usually returned this way) 184 | // 185 | //HTTP 100 Continue response can also be returned before 186 | //the REAL status header, so we need look until we find 187 | //the last header starting with HTTP 188 | // 189 | //the spec: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.1 190 | // 191 | //Thanks to Daniel Andersson for pointing out this oversight 192 | while (isset($httpHeaders[0]) && substr($httpHeaders[0], 0, 4) == 'HTTP') 193 | { 194 | // we can do a intval on status line without the "HTTP/1.X " to get the code 195 | $status = intval(substr($httpHeaders[0], 9)); 196 | 197 | // remove this from the headers so we can check for more 198 | array_shift($httpHeaders); 199 | } 200 | 201 | //Look for the Content-Type response header and determine type 202 | //and encoding from it (if possible - such as 'Content-Type: text/plain; charset=UTF-8') 203 | foreach ($httpHeaders as $header) 204 | { 205 | // look for the header that starts appropriately 206 | if (strncasecmp($header, 'Content-Type:', 13) == 0) 207 | { 208 | $contentType = substr($header, 13); 209 | break; 210 | } 211 | } 212 | } 213 | 214 | return new Apache_Solr_HttpTransport_Response($status, $contentType, $rawResponse); 215 | } 216 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/HttpTransport/Interface.php: -------------------------------------------------------------------------------- 1 | , Donovan Jimenez 37 | */ 38 | 39 | // require Apache_Solr_HttpTransport_Response 40 | require_once(dirname(__FILE__) . '/Response.php'); 41 | 42 | /** 43 | * Interface that all Transport (HTTP Requester) implementations must implement. These 44 | * Implementations can then be plugged into the Service instance in order to user their 45 | * the desired method for making HTTP requests 46 | */ 47 | interface Apache_Solr_HttpTransport_Interface 48 | { 49 | /** 50 | * Get the current default timeout for all HTTP requests 51 | * 52 | * @return float 53 | */ 54 | public function getDefaultTimeout(); 55 | 56 | /** 57 | * Set the current default timeout for all HTTP requests 58 | * 59 | * @param float $timeout 60 | */ 61 | public function setDefaultTimeout($timeout); 62 | 63 | /** 64 | * Perform a GET HTTP operation with an optional timeout and return the response 65 | * contents, use getLastResponseHeaders to retrieve HTTP headers 66 | * 67 | * @param string $url 68 | * @param float $timeout 69 | * @return Apache_Solr_HttpTransport_Response HTTP response 70 | */ 71 | public function performGetRequest($url, $timeout = false); 72 | 73 | /** 74 | * Perform a HEAD HTTP operation with an optional timeout and return the response 75 | * headers - NOTE: head requests have no response body 76 | * 77 | * @param string $url 78 | * @param float $timeout 79 | * @return Apache_Solr_HttpTransport_Response HTTP response 80 | */ 81 | public function performHeadRequest($url, $timeout = false); 82 | 83 | /** 84 | * Perform a POST HTTP operation with an optional timeout and return the response 85 | * contents, use getLastResponseHeaders to retrieve HTTP headers 86 | * 87 | * @param string $url 88 | * @param string $rawPost 89 | * @param string $contentType 90 | * @param float $timeout 91 | * @return Apache_Solr_HttpTransport_Response HTTP response 92 | */ 93 | public function performPostRequest($url, $rawPost, $contentType, $timeout = false); 94 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/HttpTransport/Response.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | 39 | /** 40 | * Represents the required pieces of an HTTP response provided by HTTP transport 41 | * implementations and then consumed by the Apache_Solr_Response class which provides 42 | * decoding 43 | */ 44 | class Apache_Solr_HttpTransport_Response 45 | { 46 | /** 47 | * Status Messages indexed by Status Code 48 | * Obtained from: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 49 | * 50 | * @var array 51 | */ 52 | static private $_defaultStatusMessages = array( 53 | // Specific to PHP Solr Client 54 | 0 => "Communication Error", 55 | 56 | // Informational 1XX 57 | 100 => "Continue", 58 | 101 => "Switching Protocols", 59 | 60 | // Successful 2XX 61 | 200 => "OK", 62 | 201 => "Created", 63 | 202 => "Accepted", 64 | 203 => "Non-Authoritative Information", 65 | 204 => "No Content", 66 | 205 => "Reset Content", 67 | 206 => "Partial Content", 68 | 69 | // Redirection 3XX 70 | 300 => "Multiple Choices", 71 | 301 => "Moved Permanently", 72 | 302 => "Found", 73 | 303 => "See Other", 74 | 304 => "Not Modified", 75 | 305 => "Use Proxy", 76 | 307 => "Temporary Redirect", 77 | 78 | // Client Error 4XX 79 | 400 => "Bad Request", 80 | 401 => "Unauthorized", 81 | 402 => "Payment Required", 82 | 403 => "Forbidden", 83 | 404 => "Not Found", 84 | 405 => "Method Not Allowed", 85 | 406 => "Not Acceptable", 86 | 407 => "Proxy Authentication Required", 87 | 408 => "Request Timeout", 88 | 409 => "Conflict", 89 | 410 => "Gone", 90 | 411 => "Length Required", 91 | 412 => "Precondition Failed", 92 | 413 => "Request Entity Too Large", 93 | 414 => "Request-URI Too Long", 94 | 415 => "Unsupported Media Type", 95 | 416 => "Request Range Not Satisfiable", 96 | 417 => "Expectation Failed", 97 | 98 | // Server Error 5XX 99 | 500 => "Internal Server Error", 100 | 501 => "Not Implemented", 101 | 502 => "Bad Gateway", 102 | 503 => "Service Unavailable", 103 | 504 => "Gateway Timeout", 104 | 505 => "HTTP Version Not Supported" 105 | ); 106 | 107 | /** 108 | * Get the HTTP status message based on status code 109 | * 110 | * @return string 111 | */ 112 | public static function getDefaultStatusMessage($statusCode) 113 | { 114 | $statusCode = (int) $statusCode; 115 | 116 | if (isset(self::$_defaultStatusMessages[$statusCode])) 117 | { 118 | return self::$_defaultStatusMessages[$statusCode]; 119 | } 120 | 121 | return "Unknown Status"; 122 | } 123 | 124 | /** 125 | * The response's HTTP status code 126 | * 127 | * @var integer 128 | */ 129 | private $_statusCode; 130 | 131 | /** 132 | * The response's HTTP status message 133 | * 134 | * @var string 135 | */ 136 | private $_statusMessage; 137 | 138 | /** 139 | * The response's mime type 140 | * 141 | * @var string 142 | */ 143 | private $_mimeType; 144 | 145 | /** 146 | * The response's character encoding 147 | * 148 | * @var string 149 | */ 150 | private $_encoding; 151 | 152 | /** 153 | * The response's data 154 | * 155 | * @var string 156 | */ 157 | private $_responseBody; 158 | 159 | /** 160 | * Construct a HTTP transport response 161 | * 162 | * @param integer $statusCode The HTTP status code 163 | * @param string $contentType The VALUE of the Content-Type HTTP header 164 | * @param string $responseBody The body of the HTTP response 165 | */ 166 | public function __construct($statusCode, $contentType, $responseBody) 167 | { 168 | // set the status code, make sure its an integer 169 | $this->_statusCode = (int) $statusCode; 170 | 171 | // lookup up status message based on code 172 | $this->_statusMessage = self::getDefaultStatusMessage($this->_statusCode); 173 | 174 | // set the response body, it should always be a string 175 | $this->_responseBody = (string) $responseBody; 176 | 177 | // parse the content type header value for mimetype and encoding 178 | // first set default values that will remain if we can't find 179 | // what we're looking for in the content type 180 | $this->_mimeType = "text/plain"; 181 | $this->_encoding = "UTF-8"; 182 | 183 | if ($contentType) 184 | { 185 | // now break apart the header to see if there's character encoding 186 | $contentTypeParts = explode(';', $contentType, 2); 187 | 188 | if (isset($contentTypeParts[0])) 189 | { 190 | $this->_mimeType = trim($contentTypeParts[0]); 191 | } 192 | 193 | if (isset($contentTypeParts[1])) 194 | { 195 | // we have a second part, split it further 196 | $contentTypeParts = explode('=', $contentTypeParts[1]); 197 | 198 | if (isset($contentTypeParts[1])) 199 | { 200 | $this->_encoding = trim($contentTypeParts[1]); 201 | } 202 | } 203 | } 204 | } 205 | 206 | /** 207 | * Get the status code of the response 208 | * 209 | * @return integer 210 | */ 211 | public function getStatusCode() 212 | { 213 | return $this->_statusCode; 214 | } 215 | 216 | /** 217 | * Get the status message of the response 218 | * 219 | * @return string 220 | */ 221 | public function getStatusMessage() 222 | { 223 | return $this->_statusMessage; 224 | } 225 | 226 | /** 227 | * Get the mimetype of the response body 228 | * 229 | * @return string 230 | */ 231 | public function getMimeType() 232 | { 233 | return $this->_mimeType; 234 | } 235 | 236 | /** 237 | * Get the charset encoding of the response body. 238 | * 239 | * @return string 240 | */ 241 | public function getEncoding() 242 | { 243 | return $this->_encoding; 244 | } 245 | 246 | /** 247 | * Get the raw response body 248 | * 249 | * @return string 250 | */ 251 | public function getBody() 252 | { 253 | return $this->_responseBody; 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/HttpTransportException.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | 39 | class Apache_Solr_HttpTransportException extends Apache_Solr_Exception 40 | { 41 | /** 42 | * SVN Revision meta data for this class 43 | */ 44 | const SVN_REVISION = '$Revision: 54 $'; 45 | 46 | /** 47 | * SVN ID meta data for this class 48 | */ 49 | const SVN_ID = '$Id: HttpTransportException.php 54 2011-02-04 16:29:18Z donovan.jimenez $'; 50 | 51 | /** 52 | * Response for which exception was generated 53 | * 54 | * @var Apache_Solr_Response 55 | */ 56 | private $_response; 57 | 58 | /** 59 | * HttpTransportException Constructor 60 | * 61 | * @param Apache_Solr_Response $response 62 | */ 63 | public function __construct(Apache_Solr_Response $response) 64 | { 65 | parent::__construct("'{$response->getHttpStatus()}' Status: {$response->getHttpStatusMessage()}", $response->getHttpStatus()); 66 | 67 | $this->_response = $response; 68 | } 69 | 70 | /** 71 | * Get the response for which this exception was generated 72 | * 73 | * @return Apache_Solr_Response 74 | */ 75 | public function getResponse() 76 | { 77 | return $this->_response; 78 | } 79 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | 39 | class Apache_Solr_InvalidArgumentException extends Apache_Solr_Exception 40 | { 41 | /** 42 | * SVN Revision meta data for this class 43 | */ 44 | const SVN_REVISION = '$Revision: 54 $'; 45 | 46 | /** 47 | * SVN ID meta data for this class 48 | */ 49 | const SVN_ID = '$Id: InvalidArgumentException.php 54 2011-02-04 16:29:18Z donovan.jimenez $'; 50 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/NoServiceAvailableException.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | 39 | class Apache_Solr_NoServiceAvailableException extends Apache_Solr_Exception 40 | { 41 | /** 42 | * SVN Revision meta data for this class 43 | */ 44 | const SVN_REVISION = '$Revision: 54 $'; 45 | 46 | /** 47 | * SVN ID meta data for this class 48 | */ 49 | const SVN_ID = '$Id: NoServiceAvailableException.php 54 2011-02-04 16:29:18Z donovan.jimenez $'; 50 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/ParserException.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | 39 | class Apache_Solr_ParserException extends Apache_Solr_Exception 40 | { 41 | /** 42 | * SVN Revision meta data for this class 43 | */ 44 | const SVN_REVISION = '$Revision: 54 $'; 45 | 46 | /** 47 | * SVN ID meta data for this class 48 | */ 49 | const SVN_ID = '$Id: ParserException.php 54 2011-02-04 16:29:18Z donovan.jimenez $'; 50 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/Response.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | 39 | require_once(dirname(__FILE__) . '/ParserException.php'); 40 | 41 | /** 42 | * Represents a Solr response. Parses the raw response into a set of stdClass objects 43 | * and associative arrays for easy access. 44 | * 45 | * Currently requires json_decode which is bundled with PHP >= 5.2.0, Alternatively can be 46 | * installed with PECL. Zend Framework also includes a purely PHP solution. 47 | */ 48 | class Apache_Solr_Response 49 | { 50 | /** 51 | * SVN Revision meta data for this class 52 | */ 53 | const SVN_REVISION = '$Revision: 54 $'; 54 | 55 | /** 56 | * SVN ID meta data for this class 57 | */ 58 | const SVN_ID = '$Id: Response.php 54 2011-02-04 16:29:18Z donovan.jimenez $'; 59 | 60 | /** 61 | * Holds the raw response used in construction 62 | * 63 | * @var Apache_Solr_HttpTransport_Response HTTP response 64 | */ 65 | protected $_response; 66 | 67 | /** 68 | * Whether the raw response has been parsed 69 | * 70 | * @var boolean 71 | */ 72 | protected $_isParsed = false; 73 | 74 | /** 75 | * Parsed representation of the data 76 | * 77 | * @var mixed 78 | */ 79 | protected $_parsedData; 80 | 81 | /** 82 | * Data parsing flags. Determines what extra processing should be done 83 | * after the data is initially converted to a data structure. 84 | * 85 | * @var boolean 86 | */ 87 | protected $_createDocuments = true, 88 | $_collapseSingleValueArrays = true; 89 | 90 | /** 91 | * Constructor. Takes the raw HTTP response body and the exploded HTTP headers 92 | * 93 | * @return Apache_Solr_HttpTransport_Response HTTP response 94 | * @param boolean $createDocuments Whether to convert the documents json_decoded as stdClass instances to Apache_Solr_Document instances 95 | * @param boolean $collapseSingleValueArrays Whether to make multivalued fields appear as single values 96 | */ 97 | public function __construct(Apache_Solr_HttpTransport_Response $response, $createDocuments = true, $collapseSingleValueArrays = true) 98 | { 99 | $this->_response = $response; 100 | $this->_createDocuments = (bool) $createDocuments; 101 | $this->_collapseSingleValueArrays = (bool) $collapseSingleValueArrays; 102 | } 103 | 104 | /** 105 | * Get the HTTP status code 106 | * 107 | * @return integer 108 | */ 109 | public function getHttpStatus() 110 | { 111 | return $this->_response->getStatusCode(); 112 | } 113 | 114 | /** 115 | * Get the HTTP status message of the response 116 | * 117 | * @return string 118 | */ 119 | public function getHttpStatusMessage() 120 | { 121 | return $this->_response->getStatusMessage(); 122 | } 123 | 124 | /** 125 | * Get content type of this Solr response 126 | * 127 | * @return string 128 | */ 129 | public function getType() 130 | { 131 | return $this->_response->getMimeType(); 132 | } 133 | 134 | /** 135 | * Get character encoding of this response. Should usually be utf-8, but just in case 136 | * 137 | * @return string 138 | */ 139 | public function getEncoding() 140 | { 141 | return $this->_response->getEncoding(); 142 | } 143 | 144 | /** 145 | * Get the raw response as it was given to this object 146 | * 147 | * @return string 148 | */ 149 | public function getRawResponse() 150 | { 151 | return $this->_response->getBody(); 152 | } 153 | 154 | /** 155 | * Magic get to expose the parsed data and to lazily load it 156 | * 157 | * @param string $key 158 | * @return mixed 159 | */ 160 | public function __get($key) 161 | { 162 | if (!$this->_isParsed) 163 | { 164 | $this->_parseData(); 165 | $this->_isParsed = true; 166 | } 167 | 168 | if (isset($this->_parsedData->$key)) 169 | { 170 | return $this->_parsedData->$key; 171 | } 172 | 173 | return null; 174 | } 175 | 176 | /** 177 | * Magic function for isset function on parsed data 178 | * 179 | * @param string $key 180 | * @return boolean 181 | */ 182 | public function __isset($key) 183 | { 184 | if (!$this->_isParsed) 185 | { 186 | $this->_parseData(); 187 | $this->_isParsed = true; 188 | } 189 | 190 | return isset($this->_parsedData->$key); 191 | } 192 | 193 | /** 194 | * Parse the raw response into the parsed_data array for access 195 | * 196 | * @throws Apache_Solr_ParserException If the data could not be parsed 197 | */ 198 | protected function _parseData() 199 | { 200 | //An alternative would be to use Zend_Json::decode(...) 201 | $data = json_decode($this->_response->getBody()); 202 | 203 | // check that we receive a valid JSON response - we should never receive a null 204 | if ($data === null) 205 | { 206 | throw new Apache_Solr_ParserException('Solr response does not appear to be valid JSON, please examine the raw response with getRawResponse() method'); 207 | } 208 | 209 | //if we're configured to collapse single valued arrays or to convert them to Apache_Solr_Document objects 210 | //and we have response documents, then try to collapse the values and / or convert them now 211 | if (($this->_createDocuments || $this->_collapseSingleValueArrays) && isset($data->response) && is_array($data->response->docs)) 212 | { 213 | $documents = array(); 214 | 215 | foreach ($data->response->docs as $originalDocument) 216 | { 217 | if ($this->_createDocuments) 218 | { 219 | $document = new Apache_Solr_Document(); 220 | } 221 | else 222 | { 223 | $document = $originalDocument; 224 | } 225 | 226 | foreach ($originalDocument as $key => $value) 227 | { 228 | //If a result is an array with only a single 229 | //value then its nice to be able to access 230 | //it as if it were always a single value 231 | if ($this->_collapseSingleValueArrays && is_array($value) && count($value) <= 1) 232 | { 233 | $value = array_shift($value); 234 | } 235 | 236 | $document->$key = $value; 237 | } 238 | 239 | $documents[] = $document; 240 | } 241 | 242 | $data->response->docs = $documents; 243 | } 244 | 245 | $this->_parsedData = $data; 246 | } 247 | } -------------------------------------------------------------------------------- /SolrPhpClient/Apache/Solr/Service/Balancer.php: -------------------------------------------------------------------------------- 1 | , Dan Wolfe 37 | */ 38 | 39 | // See Issue #1 (http://code.google.com/p/solr-php-client/issues/detail?id=1) 40 | // Doesn't follow typical include path conventions, but is more convenient for users 41 | require_once(dirname(dirname(__FILE__)) . '/Service.php'); 42 | 43 | require_once(dirname(dirname(__FILE__)) . '/NoServiceAvailableException.php'); 44 | 45 | /** 46 | * Reference Implementation for using multiple Solr services in a distribution. Functionality 47 | * includes: 48 | * routing of read / write operations 49 | * failover (on selection) for multiple read servers 50 | */ 51 | class Apache_Solr_Service_Balancer 52 | { 53 | /** 54 | * SVN Revision meta data for this class 55 | */ 56 | const SVN_REVISION = '$Revision: 54 $'; 57 | 58 | /** 59 | * SVN ID meta data for this class 60 | */ 61 | const SVN_ID = '$Id: Balancer.php 54 2011-02-04 16:29:18Z donovan.jimenez $'; 62 | 63 | protected $_createDocuments = true; 64 | 65 | protected $_readableServices = array(); 66 | protected $_writeableServices = array(); 67 | 68 | protected $_currentReadService = null; 69 | protected $_currentWriteService = null; 70 | 71 | protected $_readPingTimeout = 2; 72 | protected $_writePingTimeout = 4; 73 | 74 | // Configuration for server selection backoff intervals 75 | protected $_useBackoff = false; // Set to true to use more resillient write server selection 76 | protected $_backoffLimit = 600; // 10 minute default maximum 77 | protected $_backoffEscalation = 2.0; // Rate at which to increase backoff period 78 | protected $_defaultBackoff = 2.0; // Default backoff interval 79 | 80 | /** 81 | * Escape a value for special query characters such as ':', '(', ')', '*', '?', etc. 82 | * 83 | * NOTE: inside a phrase fewer characters need escaped, use {@link Apache_Solr_Service::escapePhrase()} instead 84 | * 85 | * @param string $value 86 | * @return string 87 | */ 88 | static public function escape($value) 89 | { 90 | return Apache_Solr_Service::escape($value); 91 | } 92 | 93 | /** 94 | * Escape a value meant to be contained in a phrase for special query characters 95 | * 96 | * @param string $value 97 | * @return string 98 | */ 99 | static public function escapePhrase($value) 100 | { 101 | return Apache_Solr_Service::escapePhrase($value); 102 | } 103 | 104 | /** 105 | * Convenience function for creating phrase syntax from a value 106 | * 107 | * @param string $value 108 | * @return string 109 | */ 110 | static public function phrase($value) 111 | { 112 | return Apache_Solr_Service::phrase($value); 113 | } 114 | 115 | /** 116 | * Constructor. Takes arrays of read and write service instances or descriptions 117 | * 118 | * @param array $readableServices 119 | * @param array $writeableServices 120 | */ 121 | public function __construct($readableServices = array(), $writeableServices = array()) 122 | { 123 | //setup readable services 124 | foreach ($readableServices as $service) 125 | { 126 | $this->addReadService($service); 127 | } 128 | 129 | //setup writeable services 130 | foreach ($writeableServices as $service) 131 | { 132 | $this->addWriteService($service); 133 | } 134 | } 135 | 136 | public function setReadPingTimeout($timeout) 137 | { 138 | $this->_readPingTimeout = $timeout; 139 | } 140 | 141 | public function setWritePingTimeout($timeout) 142 | { 143 | $this->_writePingTimeout = $timeout; 144 | } 145 | 146 | public function setUseBackoff($enable) 147 | { 148 | $this->_useBackoff = $enable; 149 | } 150 | 151 | /** 152 | * Generates a service ID 153 | * 154 | * @param string $host 155 | * @param integer $port 156 | * @param string $path 157 | * @return string 158 | */ 159 | protected function _getServiceId($host, $port, $path) 160 | { 161 | return $host . ':' . $port . $path; 162 | } 163 | 164 | /** 165 | * Adds a service instance or service descriptor (if it is already 166 | * not added) 167 | * 168 | * @param mixed $service 169 | * 170 | * @throws Apache_Solr_InvalidArgumentException If service descriptor is not valid 171 | */ 172 | public function addReadService($service) 173 | { 174 | if ($service instanceof Apache_Solr_Service) 175 | { 176 | $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath()); 177 | 178 | $this->_readableServices[$id] = $service; 179 | } 180 | else if (is_array($service)) 181 | { 182 | if (isset($service['host']) && isset($service['port']) && isset($service['path'])) 183 | { 184 | $id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']); 185 | 186 | $this->_readableServices[$id] = $service; 187 | } 188 | else 189 | { 190 | throw new Apache_Solr_InvalidArgumentException('A Readable Service description array does not have all required elements of host, port, and path'); 191 | } 192 | } 193 | } 194 | 195 | /** 196 | * Removes a service instance or descriptor from the available services 197 | * 198 | * @param mixed $service 199 | * 200 | * @throws Apache_Solr_InvalidArgumentException If service descriptor is not valid 201 | */ 202 | public function removeReadService($service) 203 | { 204 | $id = ''; 205 | 206 | if ($service instanceof Apache_Solr_Service) 207 | { 208 | $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath()); 209 | } 210 | else if (is_array($service)) 211 | { 212 | if (isset($service['host']) && isset($service['port']) && isset($service['path'])) 213 | { 214 | $id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']); 215 | } 216 | else 217 | { 218 | throw new Apache_Solr_InvalidArgumentException('A Readable Service description array does not have all required elements of host, port, and path'); 219 | } 220 | } 221 | else if (is_string($service)) 222 | { 223 | $id = $service; 224 | } 225 | 226 | if ($id && isset($this->_readableServices[$id])) 227 | { 228 | unset($this->_readableServices[$id]); 229 | } 230 | } 231 | 232 | /** 233 | * Adds a service instance or service descriptor (if it is already 234 | * not added) 235 | * 236 | * @param mixed $service 237 | * 238 | * @throws Apache_Solr_InvalidArgumentException If service descriptor is not valid 239 | */ 240 | public function addWriteService($service) 241 | { 242 | if ($service instanceof Apache_Solr_Service) 243 | { 244 | $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath()); 245 | 246 | $this->_writeableServices[$id] = $service; 247 | } 248 | else if (is_array($service)) 249 | { 250 | if (isset($service['host']) && isset($service['port']) && isset($service['path'])) 251 | { 252 | $id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']); 253 | 254 | $this->_writeableServices[$id] = $service; 255 | } 256 | else 257 | { 258 | throw new Apache_Solr_InvalidArgumentException('A Writeable Service description array does not have all required elements of host, port, and path'); 259 | } 260 | } 261 | } 262 | 263 | /** 264 | * Removes a service instance or descriptor from the available services 265 | * 266 | * @param mixed $service 267 | * 268 | * @throws Apache_Solr_InvalidArgumentException If service descriptor is not valid 269 | */ 270 | public function removeWriteService($service) 271 | { 272 | $id = ''; 273 | 274 | if ($service instanceof Apache_Solr_Service) 275 | { 276 | $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath()); 277 | } 278 | else if (is_array($service)) 279 | { 280 | if (isset($service['host']) && isset($service['port']) && isset($service['path'])) 281 | { 282 | $id = $this->_getServiceId((string)$service['host'], (int)$service['port'], (string)$service['path']); 283 | } 284 | else 285 | { 286 | throw new Apache_Solr_InvalidArgumentException('A Readable Service description array does not have all required elements of host, port, and path'); 287 | } 288 | } 289 | else if (is_string($service)) 290 | { 291 | $id = $service; 292 | } 293 | 294 | if ($id && isset($this->_writeableServices[$id])) 295 | { 296 | unset($this->_writeableServices[$id]); 297 | } 298 | } 299 | 300 | /** 301 | * Iterate through available read services and select the first with a ping 302 | * that satisfies configured timeout restrictions (or the default) 303 | * 304 | * @return Apache_Solr_Service 305 | * 306 | * @throws Apache_Solr_NoServiceAvailableException If there are no read services that meet requirements 307 | */ 308 | protected function _selectReadService($forceSelect = false) 309 | { 310 | if (!$this->_currentReadService || !isset($this->_readableServices[$this->_currentReadService]) || $forceSelect) 311 | { 312 | if ($this->_currentReadService && isset($this->_readableServices[$this->_currentReadService]) && $forceSelect) 313 | { 314 | // we probably had a communication error, ping the current read service, remove it if it times out 315 | if ($this->_readableServices[$this->_currentReadService]->ping($this->_readPingTimeout) === false) 316 | { 317 | $this->removeReadService($this->_currentReadService); 318 | } 319 | } 320 | 321 | if (count($this->_readableServices)) 322 | { 323 | // select one of the read services at random 324 | $ids = array_keys($this->_readableServices); 325 | 326 | $id = $ids[rand(0, count($ids) - 1)]; 327 | $service = $this->_readableServices[$id]; 328 | 329 | if (is_array($service)) 330 | { 331 | //convert the array definition to a client object 332 | $service = new Apache_Solr_Service($service['host'], $service['port'], $service['path']); 333 | $this->_readableServices[$id] = $service; 334 | } 335 | 336 | $service->setCreateDocuments($this->_createDocuments); 337 | $this->_currentReadService = $id; 338 | } 339 | else 340 | { 341 | throw new Apache_Solr_NoServiceAvailableException('No read services were available'); 342 | } 343 | } 344 | 345 | return $this->_readableServices[$this->_currentReadService]; 346 | } 347 | 348 | /** 349 | * Iterate through available write services and select the first with a ping 350 | * that satisfies configured timeout restrictions (or the default) 351 | * 352 | * @return Apache_Solr_Service 353 | * 354 | * @throws Apache_Solr_NoServiceAvailableException If there are no write services that meet requirements 355 | */ 356 | protected function _selectWriteService($forceSelect = false) 357 | { 358 | if($this->_useBackoff) 359 | { 360 | return $this->_selectWriteServiceSafe($forceSelect); 361 | } 362 | 363 | if (!$this->_currentWriteService || !isset($this->_writeableServices[$this->_currentWriteService]) || $forceSelect) 364 | { 365 | if ($this->_currentWriteService && isset($this->_writeableServices[$this->_currentWriteService]) && $forceSelect) 366 | { 367 | // we probably had a communication error, ping the current read service, remove it if it times out 368 | if ($this->_writeableServices[$this->_currentWriteService]->ping($this->_writePingTimeout) === false) 369 | { 370 | $this->removeWriteService($this->_currentWriteService); 371 | } 372 | } 373 | 374 | if (count($this->_writeableServices)) 375 | { 376 | // select one of the read services at random 377 | $ids = array_keys($this->_writeableServices); 378 | 379 | $id = $ids[rand(0, count($ids) - 1)]; 380 | $service = $this->_writeableServices[$id]; 381 | 382 | if (is_array($service)) 383 | { 384 | //convert the array definition to a client object 385 | $service = new Apache_Solr_Service($service['host'], $service['port'], $service['path']); 386 | $this->_writeableServices[$id] = $service; 387 | } 388 | 389 | $this->_currentWriteService = $id; 390 | } 391 | else 392 | { 393 | throw new Apache_Solr_NoServiceAvailableException('No write services were available'); 394 | } 395 | } 396 | 397 | return $this->_writeableServices[$this->_currentWriteService]; 398 | } 399 | 400 | /** 401 | * Iterate through available write services and select the first with a ping 402 | * that satisfies configured timeout restrictions (or the default). The 403 | * timeout period will increase until a connection is made or the limit is 404 | * reached. This will allow for increased reliability with heavily loaded 405 | * server(s). 406 | * 407 | * @return Apache_Solr_Service 408 | * 409 | * @throws Apache_Solr_NoServiceAvailableException If there are no write services that meet requirements 410 | */ 411 | 412 | protected function _selectWriteServiceSafe($forceSelect = false) 413 | { 414 | if (!$this->_currentWriteService || !isset($this->_writeableServices[$this->_currentWriteService]) || $forceSelect) 415 | { 416 | if (count($this->_writeableServices)) 417 | { 418 | $backoff = $this->_defaultBackoff; 419 | 420 | do { 421 | // select one of the read services at random 422 | $ids = array_keys($this->_writeableServices); 423 | 424 | $id = $ids[rand(0, count($ids) - 1)]; 425 | $service = $this->_writeableServices[$id]; 426 | 427 | if (is_array($service)) 428 | { 429 | //convert the array definition to a client object 430 | $service = new Apache_Solr_Service($service['host'], $service['port'], $service['path']); 431 | $this->_writeableServices[$id] = $service; 432 | } 433 | 434 | $this->_currentWriteService = $id; 435 | 436 | $backoff *= $this->_backoffEscalation; 437 | 438 | if($backoff > $this->_backoffLimit) 439 | { 440 | throw new Apache_Solr_NoServiceAvailableException('No write services were available. All timeouts exceeded.'); 441 | } 442 | 443 | } while($this->_writeableServices[$this->_currentWriteService]->ping($backoff) === false); 444 | } 445 | else 446 | { 447 | throw new Apache_Solr_NoServiceAvailableException('No write services were available'); 448 | } 449 | } 450 | 451 | return $this->_writeableServices[$this->_currentWriteService]; 452 | } 453 | 454 | /** 455 | * Set the create documents flag. This determines whether {@link Apache_Solr_Response} objects will 456 | * parse the response and create {@link Apache_Solr_Document} instances in place. 457 | * 458 | * @param boolean $createDocuments 459 | */ 460 | public function setCreateDocuments($createDocuments) 461 | { 462 | $this->_createDocuments = (bool) $createDocuments; 463 | 464 | // set on current read service 465 | if ($this->_currentReadService) 466 | { 467 | $service = $this->_selectReadService(); 468 | $service->setCreateDocuments($createDocuments); 469 | } 470 | } 471 | 472 | /** 473 | * Get the current state of teh create documents flag. 474 | * 475 | * @return boolean 476 | */ 477 | public function getCreateDocuments() 478 | { 479 | return $this->_createDocuments; 480 | } 481 | 482 | /** 483 | * Raw Add Method. Takes a raw post body and sends it to the update service. Post body 484 | * should be a complete and well formed "add" xml document. 485 | * 486 | * @param string $rawPost 487 | * @return Apache_Solr_Response 488 | * 489 | * @throws Apache_Solr_HttpTransportException If an error occurs during the service call 490 | */ 491 | public function add($rawPost) 492 | { 493 | $service = $this->_selectWriteService(); 494 | 495 | do 496 | { 497 | try 498 | { 499 | return $service->add($rawPost); 500 | } 501 | catch (Apache_Solr_HttpTransportException $e) 502 | { 503 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 504 | { 505 | throw $e; 506 | } 507 | } 508 | 509 | $service = $this->_selectWriteService(true); 510 | } while ($service); 511 | 512 | return false; 513 | } 514 | 515 | /** 516 | * Add a Solr Document to the index 517 | * 518 | * @param Apache_Solr_Document $document 519 | * @param boolean $allowDups 520 | * @param boolean $overwritePending 521 | * @param boolean $overwriteCommitted 522 | * @return Apache_Solr_Response 523 | * 524 | * @throws Apache_Solr_HttpTransportException If an error occurs during the service call 525 | */ 526 | public function addDocument(Apache_Solr_Document $document, $allowDups = false, $overwritePending = true, $overwriteCommitted = true) 527 | { 528 | $service = $this->_selectWriteService(); 529 | 530 | do 531 | { 532 | try 533 | { 534 | return $service->addDocument($document, $allowDups, $overwritePending, $overwriteCommitted); 535 | } 536 | catch (Apache_Solr_HttpTransportException $e) 537 | { 538 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 539 | { 540 | throw $e; 541 | } 542 | } 543 | 544 | $service = $this->_selectWriteService(true); 545 | } while ($service); 546 | 547 | return false; 548 | } 549 | 550 | /** 551 | * Add an array of Solr Documents to the index all at once 552 | * 553 | * @param array $documents Should be an array of Apache_Solr_Document instances 554 | * @param boolean $allowDups 555 | * @param boolean $overwritePending 556 | * @param boolean $overwriteCommitted 557 | * @return Apache_Solr_Response 558 | * 559 | * @throws Apache_Solr_HttpTransportException If an error occurs during the service call 560 | */ 561 | public function addDocuments($documents, $allowDups = false, $overwritePending = true, $overwriteCommitted = true) 562 | { 563 | $service = $this->_selectWriteService(); 564 | 565 | do 566 | { 567 | try 568 | { 569 | return $service->addDocuments($documents, $allowDups, $overwritePending, $overwriteCommitted); 570 | } 571 | catch (Apache_Solr_HttpTransportException $e) 572 | { 573 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 574 | { 575 | throw $e; 576 | } 577 | } 578 | 579 | $service = $this->_selectWriteService(true); 580 | } while ($service); 581 | 582 | return false; 583 | } 584 | 585 | /** 586 | * Send a commit command. Will be synchronous unless both wait parameters are set 587 | * to false. 588 | * 589 | * @param boolean $waitFlush 590 | * @param boolean $waitSearcher 591 | * @return Apache_Solr_Response 592 | * 593 | * @throws Apache_Solr_HttpTransportException If an error occurs during the service call 594 | */ 595 | public function commit($optimize = true, $waitFlush = true, $waitSearcher = true, $timeout = 3600) 596 | { 597 | $service = $this->_selectWriteService(); 598 | 599 | do 600 | { 601 | try 602 | { 603 | return $service->commit($optimize, $waitFlush, $waitSearcher, $timeout); 604 | } 605 | catch (Apache_Solr_HttpTransportException $e) 606 | { 607 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 608 | { 609 | throw $e; 610 | } 611 | } 612 | 613 | $service = $this->_selectWriteService(true); 614 | } while ($service); 615 | 616 | return false; 617 | } 618 | 619 | /** 620 | * Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be 621 | * a complete and well formed "delete" xml document 622 | * 623 | * @param string $rawPost 624 | * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception) 625 | * @return Apache_Solr_Response 626 | * 627 | * @throws Apache_Solr_HttpTransportException If an error occurs during the service call 628 | */ 629 | public function delete($rawPost, $timeout = 3600) 630 | { 631 | $service = $this->_selectWriteService(); 632 | 633 | do 634 | { 635 | try 636 | { 637 | return $service->delete($rawPost, $timeout); 638 | } 639 | catch (Apache_Solr_HttpTransportException $e) 640 | { 641 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 642 | { 643 | throw $e; 644 | } 645 | } 646 | 647 | $service = $this->_selectWriteService(true); 648 | } while ($service); 649 | 650 | return false; 651 | } 652 | 653 | /** 654 | * Create a delete document based on document ID 655 | * 656 | * @param string $id 657 | * @param boolean $fromPending 658 | * @param boolean $fromCommitted 659 | * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception) 660 | * @return Apache_Solr_Response 661 | * 662 | * @throws Apache_Solr_HttpTransportException If an error occurs during the service call 663 | */ 664 | public function deleteById($id, $fromPending = true, $fromCommitted = true, $timeout = 3600) 665 | { 666 | $service = $this->_selectWriteService(); 667 | 668 | do 669 | { 670 | try 671 | { 672 | return $service->deleteById($id, $fromPending, $fromCommitted, $timeout); 673 | } 674 | catch (Apache_Solr_HttpTransportException $e) 675 | { 676 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 677 | { 678 | throw $e; 679 | } 680 | } 681 | 682 | $service = $this->_selectWriteService(true); 683 | } while ($service); 684 | 685 | return false; 686 | } 687 | 688 | /** 689 | * Create and post a delete document based on multiple document IDs. 690 | * 691 | * @param array $ids Expected to be utf-8 encoded strings 692 | * @param boolean $fromPending 693 | * @param boolean $fromCommitted 694 | * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception) 695 | * @return Apache_Solr_Response 696 | * 697 | * @throws Apache_Solr_HttpTransportException If an error occurs during the service call 698 | */ 699 | public function deleteByMultipleIds($ids, $fromPending = true, $fromCommitted = true, $timeout = 3600) 700 | { 701 | $service = $this->_selectWriteService(); 702 | 703 | do 704 | { 705 | try 706 | { 707 | return $service->deleteByMultipleId($ids, $fromPending, $fromCommitted, $timeout); 708 | } 709 | catch (Apache_Solr_HttpTransportException $e) 710 | { 711 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 712 | { 713 | throw $e; 714 | } 715 | } 716 | 717 | $service = $this->_selectWriteService(true); 718 | } while ($service); 719 | 720 | return false; 721 | } 722 | 723 | /** 724 | * Create a delete document based on a query and submit it 725 | * 726 | * @param string $rawQuery 727 | * @param boolean $fromPending 728 | * @param boolean $fromCommitted 729 | * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception) 730 | * @return Apache_Solr_Response 731 | * 732 | * @throws Apache_Solr_HttpTransportException If an error occurs during the service call 733 | */ 734 | public function deleteByQuery($rawQuery, $fromPending = true, $fromCommitted = true, $timeout = 3600) 735 | { 736 | $service = $this->_selectWriteService(); 737 | 738 | do 739 | { 740 | try 741 | { 742 | return $service->deleteByQuery($rawQuery, $fromPending, $fromCommitted, $timeout); 743 | } 744 | catch (Apache_Solr_HttpTransportException $e) 745 | { 746 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 747 | { 748 | throw $e; 749 | } 750 | } 751 | 752 | $service = $this->_selectWriteService(true); 753 | } while ($service); 754 | 755 | return false; 756 | } 757 | 758 | /** 759 | * Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how 760 | * to use Solr Cell and what parameters are available. 761 | * 762 | * NOTE: when passing an Apache_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost." 763 | * as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value 764 | * pairs in the params array if they have the same name (e.g. you pass a "literal.id" key and value in your $params array but you also 765 | * pass in a document isntance with an "id" field" - the document's value(s) will take precedence). 766 | * 767 | * @param string $file Path to file to extract data from 768 | * @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation) 769 | * @param Apache_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params) 770 | * @param string $mimetype optional mimetype specification (for the file being extracted) 771 | * 772 | * @return Apache_Solr_Response 773 | * 774 | * @throws Apache_Solr_InvalidArgumentException if $file, $params, or $document are invalid. 775 | */ 776 | public function extract($file, $params = array(), $document = null, $mimetype = 'application/octet-stream') 777 | { 778 | $service = $this->_selectWriteService(); 779 | 780 | do 781 | { 782 | try 783 | { 784 | return $service->extract($file, $params, $document, $mimetype); 785 | } 786 | catch (Apache_Solr_HttpTransportException $e) 787 | { 788 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 789 | { 790 | throw $e; 791 | } 792 | } 793 | 794 | $service = $this->_selectWriteService(true); 795 | } while ($service); 796 | 797 | return false; 798 | } 799 | 800 | /** 801 | * Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how 802 | * to use Solr Cell and what parameters are available. 803 | * 804 | * NOTE: when passing an Apache_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost." 805 | * as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value 806 | * pairs in the params array if they have the same name (e.g. you pass a "literal.id" key and value in your $params array but you also 807 | * pass in a document isntance with an "id" field" - the document's value(s) will take precedence). 808 | * 809 | * @param string $data Data that will be passed to Solr Cell 810 | * @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation) 811 | * @param Apache_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params) 812 | * @param string $mimetype optional mimetype specification (for the file being extracted) 813 | * 814 | * @return Apache_Solr_Response 815 | * 816 | * @throws Apache_Solr_InvalidArgumentException if $file, $params, or $document are invalid. 817 | * 818 | * @todo Should be using multipart/form-data to post parameter values, but I could not get my implementation to work. Needs revisisted. 819 | */ 820 | public function extractFromString($data, $params = array(), $document = null, $mimetype = 'application/octet-stream') 821 | { 822 | $service = $this->_selectWriteService(); 823 | 824 | do 825 | { 826 | try 827 | { 828 | return $service->extractFromString($data, $params, $document, $mimetype); 829 | } 830 | catch (Apache_Solr_HttpTransportException $e) 831 | { 832 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 833 | { 834 | throw $e; 835 | } 836 | } 837 | 838 | $service = $this->_selectWriteService(true); 839 | } while ($service); 840 | 841 | return false; 842 | } 843 | 844 | /** 845 | * Send an optimize command. Will be synchronous unless both wait parameters are set 846 | * to false. 847 | * 848 | * @param boolean $waitFlush 849 | * @param boolean $waitSearcher 850 | * @param float $timeout Maximum expected duration of the optimize operation on the server (otherwise, will throw a communication exception) 851 | * @return Apache_Solr_Response 852 | * 853 | * @throws Apache_Solr_HttpTransportException If an error occurs during the service call 854 | */ 855 | public function optimize($waitFlush = true, $waitSearcher = true, $timeout = 3600) 856 | { 857 | $service = $this->_selectWriteService(); 858 | 859 | do 860 | { 861 | try 862 | { 863 | return $service->optimize($waitFlush, $waitSearcher, $timeout); 864 | } 865 | catch (Apache_Solr_HttpTransportException $e) 866 | { 867 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 868 | { 869 | throw $e; 870 | } 871 | } 872 | 873 | $service = $this->_selectWriteService(true); 874 | } while ($service); 875 | 876 | return false; 877 | } 878 | 879 | /** 880 | * Simple Search interface 881 | * 882 | * @param string $query The raw query string 883 | * @param int $offset The starting offset for result documents 884 | * @param int $limit The maximum number of result documents to return 885 | * @param array $params key / value pairs for query parameters, use arrays for multivalued parameters 886 | * @param string $method The HTTP method (Apache_Solr_Service::METHOD_GET or Apache_Solr_Service::METHOD::POST) 887 | * @return Apache_Solr_Response 888 | * 889 | * @throws Apache_Solr_HttpTransportException If an error occurs during the service call 890 | */ 891 | public function search($query, $offset = 0, $limit = 10, $params = array(), $method = Apache_Solr_Service::METHOD_GET) 892 | { 893 | $service = $this->_selectReadService(); 894 | 895 | do 896 | { 897 | try 898 | { 899 | return $service->search($query, $offset, $limit, $params, $method); 900 | } 901 | catch (Apache_Solr_HttpTransportException $e) 902 | { 903 | if ($e->getCode() != 0) //IF NOT COMMUNICATION ERROR 904 | { 905 | throw $e; 906 | } 907 | } 908 | 909 | $service = $this->_selectReadService(true); 910 | } while ($service); 911 | 912 | return false; 913 | } 914 | } 915 | -------------------------------------------------------------------------------- /SolrPhpClient/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007-2011, Servigistics, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Servigistics, Inc. nor the names of 13 | its contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /SolrPhpClient/tests/Apache/Solr/DocumentTest.php: -------------------------------------------------------------------------------- 1 | 36 | */ 37 | 38 | /** 39 | * Apache_Solr_Document Unit Test 40 | */ 41 | class Apache_Solr_DocumentTest extends PHPUnit_Framework_TestCase 42 | { 43 | /** 44 | * Fixture used for testing 45 | * 46 | * @var Apache_Solr_Document 47 | */ 48 | private $_fixture; 49 | 50 | /** 51 | * Setup for the fixture before each unit test - part of test case API 52 | */ 53 | protected function setup() 54 | { 55 | $this->_fixture = new Apache_Solr_Document(); 56 | } 57 | 58 | /** 59 | * Teardown after each unit test - part of test case API 60 | */ 61 | protected function tearDown() 62 | { 63 | unset($this->_fixture); 64 | } 65 | 66 | public function testDefaultStateAfterConstructor() 67 | { 68 | // document boost should be false 69 | $this->assertFalse($this->_fixture->getBoost()); 70 | 71 | // document fields should be empty 72 | $this->assertEquals(0, count($this->_fixture->getFieldNames())); 73 | $this->assertEquals(0, count($this->_fixture->getFieldValues())); 74 | $this->assertEquals(0, count($this->_fixture->getFieldBoosts())); 75 | 76 | // document iterator should be empty 77 | $this->assertEquals(0, iterator_count($this->_fixture)); 78 | } 79 | 80 | public function testSetAndGetField() 81 | { 82 | $field = 'field'; 83 | $value = 'value'; 84 | $boost = 0.5; 85 | 86 | // set the field 87 | $this->_fixture->setField($field, $value, $boost); 88 | 89 | $result = $this->_fixture->getField($field); 90 | 91 | // check the array values 92 | $this->assertTrue(is_array($result)); 93 | $this->assertEquals($field, $result['name']); 94 | $this->assertEquals($value, $result['value']); 95 | $this->assertEquals($boost, $result['boost']); 96 | } 97 | 98 | public function testGetFieldReturnsFalseForNonExistentField() 99 | { 100 | $this->assertFalse($this->_fixture->getField('field')); 101 | } 102 | 103 | public function testMagicGetForFieldValues() 104 | { 105 | $field = 'field'; 106 | $value = 'value'; 107 | 108 | $this->_fixture->setField($field, $value); 109 | 110 | // test the __get value 111 | $this->assertEquals($value, $this->_fixture->{$field}); 112 | } 113 | 114 | /** 115 | * Added for issue #48 (http://code.google.com/p/solr-php-client/issues/detail?id=48) 116 | */ 117 | public function testMagicGetReturnsNullForNonExistentField() 118 | { 119 | $this->assertNull($this->_fixture->nonExistent); 120 | } 121 | 122 | public function testMagicSetForFieldValues() 123 | { 124 | $field = 'field'; 125 | $value = 'value'; 126 | 127 | // set field value with magic __set 128 | $this->_fixture->{$field} = $value; 129 | 130 | $fieldArray = $this->_fixture->getField($field); 131 | 132 | // set values 133 | $this->assertEquals($field, $fieldArray['name']); 134 | $this->assertEquals($value, $fieldArray['value']); 135 | $this->assertTrue($fieldArray['boost'] === false); 136 | } 137 | 138 | public function testMagicIssetForNonExistentField() 139 | { 140 | $this->assertFalse(isset($this->_fixture->field)); 141 | } 142 | 143 | public function testMagicIssetForExistingField() 144 | { 145 | $field = 'field'; 146 | $this->_fixture->{$field} = 'value'; 147 | $this->assertTrue(isset($this->_fixture->{$field})); 148 | } 149 | 150 | public function testMagicUnsetForExistingField() 151 | { 152 | $field = 'field'; 153 | 154 | $this->_fixture->{$field} = 'value'; 155 | 156 | // now unset the field 157 | unset($this->_fixture->{$field}); 158 | 159 | // now test that its unset 160 | $this->assertFalse(isset($this->_fixture->{$field})); 161 | } 162 | 163 | public function testMagicUnsetForNonExistingField() 164 | { 165 | $field = 'field'; 166 | unset($this->_fixture->{$field}); 167 | 168 | // now test that it still does not exist 169 | $this->assertFalse(isset($this->_fixture->{$field})); 170 | } 171 | 172 | public function testSetAndGetFieldBoostWithPositiveNumberSetsBoost() 173 | { 174 | $field = 'field'; 175 | $boost = 0.5; 176 | 177 | $this->_fixture->setFieldBoost($field, $boost); 178 | 179 | // test the field boost 180 | $this->assertEquals($boost, $this->_fixture->getFieldBoost($field)); 181 | } 182 | 183 | public function testSetAndGetFieldBoostWithZeroRemovesBoost() 184 | { 185 | $field = 'field'; 186 | $boost = 0; 187 | 188 | $this->_fixture->setFieldBoost($field, $boost); 189 | 190 | // test the field boost 191 | $this->assertTrue($this->_fixture->getFieldBoost($field) === false); 192 | } 193 | 194 | public function testSetAndGetFieldBoostWithNegativeNumberRemovesBoost() 195 | { 196 | $field = 'field'; 197 | $boost = -1; 198 | 199 | $this->_fixture->setFieldBoost($field, $boost); 200 | 201 | // test the field boost 202 | $this->assertTrue($this->_fixture->getFieldBoost($field) === false); 203 | } 204 | 205 | public function testSetAndGetFieldBoostWithNonNumberRemovesBoost() 206 | { 207 | $field = 'field'; 208 | $boost = "i am not a number"; 209 | 210 | $this->_fixture->setFieldBoost($field, $boost); 211 | 212 | // test the field boost 213 | $this->assertTrue($this->_fixture->getFieldBoost($field) === false); 214 | } 215 | 216 | public function testSetAndGetBoostWithPositiveNumberSetsBoost() 217 | { 218 | $boost = 0.5; 219 | $this->_fixture->setBoost($boost); 220 | 221 | // the boost should now be set 222 | $this->assertEquals($boost, $this->_fixture->getBoost()); 223 | } 224 | 225 | public function testSetAndGetBoostWithZeroRemovesBoost() 226 | { 227 | $this->_fixture->setBoost(0); 228 | 229 | // should be boolean false 230 | $this->assertTrue($this->_fixture->getBoost() === false); 231 | } 232 | 233 | public function testSetAndGetBoostWithNegativeNumberRemovesBoost() 234 | { 235 | $this->_fixture->setBoost(-1); 236 | 237 | // should be boolean false 238 | $this->assertTrue($this->_fixture->getBoost() === false); 239 | } 240 | 241 | public function testSetAndGetBoostWithNonNumberRemovesBoost() 242 | { 243 | $this->_fixture->setBoost("i am not a number"); 244 | 245 | // should be boolean false 246 | $this->assertTrue($this->_fixture->getBoost() === false); 247 | } 248 | 249 | public function testAddFieldCreatesMultiValueWhenFieldDoesNotExist() 250 | { 251 | $field = 'field'; 252 | $value = 'value'; 253 | 254 | $this->_fixture->addField($field, $value); 255 | 256 | // check that value is an array with correct values 257 | $fieldValue = $this->_fixture->{$field}; 258 | 259 | $this->assertTrue(is_array($fieldValue)); 260 | $this->assertEquals(1, count($fieldValue)); 261 | $this->assertEquals($value, $fieldValue[0]); 262 | } 263 | 264 | /** 265 | * setMultiValue has been deprecated and defers to addField 266 | * 267 | * @deprecated 268 | */ 269 | public function testSetMultiValueCreateMultiValueWhenFieldDoesNotExist() 270 | { 271 | $field = 'field'; 272 | $value = 'value'; 273 | 274 | $this->_fixture->setMultiValue($field, $value); 275 | 276 | // check that value is an array with correct values 277 | $fieldValue = $this->_fixture->{$field}; 278 | 279 | $this->assertTrue(is_array($fieldValue)); 280 | $this->assertEquals(1, count($fieldValue)); 281 | $this->assertEquals($value, $fieldValue[0]); 282 | } 283 | 284 | public function testAddFieldCreatesMultiValueWhenFieldDoesExistAsSingleValue() 285 | { 286 | $field = 'field'; 287 | $value1 = 'value1'; 288 | $value2 = 'value2'; 289 | 290 | // set first value as singular value 291 | $this->_fixture->{$field} = $value1; 292 | 293 | // add a second value with addField 294 | $this->_fixture->addField($field, $value2); 295 | 296 | // check that value is an array with correct values 297 | $fieldValue = $this->_fixture->{$field}; 298 | 299 | $this->assertTrue(is_array($fieldValue)); 300 | $this->assertEquals(2, count($fieldValue)); 301 | $this->assertEquals($value1, $fieldValue[0]); 302 | $this->assertEquals($value2, $fieldValue[1]); 303 | } 304 | 305 | /** 306 | * setMultiValue has been deprecated and defers to addField 307 | * 308 | * @deprecated 309 | */ 310 | public function testSetMultiValueCreatesMultiValueWhenFieldDoesExistAsSingleValue() 311 | { 312 | $field = 'field'; 313 | $value1 = 'value1'; 314 | $value2 = 'value2'; 315 | 316 | // set first value as singular value 317 | $this->_fixture->{$field} = $value1; 318 | 319 | // add a second value with addField 320 | $this->_fixture->setMultiValue($field, $value2); 321 | 322 | // check that value is an array with correct values 323 | $fieldValue = $this->_fixture->{$field}; 324 | 325 | $this->assertTrue(is_array($fieldValue)); 326 | $this->assertEquals(2, count($fieldValue)); 327 | $this->assertEquals($value1, $fieldValue[0]); 328 | $this->assertEquals($value2, $fieldValue[1]); 329 | } 330 | 331 | public function testAddFieldWithBoostSetsFieldBoost() 332 | { 333 | $field = 'field'; 334 | $boost = 0.5; 335 | 336 | $this->_fixture->addField($field, 'value', $boost); 337 | 338 | // check the field boost 339 | $this->assertEquals($boost, $this->_fixture->getFieldBoost($field)); 340 | } 341 | 342 | public function testAddFieldWithBoostMultipliesWithAPreexistingBoost() 343 | { 344 | $field = 'field'; 345 | $boost = 0.5; 346 | 347 | // set a field with a boost 348 | $this->_fixture->setField($field, 'value1', $boost); 349 | 350 | // now add another value with the same boost 351 | $this->_fixture->addField($field, 'value2', $boost); 352 | 353 | // new boost should be $boost * $boost 354 | $this->assertEquals($boost * $boost, $this->_fixture->getFieldBoost($field)); 355 | } 356 | 357 | public function testGetFieldNamesIsInitiallyEmpty() 358 | { 359 | $fieldNames = $this->_fixture->getFieldNames(); 360 | 361 | $this->assertTrue(empty($fieldNames)); 362 | } 363 | 364 | public function testGetFieldNamesAfterFieldIsSetIsNotEmpty() 365 | { 366 | $field = 'field'; 367 | 368 | $this->_fixture->{$field} = 'value'; 369 | $fieldNames = $this->_fixture->getFieldNames(); 370 | 371 | $this->assertTrue(!empty($fieldNames)); 372 | $this->assertEquals(1, count($fieldNames)); 373 | $this->assertEquals($field, $fieldNames[0]); 374 | } 375 | 376 | public function testGetFieldValuesIsInitiallyEmpty() 377 | { 378 | $fieldValues = $this->_fixture->getFieldValues(); 379 | 380 | $this->assertTrue(empty($fieldValues)); 381 | } 382 | 383 | public function testGetFieldValuessAfterFieldIsSetIsNotEmpty() 384 | { 385 | $value = 'value'; 386 | 387 | $this->_fixture->field = $value; 388 | $fieldValues = $this->_fixture->getFieldValues(); 389 | 390 | $this->assertTrue(!empty($fieldValues)); 391 | $this->assertEquals(1, count($fieldValues)); 392 | $this->assertEquals($value, $fieldValues[0]); 393 | } 394 | 395 | public function testGetIteratorAfterFieldValueIsSet() 396 | { 397 | $field = 'field'; 398 | $value = 'value'; 399 | 400 | $this->_fixture->{$field} = $value; 401 | 402 | $itemCount = 0; 403 | 404 | foreach ($this->_fixture as $iteratedField => $iteratedValue) 405 | { 406 | ++$itemCount; 407 | 408 | // test field and value 409 | $this->assertEquals($field, $iteratedField); 410 | $this->assertEquals($value, $iteratedValue); 411 | } 412 | 413 | // test number of iterations is 1 414 | $this->assertEquals(1, $itemCount); 415 | } 416 | 417 | public function testClearReturnsDocumentToDefaultState() 418 | { 419 | // set the document boost 420 | $this->_fixture->setBoost(0.5); 421 | 422 | // set a field 423 | $this->_fixture->someField = "some value"; 424 | 425 | // clear the document to remove boost and fields 426 | $this->_fixture->clear(); 427 | 428 | // document boost should now be false 429 | $this->assertFalse($this->_fixture->getBoost()); 430 | 431 | // document fields should now be empty 432 | $this->assertEquals(0, count($this->_fixture->getFieldNames())); 433 | $this->assertEquals(0, count($this->_fixture->getFieldValues())); 434 | $this->assertEquals(0, count($this->_fixture->getFieldBoosts())); 435 | 436 | // document iterator should now be empty 437 | $this->assertEquals(0, iterator_count($this->_fixture)); 438 | } 439 | } -------------------------------------------------------------------------------- /SolrPhpClient/tests/Apache/Solr/HttpTransport/AbstractTest.php: -------------------------------------------------------------------------------- 1 | 36 | */ 37 | 38 | /** 39 | * Apache_Solr_HttpTransport_Abstract Unit Tests 40 | */ 41 | abstract class Apache_Solr_HttpTransport_AbstractTest extends PHPUnit_Framework_TestCase 42 | { 43 | const TIMEOUT = 2; 44 | 45 | // request our copyright file from googlecode for GET and HEAD 46 | const GET_URL = "http://solr-php-client.googlecode.com/svn/trunk/COPYING"; 47 | const GET_RESPONSE_MIME_TYPE = 'text/plain'; 48 | const GET_RESPONSE_ENCODING = 'UTF-8'; 49 | const GET_RESPONSE_MATCH = 'Copyright (c) '; 50 | 51 | // post to the issue list page with a search for 'meh' 52 | const POST_URL = "http://code.google.com/p/solr-php-client/issues/list"; 53 | const POST_DATA = "can=2&q=meh&colspec=ID+Type+Status+Priority+Milestone+Owner+Summary&cells=tiles"; 54 | const POST_REQUEST_CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=UTF-8'; 55 | 56 | const POST_RESPONSE_MIME_TYPE = 'text/html'; 57 | const POST_RESPONSE_ENCODING = 'UTF-8'; 58 | //const POST_RESPONSE_MATCH = 'not sure'; 59 | 60 | abstract public function getFixture(); 61 | 62 | public function testGetDefaultTimeoutWithDefaultConstructor() 63 | { 64 | $fixture = $this->getFixture(); 65 | $timeout = $fixture->getDefaultTimeout(); 66 | 67 | $this->assertGreaterThan(0, $timeout); 68 | } 69 | 70 | public function testGetDefaultTimeoutSetToSixtyForBadValues() 71 | { 72 | // first set our default_socket_timeout ini setting 73 | $previousValue = ini_get('default_socket_timeout'); 74 | ini_set('default_socket_timeout', 0); 75 | 76 | $fixture = $this->getFixture(); 77 | $timeout = $fixture->getDefaultTimeout(); 78 | 79 | // reset timeout 80 | ini_set('default_socket_timeout', $previousValue); 81 | 82 | $this->assertEquals(60, $timeout); 83 | } 84 | 85 | public function testSetDefaultTimeout() 86 | { 87 | $newTimeout = 1234; 88 | 89 | $fixture = $this->getFixture(); 90 | $fixture->setDefaultTimeout($newTimeout); 91 | $timeout = $fixture->getDefaultTimeout(); 92 | 93 | $this->assertEquals($newTimeout, $timeout); 94 | } 95 | 96 | public function testPerformGetRequest() 97 | { 98 | $fixture = $this->getFixture(); 99 | $fixture->setDefaultTimeout(self::TIMEOUT); 100 | 101 | $response = $fixture->performGetRequest(self::GET_URL); 102 | 103 | $this->assertType('Apache_Solr_HttpTransport_Response', $response); 104 | 105 | $this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200'); 106 | $this->assertEquals(self::GET_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct'); 107 | $this->assertEquals(self::GET_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct'); 108 | $this->assertStringStartsWith(self::GET_RESPONSE_MATCH, $response->getBody(), 'body did not start with match text'); 109 | } 110 | 111 | public function testPerformGetRequestWithTimeout() 112 | { 113 | $fixture = $this->getFixture(); 114 | $response = $fixture->performGetRequest(self::GET_URL, self::TIMEOUT); 115 | 116 | $this->assertType('Apache_Solr_HttpTransport_Response', $response); 117 | 118 | $this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200'); 119 | $this->assertEquals(self::GET_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct'); 120 | $this->assertEquals(self::GET_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct'); 121 | $this->assertStringStartsWith(self::GET_RESPONSE_MATCH, $response->getBody(), 'body did not start with match text'); 122 | } 123 | 124 | public function testPerformHeadRequest() 125 | { 126 | $fixture = $this->getFixture(); 127 | $fixture->setDefaultTimeout(self::TIMEOUT); 128 | 129 | $response = $fixture->performHeadRequest(self::GET_URL); 130 | 131 | // we should get everything the same as a get, except the body 132 | $this->assertType('Apache_Solr_HttpTransport_Response', $response); 133 | 134 | $this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200'); 135 | $this->assertEquals(self::GET_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct'); 136 | $this->assertEquals(self::GET_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct'); 137 | $this->assertEquals("", $response->getBody(), 'body was not empty'); 138 | } 139 | 140 | public function testPerformHeadRequestWithTimeout() 141 | { 142 | $fixture = $this->getFixture(); 143 | $response = $fixture->performHeadRequest(self::GET_URL, self::TIMEOUT); 144 | 145 | // we should get everything the same as a get, except the body 146 | $this->assertType('Apache_Solr_HttpTransport_Response', $response); 147 | 148 | $this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200'); 149 | $this->assertEquals(self::GET_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct'); 150 | $this->assertEquals(self::GET_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct'); 151 | $this->assertEquals("", $response->getBody(), 'body was not empty'); 152 | } 153 | 154 | public function testPerformPostRequest() 155 | { 156 | $fixture = $this->getFixture(); 157 | $fixture->setDefaultTimeout(self::TIMEOUT); 158 | 159 | $response = $fixture->performPostRequest(self::POST_URL, self::POST_DATA, self::POST_REQUEST_CONTENT_TYPE); 160 | 161 | $this->assertType('Apache_Solr_HttpTransport_Response', $response); 162 | 163 | $this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200'); 164 | $this->assertEquals(self::POST_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct'); 165 | $this->assertEquals(self::POST_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct'); 166 | //$this->assertStringStartsWith(self::POST_RESPONSE_MATCH, $response->getBody(), 'body did not start with match text'); 167 | } 168 | 169 | public function testPerformPostRequestWithTimeout() 170 | { 171 | $fixture = $this->getFixture(); 172 | $response = $fixture->performPostRequest(self::POST_URL, self::POST_DATA, self::POST_REQUEST_CONTENT_TYPE, self::TIMEOUT); 173 | 174 | $this->assertType('Apache_Solr_HttpTransport_Response', $response); 175 | 176 | $this->assertEquals(200, $response->getStatusCode(), 'Status code was not 200'); 177 | $this->assertEquals(self::POST_RESPONSE_MIME_TYPE, $response->getMimeType(), 'mimetype was not correct'); 178 | $this->assertEquals(self::POST_RESPONSE_ENCODING, $response->getEncoding(), 'character encoding was not correct'); 179 | //$this->assertStringStartsWith(self::POST_RESPONSE_MATCH, $response->getBody(), 'body did not start with match text'); 180 | } 181 | 182 | /** 183 | * Test one session doing multiple requests in multiple orders 184 | */ 185 | public function testMultipleRequests() 186 | { 187 | // initial get request 188 | $this->testPerformGetRequest(); 189 | 190 | // head following get 191 | $this->testPerformHeadRequest(); 192 | 193 | // post following head 194 | $this->testPerformPostRequest(); 195 | 196 | // get following post 197 | $this->testPerformGetRequest(); 198 | 199 | // post following get 200 | $this->testPerformPostRequest(); 201 | 202 | // head following post 203 | $this->testPerformHeadRequest(); 204 | 205 | // get following post 206 | $this->testPerformGetRequest(); 207 | } 208 | } -------------------------------------------------------------------------------- /SolrPhpClient/tests/Apache/Solr/HttpTransport/CurlNoReuseTest.php: -------------------------------------------------------------------------------- 1 | 36 | */ 37 | 38 | /** 39 | * Apache_Solr_HttpTransport_CurlNoReuse Unit Tests 40 | */ 41 | class Apache_Solr_HttpTransport_CurlNoReuseTest extends Apache_Solr_HttpTransport_AbstractTest 42 | { 43 | public function getFixture() 44 | { 45 | // ensure curl is enabled 46 | if (!extension_loaded('curl')) 47 | { 48 | $this->markTestSkipped("curl module is not enabled"); 49 | } 50 | 51 | return new Apache_Solr_HttpTransport_CurlNoReuse(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /SolrPhpClient/tests/Apache/Solr/HttpTransport/CurlTest.php: -------------------------------------------------------------------------------- 1 | 36 | */ 37 | 38 | /** 39 | * Apache_Solr_HttpTransport_Curl Unit Tests 40 | */ 41 | class Apache_Solr_HttpTransport_CurlTest extends Apache_Solr_HttpTransport_AbstractTest 42 | { 43 | public function getFixture() 44 | { 45 | // ensure curl is enabled 46 | if (!extension_loaded('curl')) 47 | { 48 | $this->markTestSkipped("curl module is not enabled"); 49 | } 50 | 51 | return new Apache_Solr_HttpTransport_Curl(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /SolrPhpClient/tests/Apache/Solr/HttpTransport/FileGetContentsTest.php: -------------------------------------------------------------------------------- 1 | 36 | */ 37 | 38 | /** 39 | * Apache_Solr_HttpTransport_FileGetContents Unit Tests 40 | */ 41 | class Apache_Solr_HttpTransport_FileGetContentsTest extends Apache_Solr_HttpTransport_AbstractTest 42 | { 43 | public function getFixture() 44 | { 45 | // make sure allow_url_fopen is on 46 | if (!ini_get("allow_url_fopen")) 47 | { 48 | $this->markTestSkipped("allow_url_fopen is not enabled"); 49 | } 50 | 51 | return new Apache_Solr_HttpTransport_FileGetContents(); 52 | } 53 | } -------------------------------------------------------------------------------- /SolrPhpClient/tests/Apache/Solr/HttpTransport/ResponseTest.php: -------------------------------------------------------------------------------- 1 | 36 | */ 37 | 38 | /** 39 | * Apache_Solr_HttpTransport_Response Unit Tests 40 | */ 41 | class Apache_Solr_HttpTransport_ResponseTest extends PHPUnit_Framework_TestCase 42 | { 43 | // generated with the following query string: select?q=solr&wt=json 44 | const STATUS_CODE_200 = 200; 45 | const STATUS_MESSAGE_200 = "OK"; 46 | const BODY_200 = '{"responseHeader":{"status":0,"QTime":0,"params":{"q":"solr","wt":"json"}},"response":{"numFound":0,"start":0,"docs":[]}}'; 47 | const BODY_200_WITH_DOCUMENTS = '{"responseHeader":{"status":0,"QTime":0,"params":{"q":"*:*","wt":"json"}},"response":{"numFound":1,"start":0,"docs":[{"guid":"dev/2/products/45410/1236981","cit_domain":"products","cit_client":"2","cit_instance":"dev","cit_timestamp":"2010-10-06T18:16:51.573Z","product_code_t":["235784"],"product_id":[1236981],"dealer_id":[45410],"category_id":[1030],"manufacturer_id":[0],"vendor_id":[472],"catalog_id":[202]}]}}'; 48 | const CONTENT_TYPE_200 = "text/plain; charset=utf-8"; 49 | const MIME_TYPE_200 = "text/plain"; 50 | const ENCODING_200 = "utf-8"; 51 | 52 | // generated with the following query string: select?qt=standad&q=solr&wt=json 53 | // NOTE: the intentional mispelling of the standard in the qt parameter 54 | const STATUS_CODE_400 = 400; 55 | const STATUS_MESSAGE_400 = "Bad Request"; 56 | const BODY_400 = 'Apache Tomcat/6.0.24 - Error report

HTTP Status 400 - unknown handler: standad


type Status report

message unknown handler: standad

description The request sent by the client was syntactically incorrect (unknown handler: standad).


Apache Tomcat/6.0.24

'; 57 | const CONTENT_TYPE_400 = "text/html; charset=utf-8"; 58 | const MIME_TYPE_400 = "text/html"; 59 | const ENCODING_400 = "utf-8"; 60 | 61 | // generated with the following query string: select?q=solr&wt=json on a core that does not exist 62 | const STATUS_CODE_404 = 404; 63 | const STATUS_MESSAGE_404 = "Not Found"; 64 | const BODY_404 = 'Apache Tomcat/6.0.24 - Error report

HTTP Status 404 - /solr/doesnotexist/select


type Status report

message /solr/doesnotexist/select

description The requested resource (/solr/doesnotexist/select) is not available.


Apache Tomcat/6.0.24

'; 65 | const CONTENT_TYPE_404 = "text/html; charset=utf-8"; 66 | const MIME_TYPE_404 = "text/html"; 67 | const ENCODING_404 = "utf-8"; 68 | 69 | public static function get0Response() 70 | { 71 | return new Apache_Solr_HttpTransport_Response(null, null, null); 72 | } 73 | 74 | public static function get200Response() 75 | { 76 | return new Apache_Solr_HttpTransport_Response(self::STATUS_CODE_200, self::CONTENT_TYPE_200, self::BODY_200); 77 | } 78 | 79 | public static function get200ResponseWithDocuments() 80 | { 81 | return new Apache_Solr_HttpTransport_Response(self::STATUS_CODE_200, self::CONTENT_TYPE_200, self::BODY_200_WITH_DOCUMENTS); 82 | } 83 | 84 | public static function get400Response() 85 | { 86 | return new Apache_Solr_HttpTransport_Response(self::STATUS_CODE_400, self::CONTENT_TYPE_400, self::BODY_400); 87 | } 88 | 89 | public static function get404Response() 90 | { 91 | return new Apache_Solr_HttpTransport_Response(self::STATUS_CODE_404, self::CONTENT_TYPE_404, self::BODY_404); 92 | } 93 | 94 | public function testGetStatusCode() 95 | { 96 | $fixture = self::get200Response(); 97 | 98 | $statusCode = $fixture->getStatusCode(); 99 | 100 | $this->assertEquals(self::STATUS_CODE_200, $statusCode); 101 | } 102 | 103 | public function testGetStatusMessage() 104 | { 105 | $fixture = self::get200Response(); 106 | 107 | $statusMessage = $fixture->getStatusMessage(); 108 | 109 | $this->assertEquals(self::STATUS_MESSAGE_200, $statusMessage); 110 | } 111 | 112 | public function testGetStatusMessageWithUnknownCode() 113 | { 114 | $fixture = new Apache_Solr_HttpTransport_Response(499, null, null); 115 | 116 | $statusMessage = $fixture->getStatusMessage(); 117 | $this->assertEquals("Unknown Status", $statusMessage); 118 | } 119 | 120 | public function testGetBody() 121 | { 122 | $fixture = self::get200Response(); 123 | 124 | $body = $fixture->getBody(); 125 | 126 | $this->assertEquals(self::BODY_200, $body); 127 | } 128 | 129 | public function testGetMimeType() 130 | { 131 | $fixture = self::get200Response(); 132 | 133 | $mimeType = $fixture->getMimeType(); 134 | 135 | $this->assertEquals(self::MIME_TYPE_200, $mimeType); 136 | } 137 | 138 | public function testGetEncoding() 139 | { 140 | $fixture = self::get200Response(); 141 | 142 | $encoding = $fixture->getEncoding(); 143 | 144 | $this->assertEquals(self::ENCODING_200, $encoding); 145 | } 146 | 147 | public function testGetStatusMessageWhenNotProvided() 148 | { 149 | // test 4 of the most common status code responses, probably don't need 150 | // to test all the codes we have 151 | 152 | $fixture = new Apache_Solr_HttpTransport_Response(null, null, null, null, null); 153 | $this->assertEquals("Communication Error", $fixture->getStatusMessage(), 'Did not get correct default status message for status code 0'); 154 | 155 | $fixture = new Apache_Solr_HttpTransport_Response(200, null, null, null, null); 156 | $this->assertEquals("OK", $fixture->getStatusMessage(), 'Did not get correct default status message for status code 200'); 157 | 158 | $fixture = new Apache_Solr_HttpTransport_Response(400, null, null, null, null); 159 | $this->assertEquals("Bad Request", $fixture->getStatusMessage(), 'Did not get correct default status message for status code 400'); 160 | 161 | $fixture = new Apache_Solr_HttpTransport_Response(404, null, null, null, null); 162 | $this->assertEquals("Not Found", $fixture->getStatusMessage(), 'Did not get correct default status message for status code 404'); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /SolrPhpClient/tests/Apache/Solr/HttpTransportExceptionTest.php: -------------------------------------------------------------------------------- 1 | 36 | */ 37 | 38 | /** 39 | * Apache_Solr_HttpTransportException Unit Tests 40 | */ 41 | class Apache_Solr_HttpTransportExceptionTest extends PHPUnit_Framework_TestCase 42 | { 43 | /** 44 | * @expectedException PHPUnit_Framework_Error 45 | */ 46 | public function testConstructorRequiresResponse() 47 | { 48 | $fixture = new Apache_Solr_HttpTransportException(); 49 | } 50 | 51 | public function testGetResponse() 52 | { 53 | $response = Apache_Solr_ResponseTest::get0Response(); 54 | $fixture = new Apache_Solr_HttpTransportException($response); 55 | 56 | $this->assertEquals($response, $fixture->getResponse()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /SolrPhpClient/tests/Apache/Solr/ResponseTest.php: -------------------------------------------------------------------------------- 1 | 36 | */ 37 | 38 | /** 39 | * Apache_Solr_Response Unit Test 40 | */ 41 | class Apache_Solr_ResponseTest extends PHPUnit_Framework_TestCase 42 | { 43 | static public function get0Response($createDocuments = true, $collapseSingleValueArrays = true) 44 | { 45 | return new Apache_Solr_Response(Apache_Solr_HttpTransport_ResponseTest::get0Response(), $createDocuments, $collapseSingleValueArrays); 46 | } 47 | 48 | static public function get200Response($createDocuments = true, $collapseSingleValueArrays = true) 49 | { 50 | return new Apache_Solr_Response(Apache_Solr_HttpTransport_ResponseTest::get200Response(), $createDocuments, $collapseSingleValueArrays); 51 | } 52 | 53 | static public function get200ResponseWithDocuments($createDocuments = true, $collapseSingleValueArrays = true) 54 | { 55 | return new Apache_Solr_Response(Apache_Solr_HttpTransport_ResponseTest::get200ResponseWithDocuments(), $createDocuments, $collapseSingleValueArrays); 56 | } 57 | 58 | static public function get400Response($createDocuments = true, $collapseSingleValueArrays = true) 59 | { 60 | return new Apache_Solr_Response(Apache_Solr_HttpTransport_ResponseTest::get400Response(), $createDocuments, $collapseSingleValueArrays); 61 | } 62 | 63 | static public function get404Response($createDocuments = true, $collapseSingleValueArrays = true) 64 | { 65 | return new Apache_Solr_Response(Apache_Solr_HttpTransport_ResponseTest::get404Response(), $createDocuments, $collapseSingleValueArrays); 66 | } 67 | 68 | public function testConstuctorWithValidBodyAndHeaders() 69 | { 70 | $fixture = self::get200Response(); 71 | 72 | // check that we parsed the HTTP status correctly 73 | $this->assertEquals(Apache_Solr_HttpTransport_ResponseTest::STATUS_CODE_200, $fixture->getHttpStatus()); 74 | 75 | // check that we received the body correctly 76 | $this->assertEquals(Apache_Solr_HttpTransport_ResponseTest::BODY_200, $fixture->getRawResponse()); 77 | 78 | // check that our defaults are correct 79 | $this->assertEquals(Apache_Solr_HttpTransport_ResponseTest::ENCODING_200, $fixture->getEncoding()); 80 | $this->assertEquals(Apache_Solr_HttpTransport_ResponseTest::MIME_TYPE_200, $fixture->getType()); 81 | } 82 | 83 | public function testConstructorWithBadBodyAndHeaders() 84 | { 85 | $fixture = self::get0Response(); 86 | 87 | // check that our defaults are correct 88 | $this->assertEquals(0, $fixture->getHttpStatus()); 89 | $this->assertEquals("UTF-8", $fixture->getEncoding()); 90 | $this->assertEquals("text/plain", $fixture->getType()); 91 | } 92 | 93 | public function testMagicGetWithValidBodyAndHeaders() 94 | { 95 | $fixture = self::get200Response(); 96 | 97 | // test top level gets 98 | $this->assertType('stdClass', $fixture->responseHeader); 99 | $this->assertEquals(0, $fixture->responseHeader->status); 100 | $this->assertEquals(0, $fixture->responseHeader->QTime); 101 | 102 | $this->assertType('stdClass', $fixture->response); 103 | $this->assertEquals(0, $fixture->response->numFound); 104 | 105 | $this->assertTrue(is_array($fixture->response->docs)); 106 | $this->assertEquals(0, count($fixture->response->docs)); 107 | } 108 | 109 | /** 110 | * @expectedException Apache_Solr_ParserException 111 | */ 112 | public function testMagicGetWith0Response() 113 | { 114 | $fixture = self::get0Response(); 115 | 116 | // attempting to magic get a part of the response 117 | // should throw a ParserException 118 | $fixture->responseHeader; 119 | 120 | $this->fail("Expected Apache_Solr_ParserException was not raised"); 121 | } 122 | 123 | /** 124 | * @expectedException Apache_Solr_ParserException 125 | */ 126 | public function testMagicGetWith400Response() 127 | { 128 | $fixture = self::get400Response(); 129 | 130 | // attempting to magic get a part of the response 131 | // should throw a ParserException 132 | $fixture->responseHeader; 133 | 134 | $this->fail("Expected Apache_Solr_ParserException was not raised"); 135 | } 136 | 137 | /** 138 | * @expectedException Apache_Solr_ParserException 139 | */ 140 | public function testMagicGetWith404Response() 141 | { 142 | $fixture = self::get404Response(); 143 | 144 | // attempting to magic get a part of the response 145 | // should throw a ParserException 146 | $fixture->responseHeader; 147 | 148 | $this->fail("Expected Apache_Solr_ParserException was not raised"); 149 | } 150 | 151 | public function testCreateDocuments() 152 | { 153 | $fixture = self::get200ResponseWithDocuments(); 154 | 155 | $this->assertTrue(count($fixture->response->docs) > 0, 'There are not 1 or more documents, cannot test'); 156 | $this->assertType('Apache_Solr_Document', $fixture->response->docs[0], 'The first document is not of type Apache_Solr_Document'); 157 | } 158 | 159 | public function testDontCreateDocuments() 160 | { 161 | $fixture = self::get200ResponseWithDocuments(false); 162 | 163 | $this->assertTrue(count($fixture->response->docs) > 0, 'There are not 1 or more documents, cannot test'); 164 | $this->assertType('stdClass', $fixture->response->docs[0], 'The first document is not of type stdClass'); 165 | } 166 | 167 | public function testGetHttpStatusMessage() 168 | { 169 | $fixture = self::get200Response(); 170 | 171 | $this->assertEquals("OK", $fixture->getHttpStatusMessage()); 172 | } 173 | 174 | public function testMagicGetReturnsNullForUndefinedData() 175 | { 176 | $fixture = self::get200Response(); 177 | 178 | $this->assertNull($fixture->doesnotexist); 179 | } 180 | 181 | public function testMagicIssetForDefinedProperty() 182 | { 183 | $fixture = self::get200Response(); 184 | 185 | $this->assertTrue(isset($fixture->responseHeader)); 186 | } 187 | 188 | public function testMagicIssetForUndefinedProperty() 189 | { 190 | $fixture = self::get200Response(); 191 | 192 | $this->assertFalse(isset($fixture->doesnotexist)); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /SolrPhpClient/tests/Apache/Solr/Service/BalancerTest.php: -------------------------------------------------------------------------------- 1 | 36 | */ 37 | 38 | /** 39 | * Apache_Solr_Service_Balancer Unit Tests 40 | */ 41 | class Apache_Solr_Service_BalancerTest extends Apache_Solr_ServiceAbstractTest 42 | { 43 | public function getFixture() 44 | { 45 | return new Apache_Solr_Service_Balancer(); 46 | } 47 | } -------------------------------------------------------------------------------- /SolrPhpClient/tests/Apache/Solr/ServiceAbstractTest.php: -------------------------------------------------------------------------------- 1 | 36 | */ 37 | 38 | /** 39 | * Provides base funcationality test for both Apache_Solr_Service and the 40 | * Apache_Solr_Service_Balancer classes. 41 | */ 42 | abstract class Apache_Solr_ServiceAbstractTest extends PHPUnit_Framework_TestCase 43 | { 44 | /** 45 | * Method that gets the appropriate instance for testing 46 | */ 47 | abstract public function getFixture(); 48 | 49 | /** 50 | * @dataProvider testEscapeDataProvider 51 | */ 52 | public function testEscape($input, $expectedOutput) 53 | { 54 | $fixture = $this->getFixture(); 55 | 56 | $this->assertEquals($expectedOutput, $fixture->escape($input)); 57 | } 58 | 59 | public function testEscapeDataProvider() 60 | { 61 | return array( 62 | array( 63 | "I should look the same", 64 | "I should look the same" 65 | ), 66 | 67 | array( 68 | "(There) are: ^lots \\ && of spec!al charaters", 69 | "\\(There\\) are\\: \\^lots \\\\ \\&& of spec\\!al charaters" 70 | ) 71 | ); 72 | } 73 | 74 | /** 75 | * @dataProvider testEscapePhraseDataProvider 76 | */ 77 | public function testEscapePhrase($input, $expectedOutput) 78 | { 79 | $fixture = $this->getFixture(); 80 | 81 | $this->assertEquals($expectedOutput, $fixture->escapePhrase($input)); 82 | } 83 | 84 | public function testEscapePhraseDataProvider() 85 | { 86 | return array( 87 | array( 88 | "I'm a simple phrase", 89 | "I'm a simple phrase" 90 | ), 91 | 92 | array( 93 | "I have \"phrase\" characters", 94 | 'I have \\"phrase\\" characters' 95 | ) 96 | ); 97 | } 98 | 99 | /** 100 | * @dataProvider testPhraseDataProvider 101 | */ 102 | public function testPhrase($input, $expectedOutput) 103 | { 104 | $fixture = $this->getFixture(); 105 | 106 | $this->assertEquals($expectedOutput, $fixture->phrase($input)); 107 | } 108 | 109 | public function testPhraseDataProvider() 110 | { 111 | return array( 112 | array( 113 | "I'm a simple phrase", 114 | '"I\'m a simple phrase"' 115 | ), 116 | 117 | array( 118 | "I have \"phrase\" characters", 119 | '"I have \\"phrase\\" characters"' 120 | ) 121 | ); 122 | } 123 | 124 | public function testGetCreateDocumentWithDefaultConstructor() 125 | { 126 | $fixture = $this->getFixture(); 127 | 128 | $this->assertTrue($fixture->getCreateDocuments()); 129 | } 130 | 131 | public function testSetCreateDocuments() 132 | { 133 | $fixture = $this->getFixture(); 134 | 135 | $fixture->setCreateDocuments(false); 136 | 137 | $this->assertFalse($fixture->getCreateDocuments()); 138 | } 139 | } -------------------------------------------------------------------------------- /SolrPhpClient/tests/README: -------------------------------------------------------------------------------- 1 | Use the run.php script included in this directory to run all unit tests for the 2 | Solr PHP Client library. Your system will require phpunit PEAR package - which 3 | you can get install instructions for at: 4 | 5 | http://www.phpunit.de/ 6 | 7 | To generate the code coverage report, you will also need the XDebug pecl package 8 | installed, typically this can be done with a simple: 9 | 10 | pecl install xdebug 11 | 12 | If you need more information on installation, then please see the official website: 13 | 14 | http://www.xdebug.org 15 | 16 | The scripts, configuration, and test files in this directory have been confirmed to 17 | work with the following versions: 18 | 19 | phpunit: 3.3.16 20 | xdebug: 2.0.4 -------------------------------------------------------------------------------- /SolrPhpClient/tests/phpunit.bootstrap.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ../Apache 10 | 11 | ./run.php 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /SolrPhpClient/tests/run.php: -------------------------------------------------------------------------------- 1 | #! /usr/bin/php 2 | 122 | 123 | Login to the WordPress admin GUI, select add new page, set the title of the page to "Search". On the right hand side you will see a drop-down box that says "Template", click that and select "Search". Leave the content of the page blank and publish the page. 124 | 125 | You will have have your "/search/" page. 126 | 127 | = I need the output of this plugin in a different language = 128 | 129 | Solr for WordPress is internationalized. There is supplied .pot file that you can use for translations. See http://codex.wordpress.org/Translating_WordPress for more details. 130 | 131 | = How do I find out the page or post id to exclude? = 132 | 133 | Login to the WordPress admin, select pages, click the page you want to exclude. The post id is what you are looking for, you can find it in the titlebar as the &post= parameter. In this example, the page id is 22, http://www.yourblog.com/wp-admin/page.php?action=edit&post=22. 134 | 135 | 136 | == Screenshots == 137 | 138 | 1. Configuration Page 139 | 2. Example of results page in default WordPress Theme 140 | 141 | == Credits == 142 | 143 | Dominique Bejean for custom field support and testing. 144 | Eric Pugh multi server support. 145 | Dustin Rue - fixes for batch import and multisite. 146 | 147 | -------------------------------------------------------------------------------- /schema.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | id 137 | text 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattweber/solr-for-wordpress/76537e266ab8d387b4cc62b01c58a1cb5dc102c5/screenshot-1.png -------------------------------------------------------------------------------- /screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattweber/solr-for-wordpress/76537e266ab8d387b4cc62b01c58a1cb5dc102c5/screenshot-2.png -------------------------------------------------------------------------------- /solr-for-wordpress.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR Matt Weber 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: Solr for WordPress 0.2.0\n" 10 | "Report-Msgid-Bugs-To: http://wordpress.org/tag/solr-for-wordpress\n" 11 | "POT-Creation-Date: 2009-05-13 10:15-0700\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=CHARSET\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | 19 | #: solr-for-wordpress.php:36 20 | msgid "Solr for WordPress requires WordPress 2.7 or greater. " 21 | msgstr "" 22 | 23 | #: solr-for-wordpress.php:108 24 | msgid "Post Information is NULL" 25 | msgstr "" 26 | 27 | #: solr-for-wordpress.php:215 28 | #, php-format 29 | msgid "" 30 | "
" 33 | msgstr "" 34 | 35 | #: solr-for-wordpress.php:262 36 | #, php-format 37 | msgid "" 38 | "

Found %d results for %s in %.3f seconds.

" 41 | msgstr "" 42 | 43 | #: solr-for-wordpress.php:275 44 | msgid "
    " 45 | msgstr "" 46 | 47 | #: solr-for-wordpress.php:279 48 | #, php-format 49 | msgid "
  • %d
  • " 50 | msgstr "" 51 | 52 | #: solr-for-wordpress.php:282 53 | #, php-format 54 | msgid "
  • %d
  • " 55 | msgstr "" 56 | 57 | #: solr-for-wordpress.php:285 58 | msgid "
" 59 | msgstr "" 60 | 61 | #: solr-for-wordpress.php:290 62 | msgid "
    " 63 | msgstr "" 64 | 65 | #: solr-for-wordpress.php:299 66 | #, php-format 67 | msgid "
  • %s

      " 68 | msgstr "" 69 | 70 | #: solr-for-wordpress.php:314 solr-for-wordpress.php:364 71 | #, php-format 72 | msgid "?s=%s&fq=%s:%s%s" 73 | msgstr "" 74 | 75 | #: solr-for-wordpress.php:315 solr-for-wordpress.php:365 76 | #, php-format 77 | msgid "
    • %s (%d)
    • " 78 | msgstr "" 79 | 80 | #: solr-for-wordpress.php:318 solr-for-wordpress.php:370 81 | msgid "
  • " 82 | msgstr "" 83 | 84 | #: solr-for-wordpress.php:323 85 | msgid "
" 86 | msgstr "" 87 | 88 | #: solr-for-wordpress.php:324 89 | msgid "
" 90 | msgstr "" 91 | 92 | #: solr-for-wordpress.php:327 93 | msgid "
No Results Found
" 94 | msgstr "" 95 | 96 | #: solr-for-wordpress.php:331 97 | msgid "
" 98 | msgstr "" 99 | 100 | #: solr-for-wordpress.php:332 101 | #, php-format 102 | msgid "" 103 | "

%s

by %s has a " 104 | "score of %f

" 105 | msgstr "" 106 | 107 | #: solr-for-wordpress.php:337 108 | #, php-format 109 | msgid "

...%s...

" 110 | msgstr "" 111 | 112 | #: solr-for-wordpress.php:341 113 | #, php-format 114 | msgid "

%s...

" 115 | msgstr "" 116 | 117 | #: solr-for-wordpress.php:345 118 | msgid "
" 119 | msgstr "" 120 | 121 | #: solr-for-wordpress.php:358 122 | msgid "
    • " 123 | msgstr "" 124 | 125 | #: solr-for-wordpress.php:493 126 | msgid "

      Couldn't locate the options page.

      " 127 | msgstr "" 128 | 129 | #: solr-options-page.php:60 130 | msgid "Ping Success!" 131 | msgstr "" 132 | 133 | #: solr-options-page.php:64 134 | msgid "Ping Failed!" 135 | msgstr "" 136 | 137 | #: solr-options-page.php:70 138 | msgid "Pages Loaded!" 139 | msgstr "" 140 | 141 | #: solr-options-page.php:75 142 | msgid "Posts Loaded!" 143 | msgstr "" 144 | 145 | #: solr-options-page.php:80 146 | msgid "All Indexed Pages Deleted!" 147 | msgstr "" 148 | 149 | #: solr-options-page.php:86 150 | msgid "Solr For WordPress" 151 | msgstr "" 152 | 153 | #: solr-options-page.php:89 154 | msgid "Connection Information" 155 | msgstr "" 156 | 157 | #: solr-options-page.php:92 158 | msgid "Solr Host" 159 | msgstr "" 160 | 161 | #: solr-options-page.php:97 162 | msgid "Solr Port" 163 | msgstr "" 164 | 165 | #: solr-options-page.php:102 166 | msgid "Solr Path" 167 | msgstr "" 168 | 169 | #: solr-options-page.php:107 170 | msgid "Indexing Options" 171 | msgstr "" 172 | 173 | #: solr-options-page.php:110 174 | msgid "Index Pages" 175 | msgstr "" 176 | 177 | #: solr-options-page.php:112 178 | msgid "Index Posts" 179 | msgstr "" 180 | 181 | #: solr-options-page.php:117 182 | msgid "Remove Page on Delete" 183 | msgstr "" 184 | 185 | #: solr-options-page.php:119 186 | msgid "Remove Post on Delete" 187 | msgstr "" 188 | 189 | #: solr-options-page.php:124 190 | msgid "Remove Page on Status Change" 191 | msgstr "" 192 | 193 | #: solr-options-page.php:126 194 | msgid "Remove Post on Status Change" 195 | msgstr "" 196 | 197 | #: solr-options-page.php:131 198 | msgid "Excludes (comma-separated integer ids)" 199 | msgstr "" 200 | 201 | #: solr-options-page.php:136 202 | msgid "Result Options" 203 | msgstr "" 204 | 205 | #: solr-options-page.php:139 206 | msgid "Output Result Info" 207 | msgstr "" 208 | 209 | #: solr-options-page.php:141 210 | msgid "Output Result Pager" 211 | msgstr "" 212 | 213 | #: solr-options-page.php:146 214 | msgid "Output Facets" 215 | msgstr "" 216 | 217 | #: solr-options-page.php:148 218 | msgid "Category Facet as Taxonomy" 219 | msgstr "" 220 | 221 | #: solr-options-page.php:153 222 | msgid "Categories as Facet" 223 | msgstr "" 224 | 225 | #: solr-options-page.php:155 226 | msgid "Tags as Facet" 227 | msgstr "" 228 | 229 | #: solr-options-page.php:160 230 | msgid "Author as Facet" 231 | msgstr "" 232 | 233 | #: solr-options-page.php:162 234 | msgid "Type as Facet" 235 | msgstr "" 236 | 237 | #: solr-options-page.php:167 238 | msgid "Number of Results Per Page" 239 | msgstr "" 240 | 241 | #: solr-options-page.php:172 242 | msgid "Max Number of Tags to Display" 243 | msgstr "" 244 | 245 | #: solr-options-page.php:180 246 | msgid "Save Changes" 247 | msgstr "" 248 | 249 | #: solr-options-page.php:186 250 | msgid "Actions" 251 | msgstr "" 252 | 253 | #: solr-options-page.php:189 254 | msgid "Check Server Settings" 255 | msgstr "" 256 | 257 | #: solr-options-page.php:190 solr-options-page.php:195 258 | #: solr-options-page.php:200 solr-options-page.php:205 259 | msgid "Execute" 260 | msgstr "" 261 | 262 | #: solr-options-page.php:194 263 | msgid "Load All Pages" 264 | msgstr "" 265 | 266 | #: solr-options-page.php:199 267 | msgid "Load All Posts" 268 | msgstr "" 269 | 270 | #: solr-options-page.php:204 271 | msgid "Delete All" 272 | msgstr "" 273 | 274 | #. Plugin Name of an extension 275 | msgid "Solr for WordPress" 276 | msgstr "" 277 | 278 | #. Plugin URI of an extension 279 | msgid "https://launchpad.net/solr4wordpress" 280 | msgstr "" 281 | 282 | #. Description of an extension 283 | msgid "Indexes, removes, and updates documents in the Solr search engine." 284 | msgstr "" 285 | 286 | #. Author of an extension 287 | msgid "Matt Weber" 288 | msgstr "" 289 | 290 | #. Author URI of an extension 291 | msgid "http://www.mattweber.org" 292 | msgstr "" 293 | -------------------------------------------------------------------------------- /solr-options-page.php: -------------------------------------------------------------------------------- 1 | 'localhost','port'=>8983, 'path'=>'/solr'); 35 | $options['s4w_server']['info']['master']= array('host'=>'localhost','port'=>8983, 'path'=>'/solr'); 36 | $options['s4w_server']['type']['search'] = 'master'; 37 | $options['s4w_server']['type']['update'] = 'master'; 38 | 39 | //by default we index pages and posts, and remove them from index if there status changes. 40 | $options['s4w_content']['index'] = array('page'=>'1', 'post'=>'1'); 41 | $options['s4w_content']['delete'] = array('page'=>'1', 'post'=>'1'); 42 | $options['s4w_content']['private'] = array('page'=>'1', 'post'=>'1'); 43 | 44 | 45 | $options['s4w_index_pages'] = 1; 46 | $options['s4w_index_posts'] = 1; 47 | $options['s4w_delete_page'] = 1; 48 | $options['s4w_delete_post'] = 1; 49 | $options['s4w_private_page'] = 1; 50 | $options['s4w_private_post'] = 1; 51 | $options['s4w_output_info'] = 1; 52 | $options['s4w_output_pager'] = 1; 53 | $options['s4w_output_facets'] = 1; 54 | $options['s4w_exclude_pages'] = array(); 55 | $options['s4w_exclude_pages'] = ''; 56 | $options['s4w_num_results'] = 5; 57 | $options['s4w_cat_as_taxo'] = 1; 58 | $options['s4w_solr_initialized'] = 1; 59 | $options['s4w_max_display_tags'] = 10; 60 | $options['s4w_facet_on_categories'] = 1; 61 | $options['s4w_facet_on_taxonomy'] = 1; 62 | $options['s4w_facet_on_tags'] = 1; 63 | $options['s4w_facet_on_author'] = 1; 64 | $options['s4w_facet_on_type'] = 1; 65 | $options['s4w_enable_dym'] = 1; 66 | $options['s4w_index_comments'] = 1; 67 | $options['s4w_connect_type'] = 'solr'; 68 | $options['s4w_index_custom_fields'] = array(); 69 | $options['s4w_facet_on_custom_fields'] = array(); 70 | $options['s4w_index_custom_fields'] = ''; 71 | $options['s4w_facet_on_custom_fields'] = ''; 72 | 73 | 74 | //update existing settings from multiple option record to a single array 75 | //if old options exist, update to new system 76 | $delete_option_function = 'delete_option'; 77 | if (is_multisite()) { 78 | $indexall = get_site_option('s4w_index_all_sites'); 79 | $delete_option_function = 'delete_site_option'; 80 | } 81 | //find each of the old options function 82 | //update our new array and delete the record. 83 | foreach($options as $key => $value ) { 84 | if( $existing = get_option($key)) { 85 | $options[$key] = $existing; 86 | $indexall = FALSE; 87 | //run the appropriate delete options function 88 | $delete_option_function($key); 89 | } 90 | } 91 | 92 | $s4w_settings = $options; 93 | //save our options array 94 | s4w_update_option($options); 95 | } 96 | 97 | wp_reset_vars(array('action')); 98 | 99 | # save form settings if we get the update action 100 | # we do saving here instead of using options.php because we need to use 101 | # s4w_update_option instead of update option. 102 | # As it stands we have 27 options instead of making 27 insert calls (which is what update_options does) 103 | # Lets create an array of all our options and save it once. 104 | if ($_POST['action'] == 'update') { 105 | //lets loop through our setting fields $_POST['settings'] 106 | foreach ($s4w_settings as $option => $old_value ) { 107 | $value = $_POST['settings'][$option]; 108 | 109 | switch ($option) { 110 | case 's4w_solr_initialized': 111 | $value = trim($old_value); 112 | break; 113 | 114 | case 's4w_server': 115 | //remove empty server entries 116 | $s_value = &$value['info']; 117 | 118 | 119 | foreach ($s_value as $key => $v) { 120 | //lets rename the array_keys 121 | if(!$v['host']) unset($s_value[$key]); 122 | } 123 | break; 124 | } 125 | if ( !is_array($value) ) $value = trim($value); 126 | $value = stripslashes_deep($value); 127 | $s4w_settings[$option] = $value; 128 | } 129 | // if we are in single server mode set the server types to master 130 | // and configure the master server to the values of the single server 131 | if ($s4w_settings['s4w_connect_type'] =='solr_single'){ 132 | $s4w_settings['s4w_server']['info']['master']= $s4w_settings['s4w_server']['info']['single']; 133 | $s4w_settings['s4w_server']['type']['search'] = 'master'; 134 | $s4w_settings['s4w_server']['type']['update'] = 'master'; 135 | } 136 | // if this is a multi server setup we steal the master settings 137 | // and stuff them into the single server settings in case the user 138 | // decides to change it later 139 | else { 140 | $s4w_settings['s4w_server']['info']['single']= $s4w_settings['s4w_server']['info']['master']; 141 | } 142 | //lets save our options array 143 | s4w_update_option($s4w_settings); 144 | 145 | //we need to make call for the options again 146 | //as we need them to come out in an a sanitised format 147 | //otherwise fields that need to run s4w_filter_list2str will come up with nothin 148 | $s4w_settings = s4w_get_option('plugin_s4w_settings'); 149 | ?> 150 |

      151 | 174 |

      175 | 178 |

      179 | 184 |

      185 | 189 |

      190 | 194 |

      195 | 196 | 197 |
      198 |

      199 | 200 |
      201 |

      202 | 203 |
      204 |
      205 |
      206 | 207 | 208 | 209 |

      210 | 211 |

      212 | 213 |

      214 |
      215 |
      216 | 217 | 218 | '','port'=>'', 'path'=>''); 224 | foreach ($s4w_settings['s4w_server']['info'] as $server_id => $server) { 225 | if ($server_id == "single") 226 | continue; 227 | //lets set serverIDs 228 | $new_id =(is_numeric($server_id)) ? 'slave_'.$server_id : $server_id ; 229 | ?> 230 | 241 | 244 | 245 |
      231 | 232 |

      Update Server:    />

      233 |

      Search Server:    />

      234 | 235 |

      236 | 237 |

      238 | 239 |

      240 |
      246 |
      247 |
      248 |
        249 |
      1. 250 |
      2. 251 |
      3. 252 |

        onclick="switch1();" />Single Solr Server

        253 |
          254 |
        1. Download, install and configure your own Apache Solr instance
        2. 255 |
        256 |
      4. 257 |
      5. 258 |

        onclick="switch1();" />Separated Solr Servers

        259 |
          260 |
        1. Separate URL's for updates and searches.
        2. 261 |
        262 |
      6. 263 |
      264 |
      265 |
      266 |

      267 | 268 | $post_type) {?> 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 291 | 292 | 293 | 294 | 295 | 296 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 |
      /> /> />
      />
      />
      308 |
      309 |

      310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 |
      /> />
      /> />
      /> />
      /> />
      />
      />
      364 |
      365 | 366 | 367 |

      368 | 369 | 370 |

      371 | 372 |
      373 |
      374 |
      375 |

      376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | $post_type) { 390 | if ($s4w_settings['s4w_content']['index'][$post_type]==1) { 391 | ?> 392 | 393 | 394 | 395 | 396 | 397 | 0) { 402 | ?> 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 |
      419 |
      420 | 421 |
      422 | -------------------------------------------------------------------------------- /template/autocomplete.css: -------------------------------------------------------------------------------- 1 | .ac_results { 2 | border: 1px solid gray; 3 | background-color: white; 4 | padding: 0; 5 | margin: 0; 6 | list-style: none; 7 | position: absolute; 8 | z-index: 10000; 9 | display: none; 10 | } 11 | 12 | .ac_results li { 13 | padding: 2px 5px; 14 | white-space: nowrap; 15 | color: #101010; 16 | text-align: left; 17 | } 18 | 19 | .ac_over { 20 | cursor: pointer; 21 | background-color: #F0F0B8; 22 | } 23 | 24 | .ac_match { 25 | text-decoration: underline; 26 | color: black; 27 | } -------------------------------------------------------------------------------- /template/s4w_search.php: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 |
      9 | 10 |
      11 | 12 |

      Sorry, search is unavailable right now

      Try again later?

      "; 16 | } 17 | else { 18 | ?> 19 | 20 |
      21 | 40 | 41 | Did you mean: %s ?
      ", $results['dym']['link'], $results['dym']['term']); 43 | } ?> 44 | 45 |
      46 | 47 |
      48 | 49 |
      50 |
      51 | 52 | %s hits", $results['firstresult'], $results['hits']); 55 | } else { 56 | printf("Displaying results %s-%s of %s hits", $results['firstresult'], $results['lastresult'], $results['hits']); 57 | } 58 | } ?> 59 | 60 |
      61 |
      62 |
        63 |
      1. Relevance
      2. 64 |
      3. Newest
      4. 65 |
      5. Oldest
      6. 66 |
      7. Most Comments
      8. 67 |
      9. Least Comments
      10. 68 |
      69 |
      Sort by:
      70 |
      71 |
      72 | 73 |
      74 | 75 | 80 |

      Sorry, no results were found.

      81 |

      Perhaps you mispelled your search query, or need to try using broader search terms.

      82 |

      For example, instead of searching for 'Apple iPhone 3.0 3GS', try something simple like 'iPhone'.

      83 |
      \n"); 84 | } else { 85 | printf("
        \n"); 86 | foreach($results['results'] as $result) { 87 | printf("
      1. \n", $result['permalink']); 88 | printf("

        %s

        \n", $result['permalink'], $result['title']); 89 | printf("

        %s (comment match)

        \n", $result['teaser'], $result['comment_link']); 90 | printf("\n", 91 | $result['authorlink'], 92 | $result['author'], 93 | get_the_category_list( ', ', '', $result['id']), 94 | date('m/d/Y', strtotime($result['date'])), 95 | $result['comment_link'], 96 | $result['numcomments']); 97 | printf("
      2. \n"); 98 | } 99 | printf("
      \n"); 100 | } ?> 101 | 102 | "); 104 | $itemlinks = array(); 105 | $pagecnt = 0; 106 | $pagemax = 10; 107 | $next = ''; 108 | $prev = ''; 109 | $found = false; 110 | foreach($results['pager'] as $pageritm) { 111 | if ($pageritm['link']) { 112 | if ($found && $next === '') { 113 | $next = $pageritm['link']; 114 | } else if ($found == false) { 115 | $prev = $pageritm['link']; 116 | } 117 | 118 | $itemlinks[] = sprintf("%s", $pageritm['link'], $pageritm['page']); 119 | } else { 120 | $found = true; 121 | $itemlinks[] = sprintf("%s", $pageritm['link'], $pageritm['page']); 122 | } 123 | 124 | $pagecnt += 1; 125 | if ($pagecnt == $pagemax) { 126 | break; 127 | } 128 | } 129 | 130 | if ($prev !== '') { 131 | printf("Previous", $prev); 132 | } 133 | 134 | foreach ($itemlinks as $itemlink) { 135 | echo $itemlink; 136 | } 137 | 138 | if ($next !== '') { 139 | printf("Next", $next); 140 | } 141 | 142 | printf("
      \n"); 143 | } ?> 144 | 145 | 146 | 147 | 148 | 149 |
      150 |
        151 | 152 |
      • 153 |
          154 | %sx", $selectedfacet['removelink'], $selectedfacet['name']); 157 | } 158 | } ?> 159 |
        160 |
      • 161 | 162 | 1) { #don't display facets with only 1 value 165 | printf("
      • \n

        %s

        \n", $facet['name']); 166 | s4w_print_facet_items($facet["items"], "
          ", "
        ", "
      • ", "
      • ", 167 | "
        1. ", "
      • ", "
      • ", "
      • "); 168 | printf("\n"); 169 | } 170 | } 171 | } ?> 172 | 173 |
      174 |
      175 | 176 | 177 | 178 | 179 | 183 | -------------------------------------------------------------------------------- /template/search.css: -------------------------------------------------------------------------------- 1 | #content { 2 | width: auto !important; 3 | } 4 | 5 | *+ html clearfix { 6 | display: inline-block !important; 7 | } 8 | *+ html ul,ol { 9 | list-style-position: outside !important; 10 | } 11 | 12 | 13 | .solr * { 14 | line-height: 1 !important; 15 | padding: 0 !important; 16 | margin: 0 !important; 17 | text-align: left !important; 18 | } 19 | .solr ol, .solr ul, .solr ol li, .solr ul li { 20 | background: none !important; 21 | list-style-type: none !important; 22 | overflow: hidden !important; /* IE7 */ 23 | } 24 | .solr h2 {font-size:16px !important;} 25 | .solr h3 {font-size:14px !important;} 26 | .solr { 27 | font-size: 12px !important; 28 | line-height: 1 !important; 29 | margin: 0 !important; 30 | padding: 20px !important; 31 | width: auto !important; 32 | } 33 | div.solr1 { 34 | border-bottom: 1px solid #cccccc !important; 35 | padding: 0 0 6px !important; 36 | } 37 | div.solr_search { 38 | clear: both !important; 39 | padding: 0 0 12px !important; 40 | } 41 | div.solr_search input { 42 | font-size: 18px !important; 43 | } 44 | .solr_field { 45 | border: 1px solid #b7b7b7 !important; 46 | border-top: 2px solid #999999 !important; 47 | padding: 3px !important; 48 | margin: 0 8px 0 0 !important; 49 | width: 330px !important; 50 | } 51 | ol.solr_auto { 52 | background: #ffffff !important; 53 | border: 1px solid #b7b7b7 !important; 54 | width: 336px !important; 55 | padding: 6px 0 !important; 56 | position: absolute !important; 57 | clear: both !important; /* IE6 */ 58 | z-index: 100 !important; 59 | } 60 | .solr_auto li { 61 | padding: 2px 8px !important; 62 | } 63 | .solr_auto li:hover { 64 | background: #efffb0 !important; 65 | } 66 | div.solr_suggest { 67 | padding: 0 0 5px !important; 68 | } 69 | label.solr_response { 70 | font-size: 10px !important; 71 | color: #666666 !important; 72 | float: right !important; 73 | position: relative !important; 74 | top: 13px !important; 75 | } 76 | div.solr3 { 77 | float: left !important; 78 | padding: 18px 2% 0 0 !important; 79 | width: 23% !important; 80 | } 81 | .solr_active span { 82 | border-top: 4px solid #ffffff !important; 83 | border-left: 5px solid #999999 !important; 84 | border-bottom: 4px solid #ffffff !important; 85 | font-size: 0 !important; 86 | line-height: 0 !important; 87 | width: 0 !important; 88 | margin: 0 4px 0 0 !important; 89 | position: relative !important; 90 | bottom: 4px !important; 91 | zoom: 1 !important; /* IE7 */ 92 | } 93 | .solr_active b { 94 | font-family: Arial, Verdana, Helvetica, sans-serif !important; 95 | font-weight: bold !important; 96 | color: #999999 !important; 97 | } 98 | .solr_active a { 99 | text-decoration: none !important; 100 | } 101 | .solr_facets ol li { 102 | padding: 3px 0 3px !important; 103 | } 104 | .solr_facets ol li ol { 105 | padding: 3px 0 0 10px !important; 106 | } 107 | .solr_facets h3 { 108 | padding: 10px 0 3px !important; 109 | } 110 | .solr_active ol li { 111 | padding: 3px 0 !important; 112 | } 113 | .solr_active a { 114 | color: #000000 !important; 115 | } 116 | div.solr2 { 117 | float: right !important; 118 | padding: 8px 0 0 !important; 119 | width: 70% !important; 120 | } 121 | div.solr_results_header { 122 | font-size: 10px !important; 123 | color: #666666 !important; 124 | padding: 0 0 4px !important; 125 | } 126 | div.solr_results_headerL { 127 | width: 60% !important; 128 | float: left !important; 129 | padding: 0 0 0 12px !important; 130 | } 131 | div.solr_results_headerR { 132 | width: 35% !important; 133 | font-weight: bold !important; 134 | float: right !important; 135 | } 136 | .solr_sort { 137 | margin: 4px 4px 0 0 !important; 138 | float: right !important; 139 | } 140 | ol.solr_sort2 { 141 | background: #ffffff !important; 142 | text-decoration: none !important; 143 | border: 1px solid #cccccc !important; 144 | padding: 2px 0 1px !important; 145 | float: right !important; 146 | } 147 | .solr_sort2 li { 148 | display: block !important; /* FF3 */ 149 | padding: 2px 2px 2px 4px !important; 150 | } 151 | .solr_sort2 li:hover { 152 | background: #efffb0 !important; 153 | } 154 | .solr_sort2 a { 155 | text-decoration: none !important; 156 | } 157 | .solr_sort_drop span { 158 | border-top: 4px solid #999999 !important; 159 | border-right: 4px solid #ffffff !important; 160 | border-left: 5px solid #ffffff !important; 161 | font-size: 0 !important; 162 | line-height: 0 !important; 163 | width: 0 !important; 164 | margin: 0 0 0 2px !important; 165 | position: relative !important; 166 | bottom: 1px !important; 167 | zoom: 1 !important; /* IE7 */ 168 | } 169 | 170 | .solr_results ol { 171 | font-size: 12px !important; 172 | padding: 0 0 14px !important; 173 | clear: both !important; /* IE7 */ 174 | } 175 | .solr_results li { 176 | border-bottom: 1px solid #e6e6e6 !important; 177 | padding: 14px 12px !important; 178 | } 179 | .solr_results li:hover { 180 | background: #efffb0 !important; 181 | } 182 | .solr_results img { 183 | height: 50px !important; 184 | border: 1px solid #cccccc !important; 185 | float: right !important; 186 | display: block; 187 | margin: 0 0 0 5px !important; 188 | } 189 | .solr_results h2 { 190 | font-weight: normal !important; 191 | line-height: 1.1 !important; 192 | padding: 0 0 5px !important; 193 | } 194 | .solr_results label { 195 | font-size: 10px !important; 196 | color: #666666 !important; 197 | padding: 5px 0 0 !important; 198 | display: block !important; 199 | } 200 | .solr_pages { 201 | font-size: 14px !important; 202 | font-weight: bold !important; 203 | text-align: right !important; 204 | } 205 | .solr_pages a { 206 | margin: 0 0 0 5px !important; 207 | } 208 | .solr_pages_on { 209 | color: #000000 !important; 210 | } 211 | div.solr_noresult { 212 | padding: 20px 5% 40px 0 !important; 213 | } 214 | .solr_noresult h2 { 215 | font-weight: normal !important; 216 | line-height: 1.2 !important; 217 | padding: 0 0 14px !important; 218 | } 219 | .solr_noresult h3 { 220 | font-weight: normal !important; 221 | line-height: 1.2 !important; 222 | padding: 0 0 14px !important; 223 | } 224 | .solr_noresult p { 225 | font-weight: normal !important; 226 | line-height: 1.2 !important; 227 | } 228 | 229 | 230 | .solr_HL { 231 | background: #efffb0 !important; 232 | } 233 | 234 | .solr_admin { 235 | font-size: 14px; 236 | color: #464646; 237 | min-width: 800px; 238 | padding: 0 0 20px; 239 | } 240 | .solr_admin h4 { 241 | font-family: Georgia; 242 | font-size: 20px; 243 | font-style: italic; 244 | font-weight: normal; 245 | margin: 0; 246 | } 247 | .solr_admin h4 input { 248 | margin-right: 3px; 249 | } 250 | .solr_admin h5 { 251 | font-size: 14px; 252 | padding: 0 0 12px; 253 | } 254 | .solr_admin ol { 255 | list-style-type: none; 256 | width: 35%; 257 | float: right; 258 | position: relative; 259 | left: 1px; 260 | margin-left: 0; 261 | } 262 | .solr_admin li { 263 | color: #999999; 264 | background: #eeeeee; 265 | padding: 12px; 266 | margin-bottom: 0; 267 | } 268 | .solr_admin ol li ol { 269 | width: auto; 270 | float: none; 271 | left: 0; 272 | padding: 5px 0 0 32px; 273 | } 274 | 275 | .solr_admin ol li ol li { 276 | font-size: 12px; 277 | line-height: 1.2; 278 | background: none; 279 | list-style-type: disc; 280 | list-style-position: outside; 281 | padding: 1px 0; 282 | } 283 | 284 | .solr_admin_tab1 { 285 | border: 1px solid #cccccc; 286 | -moz-border-radius-topleft:6px; 287 | -webkit-border-top-left-radius:6px; 288 | } 289 | 290 | .solr_admin_tab2 { 291 | border-right: 1px solid #cccccc; 292 | border-bottom: 1px solid #cccccc; 293 | border-left: 1px solid #cccccc; 294 | -moz-border-radius-bottomleft:6px; 295 | -webkit-border-bottom-left-radius:6px; 296 | } 297 | 298 | .solr_admin_tab2 h4 { 299 | font-size: 18px; 300 | } 301 | 302 | .solr_admin_tab3 { 303 | border-right: 1px solid #cccccc; 304 | border-bottom: 1px solid #cccccc; 305 | border-left: 1px solid #cccccc; 306 | -moz-border-radius-bottomleft:6px; 307 | -webkit-border-bottom-left-radius:6px; 308 | } 309 | 310 | .solr_admin_tab3 h4 { 311 | font-size: 18px; 312 | } 313 | .solr_adminR { 314 | background: #ffffff; 315 | float: right; 316 | width: 65%; 317 | } 318 | 319 | li.solr_admin_on { 320 | color: #464646; 321 | background: #ffffff; 322 | border-right: 1px solid #eeeeee; 323 | } 324 | 325 | li.solr_admin_on li { 326 | color: #464646; 327 | } 328 | 329 | .solr_adminR1, .solr_adminR2 { 330 | border: 1px solid #cccccc; 331 | -moz-border-radius-topright:6px; 332 | -moz-border-radius-bottomright:6px; 333 | -moz-border-radius-bottomleft:6px; 334 | -webkit-border-top-right-radius:6px; 335 | -webkit-border-bottom-right-radius:6px; 336 | -webkit-border-bottom-left-radius:6px; 337 | padding: 24px 32px; 338 | } 339 | .solr_adminR2 { 340 | display: none; 341 | } 342 | .solr_adminR label { 343 | display: block; 344 | padding: 0 0 2px 3px; 345 | } 346 | .solr_adminR span { 347 | font-size: 11px; 348 | font-weight: bold; 349 | color: #00CC00; 350 | font: block; 351 | padding: 0 0 2px 3px; 352 | } 353 | span.solr_admin_warning { 354 | color: #FF9900; 355 | } 356 | .solr_adminR p { 357 | padding: 0 0 10px; 358 | } 359 | .solr_adminR input[type=text] { 360 | width: 220px; 361 | } 362 | 363 | /*CLEARFIX*/ 364 | .clearfix:after { 365 | content: " "; 366 | display: block; 367 | height: 0; 368 | clear: both; 369 | visibility: hidden; 370 | font-size: 0; 371 | } 372 | .clearfix { 373 | display: block;/*the holly hack for a bug in IE6 for Windows*/ 374 | } 375 | * html .clearfix {height: 1%;}/* Hides from IE-mac \*/ 376 | /* END CLEARFIX*/ 377 | .clear { 378 | clear: both; 379 | } 380 | --------------------------------------------------------------------------------